From 6d84c61f1845573f4c56a10e504679249d5b0301 Mon Sep 17 00:00:00 2001 From: timo Date: Sun, 4 Nov 2007 03:51:54 +0000 Subject: [PATCH] more eol-style git-svn-id: https://zerowing.idsoftware.com/svn/radiant/GtkRadiant/branches/ZeroRadiant@185 8a3a26a2-13c4-0310-b231-cf6edde360e5 --- contrib/bkgrnd2d/bkgrnd2d.cpp | 638 +- contrib/bkgrnd2d/dialog.cpp | 730 +- contrib/bkgrnd2d/plugin.cpp | 650 +- contrib/bobtoolz/DBobView.cpp | 722 +- contrib/bobtoolz/DBrush.cpp | 1696 +- contrib/bobtoolz/DEPair.cpp | 98 +- contrib/bobtoolz/DEntity.cpp | 1350 +- contrib/bobtoolz/DListener.cpp | 186 +- contrib/bobtoolz/DMap.cpp | 332 +- contrib/bobtoolz/DPatch.cpp | 828 +- contrib/bobtoolz/DPlane.cpp | 512 +- contrib/bobtoolz/DPoint.cpp | 104 +- contrib/bobtoolz/DShape.cpp | 918 +- contrib/bobtoolz/DTrainDrawer.cpp | 716 +- contrib/bobtoolz/DTreePlanter.cpp | 574 +- contrib/bobtoolz/DVisDrawer.cpp | 358 +- contrib/bobtoolz/DWinding.cpp | 966 +- contrib/bobtoolz/ScriptParser.cpp | 534 +- contrib/bobtoolz/StdAfx.cpp | 50 +- contrib/bobtoolz/bobToolz-GTK.cpp | 594 +- contrib/bobtoolz/bsploader.cpp | 516 +- contrib/bobtoolz/cportals.cpp | 680 +- contrib/bobtoolz/ctfToolz-GTK.cpp | 194 +- contrib/bobtoolz/dialogs/AboutDialog.cpp | 124 +- contrib/bobtoolz/dialogs/AutoCaulkDialog.cpp | 126 +- .../bobtoolz/dialogs/AutoCaulkStartDialog.cpp | 132 +- contrib/bobtoolz/dialogs/DoorDialog.cpp | 184 +- contrib/bobtoolz/dialogs/IntersectDialog.cpp | 130 +- .../bobtoolz/dialogs/IntersectInfoDialog.cpp | 122 +- contrib/bobtoolz/dialogs/PolygonDialog.cpp | 232 +- contrib/bobtoolz/dialogs/StairDialog.cpp | 210 +- .../bobtoolz/dialogs/TextureResetDialog.cpp | 162 +- contrib/bobtoolz/dialogs/brushcheckdialog.cpp | 122 +- contrib/bobtoolz/dialogs/dialogs-gtk.cpp | 3788 ++-- .../bobtoolz/dialogs/pathplotterdialog.cpp | 170 +- contrib/bobtoolz/funchandlers-GTK.cpp | 1600 +- contrib/bobtoolz/funchandlers-ctf-GTK.cpp | 428 +- contrib/bobtoolz/funchandlers.cpp | 1006 +- contrib/bobtoolz/lists.cpp | 170 +- contrib/bobtoolz/misc.cpp | 848 +- contrib/bobtoolz/shapes.cpp | 1332 +- contrib/bobtoolz/visfind.cpp | 490 +- contrib/camera/camera.cpp | 594 +- contrib/camera/dialogs.cpp | 2704 +-- contrib/camera/dialogs_common.cpp | 102 +- contrib/camera/funchandlers.cpp | 544 +- contrib/camera/listener.cpp | 468 +- contrib/camera/misc.cpp | 486 +- contrib/camera/renderer.cpp | 366 +- contrib/gtkgensurf/bitmap.cpp | 868 +- contrib/gtkgensurf/dec.cpp | 2656 +-- contrib/gtkgensurf/face.cpp | 900 +- contrib/gtkgensurf/font.cpp | 540 +- contrib/gtkgensurf/gendlgs.cpp | 4728 ++--- contrib/gtkgensurf/genmap.cpp | 4112 ++-- contrib/gtkgensurf/gensurf.cpp | 934 +- contrib/gtkgensurf/heretic.cpp | 300 +- contrib/gtkgensurf/plugin.cpp | 464 +- contrib/gtkgensurf/view.cpp | 2574 +-- contrib/hydratoolz/plugin.cpp | 834 +- contrib/prtview/AboutDialog.cpp | 278 +- contrib/prtview/ConfigDialog.cpp | 1850 +- contrib/prtview/LoadPortalFileDialog.cpp | 576 +- contrib/prtview/gtkdlgs.cpp | 1464 +- contrib/prtview/portals.cpp | 1604 +- contrib/prtview/prtview.cpp | 1096 +- contrib/prtview/stdafx.cpp | 50 +- docs/developer/XMLPush/StdAfx.cpp | 16 +- docs/developer/XMLPush/XMLPush.cpp | 60 +- libs/cmdlib/cmdlib.cpp | 992 +- libs/pak/pakstuff.cpp | 1958 +- libs/pak/unzip.cpp | 9068 ++++----- libs/splines/math_angles.cpp | 300 +- libs/splines/math_matrix.cpp | 268 +- libs/splines/math_quaternion.cpp | 156 +- libs/splines/math_vector.cpp | 286 +- libs/splines/q_parse.cpp | 1070 +- libs/splines/q_shared.cpp | 1952 +- libs/splines/splines.cpp | 2842 +-- libs/splines/util_str.cpp | 1256 +- libs/synapse/synapse.cpp | 2202 +-- plugins/eclassfgd/plugin.cpp | 2282 +-- plugins/entity/eclassmodel.cpp | 350 +- plugins/entity/entity.cpp | 754 +- plugins/entity/entity_entitymodel.cpp | 276 +- plugins/entity/light.cpp | 1072 +- plugins/entity/miscmodel.cpp | 508 +- plugins/entity/plugin.cpp | 242 +- plugins/image/bmp.cpp | 804 +- plugins/image/image.cpp | 266 +- plugins/image/jpeg.cpp | 830 +- plugins/image/lbmlib.cpp | 1524 +- plugins/imagehl/imagehl.cpp | 208 +- plugins/imagehl/lbmlib.cpp | 1218 +- plugins/imagem8/imagem8.cpp | 256 +- plugins/imagem8/m32.cpp | 154 +- plugins/imagem8/m8.cpp | 216 +- plugins/imagepng/plugin.cpp | 494 +- plugins/imagewal/imagewal.cpp | 194 +- plugins/imagewal/wal.cpp | 186 +- plugins/map/parse.cpp | 1358 +- plugins/map/plugin.cpp | 268 +- plugins/map/write.cpp | 454 +- plugins/mapxml/plugin.cpp | 156 +- plugins/mapxml/xmlparse.cpp | 590 +- plugins/mapxml/xmlwrite.cpp | 434 +- plugins/model/cpicomodel.cpp | 440 +- plugins/model/cpicosurface.cpp | 406 +- plugins/model/miscmodel.cpp | 902 +- plugins/model/model.cpp | 176 +- plugins/model/plugin.cpp | 868 +- plugins/model/remap.cpp | 636 +- plugins/shaders/plugin.cpp | 206 +- plugins/shaders/shaders.cpp | 1978 +- plugins/spritemodel/plugin.cpp | 558 +- plugins/spritemodel/spritemodel.cpp | 356 +- plugins/surface/surfacedialog.cpp | 3850 ++-- plugins/surface/surfdlg_plugin.cpp | 254 +- plugins/surface_heretic2/surfacedialog.cpp | 3880 ++-- .../surfaceflagsdialog_heretic2.cpp | 2834 +-- plugins/surface_heretic2/surfdlg_plugin.cpp | 254 +- plugins/surface_quake2/surfacedialog.cpp | 3878 ++-- .../surfaceflagsdialog_quake2.cpp | 2336 +-- plugins/surface_quake2/surfdlg_plugin.cpp | 254 +- plugins/textool/2DView.cpp | 404 +- plugins/textool/ControlPointsManager.cpp | 664 +- plugins/textool/StdAfx.cpp | 56 +- plugins/textool/TexTool.cpp | 1934 +- plugins/vfspak/vfs.cpp | 1606 +- plugins/vfspak/vfspak.cpp | 212 +- plugins/vfspk3/unzip.cpp | 9074 ++++----- plugins/vfspk3/vfs.cpp | 1708 +- plugins/vfspk3/vfspk3.cpp | 208 +- plugins/vfswad/unwad.cpp | 502 +- plugins/vfswad/vfs.cpp | 1518 +- plugins/vfswad/vfswad.cpp | 212 +- radiant/bp_dlg.cpp | 310 +- radiant/brush.cpp | 7288 ++++---- radiant/brush_primit.cpp | 1200 +- radiant/brushscript.cpp | 1396 +- radiant/camwindow.cpp | 3400 ++-- radiant/csg.cpp | 1374 +- radiant/dialog.cpp | 590 +- radiant/dialoginfo.cpp | 150 +- radiant/drag.cpp | 1690 +- radiant/eclass.cpp | 994 +- radiant/eclass_def.cpp | 612 +- radiant/error.cpp | 302 +- radiant/feedback.cpp | 736 +- radiant/file.cpp | 780 +- radiant/filters.cpp | 484 +- radiant/findtexturedialog.cpp | 578 +- radiant/glinterface.cpp | 182 +- radiant/glwidget.cpp | 508 +- radiant/glwindow.cpp | 574 +- radiant/groupdialog.cpp | 3426 ++-- radiant/gtkdlgs.cpp | 8090 ++++---- radiant/gtkmisc.cpp | 3220 ++-- radiant/main.cpp | 2492 +-- radiant/mainframe.cpp | 15570 ++++++++-------- radiant/map.cpp | 2644 +-- radiant/missing.cpp | 406 +- radiant/parse.cpp | 440 +- radiant/patchdialog.cpp | 1490 +- radiant/pluginentities.cpp | 148 +- radiant/pluginmanager.cpp | 5044 ++--- radiant/pmesh.cpp | 12854 ++++++------- radiant/points.cpp | 498 +- radiant/preferences.cpp | 6204 +++--- radiant/profile.cpp | 586 +- radiant/qe3.cpp | 3594 ++-- radiant/qgl_ext.cpp | 92 +- radiant/queuedraw.cpp | 316 +- radiant/select.cpp | 4250 ++--- radiant/selectedface.cpp | 256 +- radiant/stdafx.cpp | 70 +- radiant/surfacedialog.cpp | 2268 +-- radiant/surfaceplugin.cpp | 518 +- radiant/targetname.cpp | 180 +- radiant/texmanip.cpp | 760 +- radiant/texwindow.cpp | 3930 ++-- radiant/ui.cpp | 536 +- radiant/undo.cpp | 1946 +- radiant/vertsel.cpp | 772 +- radiant/watchbsp.cpp | 1548 +- radiant/winding.cpp | 1644 +- radiant/xywindow.cpp | 6924 +++---- radiant/z.cpp | 932 +- radiant/zwindow.cpp | 250 +- 189 files changed, 126572 insertions(+), 126572 deletions(-) diff --git a/contrib/bkgrnd2d/bkgrnd2d.cpp b/contrib/bkgrnd2d/bkgrnd2d.cpp index b2f09ff9..0789083e 100644 --- a/contrib/bkgrnd2d/bkgrnd2d.cpp +++ b/contrib/bkgrnd2d/bkgrnd2d.cpp @@ -1,319 +1,319 @@ -/* -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; -} - +/* +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; +} + diff --git a/contrib/bkgrnd2d/dialog.cpp b/contrib/bkgrnd2d/dialog.cpp index 43fe7717..9f4ec49c 100644 --- a/contrib/bkgrnd2d/dialog.cpp +++ b/contrib/bkgrnd2d/dialog.cpp @@ -1,365 +1,365 @@ -/* -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 - -#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(); -} - +/* +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 + +#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(); +} + diff --git a/contrib/bkgrnd2d/plugin.cpp b/contrib/bkgrnd2d/plugin.cpp index 38475b06..7433c349 100644 --- a/contrib/bkgrnd2d/plugin.cpp +++ b/contrib/bkgrnd2d/plugin.cpp @@ -1,325 +1,325 @@ -/* -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"; -} - +/* +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"; +} + diff --git a/contrib/bobtoolz/DBobView.cpp b/contrib/bobtoolz/DBobView.cpp index 74fdacd3..47215106 100644 --- a/contrib/bobtoolz/DBobView.cpp +++ b/contrib/bobtoolz/DBobView.cpp @@ -1,361 +1,361 @@ -/* -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; -} +/* +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; +} diff --git a/contrib/bobtoolz/DBrush.cpp b/contrib/bobtoolz/DBrush.cpp index e571a50a..8d254a6c 100644 --- a/contrib/bobtoolz/DBrush.cpp +++ b/contrib/bobtoolz/DBrush.cpp @@ -1,848 +1,848 @@ -/* -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::const_iterator p1=faceList.begin(); p1!=faceList.end(); p1++) - { - list::const_iterator p2=p1; - for(p2++; p2!=faceList.end(); p2++) - { - list::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::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::const_iterator deadPoint=pointList.begin(); deadPoint!=pointList.end(); deadPoint++) { - delete *deadPoint; - } - pointList.clear(); -} - -void DBrush::ClearFaces() -{ - bBoundsBuilt = FALSE; - for(list::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::const_iterator chkPoint=pointList.begin(); chkPoint!=pointList.end(); chkPoint++) - { - if(**chkPoint == pnt) - return TRUE; - } - - return FALSE; -} - -int DBrush::RemoveRedundantPlanes() -{ - int cnt = 0; - list::iterator chkPlane; - - // find duplicate planes - list::iterator p1=faceList.begin(); - - while( p1!=faceList.end() ) - { - list::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::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::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::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::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::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::const_iterator iplPlane; - - for( iplPlane=faceList.begin(); iplPlane!=faceList.end(); iplPlane++) - { - - bool allInFront = TRUE; - for(list::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::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::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::const_iterator first = pointList.begin(); - VectorCopy((*first)->_pnt, bbox_min); - VectorCopy((*first)->_pnt, bbox_max); - - list::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* exclusionList) -{ - for(list::const_iterator resetPlane=faceList.begin(); resetPlane!=faceList.end(); resetPlane++) - { - bool set = FALSE; - - if(exclusionList) - { - for(list::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::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::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::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::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::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::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::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::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::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::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::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); - } -} +/* +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::const_iterator p1=faceList.begin(); p1!=faceList.end(); p1++) + { + list::const_iterator p2=p1; + for(p2++; p2!=faceList.end(); p2++) + { + list::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::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::const_iterator deadPoint=pointList.begin(); deadPoint!=pointList.end(); deadPoint++) { + delete *deadPoint; + } + pointList.clear(); +} + +void DBrush::ClearFaces() +{ + bBoundsBuilt = FALSE; + for(list::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::const_iterator chkPoint=pointList.begin(); chkPoint!=pointList.end(); chkPoint++) + { + if(**chkPoint == pnt) + return TRUE; + } + + return FALSE; +} + +int DBrush::RemoveRedundantPlanes() +{ + int cnt = 0; + list::iterator chkPlane; + + // find duplicate planes + list::iterator p1=faceList.begin(); + + while( p1!=faceList.end() ) + { + list::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::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::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::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::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::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::const_iterator iplPlane; + + for( iplPlane=faceList.begin(); iplPlane!=faceList.end(); iplPlane++) + { + + bool allInFront = TRUE; + for(list::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::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::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::const_iterator first = pointList.begin(); + VectorCopy((*first)->_pnt, bbox_min); + VectorCopy((*first)->_pnt, bbox_max); + + list::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* exclusionList) +{ + for(list::const_iterator resetPlane=faceList.begin(); resetPlane!=faceList.end(); resetPlane++) + { + bool set = FALSE; + + if(exclusionList) + { + for(list::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::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::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::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::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::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::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::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::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::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::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::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); + } +} diff --git a/contrib/bobtoolz/DEPair.cpp b/contrib/bobtoolz/DEPair.cpp index b52ad5cb..9d5da9d1 100644 --- a/contrib/bobtoolz/DEPair.cpp +++ b/contrib/bobtoolz/DEPair.cpp @@ -1,49 +1,49 @@ -/* -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; -} +/* +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; +} diff --git a/contrib/bobtoolz/DEntity.cpp b/contrib/bobtoolz/DEntity.cpp index 2c4e8a2f..4d3610c8 100644 --- a/contrib/bobtoolz/DEntity.cpp +++ b/contrib/bobtoolz/DEntity.cpp @@ -1,675 +1,675 @@ -/* -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::const_iterator deadBrush=brushList.begin(); deadBrush!=brushList.end(); deadBrush++) - { - delete *deadBrush; - } - brushList.clear(); -} - -void DEntity::ClearPatches() -{ - for(list::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::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::const_iterator pB1=brushList.begin(); pB1!=brushList.end(); pB1++) - { - list::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::const_iterator pB1=brushList.begin(); pB1!=brushList.end(); pB1++) - { - list::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::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* exclusionList, bool useDetail) -{ - list::iterator chkBrush=brushList.begin(); - - while( chkBrush!=brushList.end() ) - { - if(!useDetail) - { - if((*chkBrush)->IsDetail()) - { - delete *chkBrush; - chkBrush = brushList.erase(chkBrush); - continue; - } - } - - list::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* exclusionList) -{ - for(list::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::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::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::const_iterator buildBrush=brushList.begin(); buildBrush!=brushList.end(); buildBrush++) - (*buildBrush)->BuildInRadiant(allowDestruction, NULL, pE); - - for(list::const_iterator buildPatch=patchList.begin(); buildPatch!=patchList.end(); buildPatch++) - (*buildPatch)->BuildInRadiant(pE); - - QER_Entity = pE; - } - else - { - for(list::const_iterator buildBrush=brushList.begin(); buildBrush!=brushList.end(); buildBrush++) - (*buildBrush)->BuildInRadiant(allowDestruction, NULL); - - for(list::const_iterator buildPatch=patchList.begin(); buildPatch!=patchList.end(); buildPatch++) - (*buildPatch)->BuildInRadiant(); - } -} - - - -int DEntity::GetIDMax( void ) { - int max = -1; - for(list::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::const_iterator ep=epairList.begin(); ep!=epairList.end(); ep++) - { - fprintf(pFile, "\"%s\" \"%s\"\n", (const char *)(*ep)->key, (const char *)(*ep)->value); - } - - for(list::const_iterator bp=brushList.begin(); bp!=brushList.end(); bp++) - { - (*bp)->SaveToFile(pFile); - } - - fprintf(pFile, "}\n"); -} - -void DEntity::ClearEPairs() -{ - for(list::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::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::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::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::const_iterator listBrush = brushList.begin(); listBrush != brushList.end(); listBrush++) { - DBrush* pBrush = (*listBrush); - if(pBrush->QER_brush == brush) { - return pBrush; - } - } - return NULL; -} +/* +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::const_iterator deadBrush=brushList.begin(); deadBrush!=brushList.end(); deadBrush++) + { + delete *deadBrush; + } + brushList.clear(); +} + +void DEntity::ClearPatches() +{ + for(list::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::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::const_iterator pB1=brushList.begin(); pB1!=brushList.end(); pB1++) + { + list::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::const_iterator pB1=brushList.begin(); pB1!=brushList.end(); pB1++) + { + list::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::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* exclusionList, bool useDetail) +{ + list::iterator chkBrush=brushList.begin(); + + while( chkBrush!=brushList.end() ) + { + if(!useDetail) + { + if((*chkBrush)->IsDetail()) + { + delete *chkBrush; + chkBrush = brushList.erase(chkBrush); + continue; + } + } + + list::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* exclusionList) +{ + for(list::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::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::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::const_iterator buildBrush=brushList.begin(); buildBrush!=brushList.end(); buildBrush++) + (*buildBrush)->BuildInRadiant(allowDestruction, NULL, pE); + + for(list::const_iterator buildPatch=patchList.begin(); buildPatch!=patchList.end(); buildPatch++) + (*buildPatch)->BuildInRadiant(pE); + + QER_Entity = pE; + } + else + { + for(list::const_iterator buildBrush=brushList.begin(); buildBrush!=brushList.end(); buildBrush++) + (*buildBrush)->BuildInRadiant(allowDestruction, NULL); + + for(list::const_iterator buildPatch=patchList.begin(); buildPatch!=patchList.end(); buildPatch++) + (*buildPatch)->BuildInRadiant(); + } +} + + + +int DEntity::GetIDMax( void ) { + int max = -1; + for(list::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::const_iterator ep=epairList.begin(); ep!=epairList.end(); ep++) + { + fprintf(pFile, "\"%s\" \"%s\"\n", (const char *)(*ep)->key, (const char *)(*ep)->value); + } + + for(list::const_iterator bp=brushList.begin(); bp!=brushList.end(); bp++) + { + (*bp)->SaveToFile(pFile); + } + + fprintf(pFile, "}\n"); +} + +void DEntity::ClearEPairs() +{ + for(list::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::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::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::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::const_iterator listBrush = brushList.begin(); listBrush != brushList.end(); listBrush++) { + DBrush* pBrush = (*listBrush); + if(pBrush->QER_brush == brush) { + return pBrush; + } + } + return NULL; +} diff --git a/contrib/bobtoolz/DListener.cpp b/contrib/bobtoolz/DListener.cpp index 4927fe6e..cb7b928a 100644 --- a/contrib/bobtoolz/DListener.cpp +++ b/contrib/bobtoolz/DListener.cpp @@ -1,93 +1,93 @@ -/* -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; -} +/* +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; +} diff --git a/contrib/bobtoolz/DMap.cpp b/contrib/bobtoolz/DMap.cpp index e827690f..bc0b0661 100644 --- a/contrib/bobtoolz/DMap.cpp +++ b/contrib/bobtoolz/DMap.cpp @@ -1,166 +1,166 @@ -/* -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::const_iterator deadEntity=entityList.begin(); deadEntity!=entityList.end(); deadEntity++) - delete *deadEntity; - - entityList.clear(); -} - -DEntity* DMap::GetEntityForID(int ID) -{ - DEntity* findEntity = NULL; - - for(list::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::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::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::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); -} +/* +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::const_iterator deadEntity=entityList.begin(); deadEntity!=entityList.end(); deadEntity++) + delete *deadEntity; + + entityList.clear(); +} + +DEntity* DMap::GetEntityForID(int ID) +{ + DEntity* findEntity = NULL; + + for(list::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::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::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::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); +} diff --git a/contrib/bobtoolz/DPatch.cpp b/contrib/bobtoolz/DPatch.cpp index 161420f3..36968b0a 100644 --- a/contrib/bobtoolz/DPatch.cpp +++ b/contrib/bobtoolz/DPatch.cpp @@ -1,414 +1,414 @@ -/* -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 -*/ - -// DPatch.cpp: implementation of the DPatch class. -// -////////////////////////////////////////////////////////////////////// - -#include "StdAfx.h" -#include "DPatch.h" -#include "misc.h" -#include "./dialogs/dialogs-gtk.h" - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -// Added patch merging, wahey! - -// -// problem is, you cant put patches into entities as yet :( -// - -DPatch::DPatch() -{ - width = MIN_PATCH_WIDTH; - height = MIN_PATCH_HEIGHT; - QER_patch = NULL; - QER_brush = NULL; -} - -DPatch::~DPatch() -{ - -} - -void DPatch::SetTexture(const char *textureName) -{ - strcpy(texture, textureName); -} - -void CopyDrawVert(const drawVert_t* in, drawVert_t* out) -{ - out->lightmap[0] = in->lightmap[0]; - out->lightmap[1] = in->lightmap[1]; - out->st[0] = in->st[0]; - out->st[1] = in->st[1]; - VectorCopy(in->normal, out->normal); - VectorCopy(in->xyz, out->xyz); -} - -void DPatch::BuildInRadiant(void* entity) -{ - int nIndex = g_FuncTable.m_pfnCreatePatchHandle(); - //$ FIXME: m_pfnGetPatchHandle - patchMesh_t* pm = g_FuncTable.m_pfnGetPatchData(nIndex); - - pm->height = height; - pm->width = width; - - for(int x = 0; x < width; x++) - for(int y = 0; y < height; y++) - CopyDrawVert(&points[x][y], &pm->ctrl[x][y]); - - QER_patch = pm; - -/* if(entity) - { -// strcpy(pm->d_texture->name, texture); - - brush_t* brush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); - brush->patchBrush = TRUE; - brush->pPatch = pm; - - pm->pSymbiot = brush; - pm->bSelected = false; - pm->bOverlay = false; // bleh, f*cks up, just have to wait for a proper function - pm->bDirty = true; // or get my own patch out.... - pm->nListID = -1; - - g_FuncTable.m_pfnCommitBrushHandleToEntity(brush, entity); - } - else*/ // patch to entity just plain dont work atm - - if(entity) - g_FuncTable.m_pfnCommitPatchHandleToEntity(nIndex, pm, texture, entity); - else - g_FuncTable.m_pfnCommitPatchHandleToMap(nIndex, pm, texture); - - QER_brush = pm->pSymbiot; -} - -void DPatch::LoadFromBrush_t(brush_t* brush) -{ - QER_brush = brush; - QER_patch = brush->pPatch; - - SetTexture(QER_patch->pShader->getName()); - - for(int x = 0; x < QER_patch->width; x++) - for(int y = 0; y < QER_patch->height; y++) - CopyDrawVert(&QER_patch->ctrl[x][y], &points[x][y]); - - width = QER_patch->width; - height = QER_patch->height; -} - -void DPatch::RemoveFromRadiant() -{ - if(QER_brush) - g_FuncTable.m_pfnDeleteBrushHandle(QER_brush); -} - -bool DPatch::ResetTextures(const char *oldTextureName, const char *newTextureName) -{ - if( !oldTextureName || !strcmp(texture, oldTextureName)) - { - strcpy(texture, newTextureName); - return TRUE; - } - - return FALSE; -} - -void Build1dArray(vec3_t* array, drawVert_t points[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT], - int startX, int startY, int number, bool horizontal, bool inverse) -{ - int x = startX, y = startY, i, step; - - if(inverse) - step = -1; - else - step = 1; - - for(i = 0; i < number; i++) - { - VectorCopy(points[x][y].xyz, array[i]); - - if(horizontal) - x+=step; - else - y+=step; - } -} - -void Print1dArray(vec3_t* array, int size) -{ - for(int i = 0; i < size; i++) - Sys_Printf("(%.0f %.0f %.0f)\t", array[i][0], array[i][1], array[i][2]); - Sys_Printf("\n"); -} - -bool Compare1dArrays(vec3_t* a1, vec3_t* a2, int size) -{ - int i; - bool equal = true; - - for(i = 0; i < size; i++) - { - if(!VectorCompare(a1[i], a2[size-i-1])) - { - equal = false; - break; - } - } - return equal; -} - -patch_merge_t DPatch::IsMergable(DPatch *other) -{ - int i, j; - vec3_t p1Array[4][MAX_PATCH_HEIGHT]; - vec3_t p2Array[4][MAX_PATCH_HEIGHT]; - - int p1ArraySizes[4]; - int p2ArraySizes[4]; - - patch_merge_t merge_info; - - Build1dArray(p1Array[0], this->points, 0, 0, this->width, true, false); - Build1dArray(p1Array[1], this->points, this->width-1, 0, this->height, false, false); - Build1dArray(p1Array[2], this->points, this->width-1, this->height-1, this->width, true, true); - Build1dArray(p1Array[3], this->points, 0, this->height-1, this->height, false, true); - - Build1dArray(p2Array[0], other->points, 0, 0, other->width, true, false); - Build1dArray(p2Array[1], other->points, other->width-1, 0, other->height, false, false); - Build1dArray(p2Array[2], other->points, other->width-1, other->height-1, other->width, true, true); - Build1dArray(p2Array[3], other->points, 0, other->height-1, other->height, false, true); - - p1ArraySizes[0] = this->width; - p1ArraySizes[1] = this->height; - p1ArraySizes[2] = this->width; - p1ArraySizes[3] = this->height; - - p2ArraySizes[0] = other->width; - p2ArraySizes[1] = other->height; - p2ArraySizes[2] = other->width; - p2ArraySizes[3] = other->height; - - for(i = 0; i < 4; i++) - { - for(j = 0; j < 4; j++) - { - if(p1ArraySizes[i] == p2ArraySizes[j]) - { - if(Compare1dArrays(p1Array[i], p2Array[j], p1ArraySizes[i])) - { - merge_info.pos1 = i; - merge_info.pos2 = j; - merge_info.mergable = true; - return merge_info; - } - } - } - } - - merge_info.mergable = false; - return merge_info; -} - -DPatch* DPatch::MergePatches(patch_merge_t merge_info, DPatch *p1, DPatch *p2) -{ - while(merge_info.pos1 != 2) - { - p1->Transpose(); - merge_info.pos1--; - if(merge_info.pos1 < 0) - merge_info.pos1 += 4; - } - - while(merge_info.pos2 != 0) - { - p2->Transpose(); - merge_info.pos2--; - if(merge_info.pos2 < 0) - merge_info.pos2 += 3; - } - - int newHeight = p1->height + p2->height - 1; - if(newHeight > MAX_PATCH_HEIGHT) - return NULL; - - DPatch* newPatch = new DPatch(); - - newPatch->height = newHeight; - newPatch->width = p1->width; - newPatch->SetTexture(p1->texture); - - int y = 0; - int i; - for(i = 0; i < p1->height; i++, y++) - for(int x = 0; x < p1->width; x++) - memcpy(&newPatch->points[x][y], &p1->points[x][i], sizeof(drawVert_t)); - - for(i = 1; i < p2->height; i++, y++) - for(int x = 0; x < p2->width; x++) - memcpy(&newPatch->points[x][y], &p2->points[x][i], sizeof(drawVert_t)); - -// newPatch->Invert(); - - return newPatch; -} - -void DPatch::Invert() -{ - drawVert_t vertTemp; - int i, j; - - for(i = 0 ; i < width ; i++ ) - { - for(j = 0; j < height / 2; j++) - { - memcpy(&vertTemp, &points[i][height - 1- j], sizeof (drawVert_t)); - memcpy(&points[i][height - 1 - j], &points[i][j], sizeof(drawVert_t)); - memcpy(&points[i][j], &vertTemp, sizeof(drawVert_t)); - } - } -} - -void DPatch::Transpose() -{ - int i, j, w; - drawVert_t dv; - - if ( width > height ) - { - for ( i = 0 ; i < height ; i++ ) - { - for ( j = i + 1 ; j < width ; j++ ) - { - if ( j < height ) - { - // swap the value - memcpy(&dv, &points[j][i], sizeof(drawVert_t)); - memcpy(&points[j][i], &points[i][j], sizeof(drawVert_t)); - memcpy(&points[i][j], &dv, sizeof(drawVert_t)); - } - else - { - // just copy - memcpy(&points[i][j], &points[j][i], sizeof(drawVert_t)); - } - } - } - } - else - { - for ( i = 0 ; i < width ; i++ ) - { - for ( j = i + 1 ; j < height ; j++ ) - { - if ( j < width ) - { - // swap the value - memcpy(&dv, &points[i][j], sizeof(drawVert_t)); - memcpy(&points[i][j], &points[j][i], sizeof(drawVert_t)); - memcpy(&points[j][i], &dv, sizeof(drawVert_t)); - } - else - { - // just copy - memcpy(&points[j][i], &points[i][j], sizeof(drawVert_t)); - } - } - } - } - - w = width; - width = height; - height = w; - - Invert(); -} - -list DPatch::Split(bool rows, bool cols) -{ - list patchList; - int i; - int x, y; - - if(rows && height >= 5) - { - for(i = 0; i < (height-1)/2; i++) - { - DPatch p; - - p.width = width; - p.height = 3; - p.SetTexture(texture); - - for(y = 0; y < 3; y++) - { - for(x = 0; x < p.width; x++) - { - memcpy(&p.points[x][y], &points[x][(i*2)+y], sizeof(drawVert_t)); - } - } - patchList.push_back(p); - } - - if(cols && width >= 5) - { - list patchList2; - - for(list::iterator patches = patchList.begin(); patches != patchList.end(); patches++) - { - list patchList3 = (*patches).Split(false, true); - - for(list::iterator patches2 = patchList3.begin(); patches2 != patchList3.end(); patches2++) - patchList2.push_front(*patches2); - } - - return patchList2; - } - } - else if(cols && width >= 5) - { - for(i = 0; i < (width-1)/2; i++) - { - DPatch p; - - p.height = height; - p.width = 3; - p.SetTexture(texture); - - for(x = 0; x < 3; x++) - { - for(y = 0; y < p.height; y++) - { - memcpy(&p.points[x][y], &points[(i*2)+x][y], sizeof(drawVert_t)); - } - } - - patchList.push_back(p); - } - } - - return patchList; -} +/* +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 +*/ + +// DPatch.cpp: implementation of the DPatch class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DPatch.h" +#include "misc.h" +#include "./dialogs/dialogs-gtk.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +// Added patch merging, wahey! + +// +// problem is, you cant put patches into entities as yet :( +// + +DPatch::DPatch() +{ + width = MIN_PATCH_WIDTH; + height = MIN_PATCH_HEIGHT; + QER_patch = NULL; + QER_brush = NULL; +} + +DPatch::~DPatch() +{ + +} + +void DPatch::SetTexture(const char *textureName) +{ + strcpy(texture, textureName); +} + +void CopyDrawVert(const drawVert_t* in, drawVert_t* out) +{ + out->lightmap[0] = in->lightmap[0]; + out->lightmap[1] = in->lightmap[1]; + out->st[0] = in->st[0]; + out->st[1] = in->st[1]; + VectorCopy(in->normal, out->normal); + VectorCopy(in->xyz, out->xyz); +} + +void DPatch::BuildInRadiant(void* entity) +{ + int nIndex = g_FuncTable.m_pfnCreatePatchHandle(); + //$ FIXME: m_pfnGetPatchHandle + patchMesh_t* pm = g_FuncTable.m_pfnGetPatchData(nIndex); + + pm->height = height; + pm->width = width; + + for(int x = 0; x < width; x++) + for(int y = 0; y < height; y++) + CopyDrawVert(&points[x][y], &pm->ctrl[x][y]); + + QER_patch = pm; + +/* if(entity) + { +// strcpy(pm->d_texture->name, texture); + + brush_t* brush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); + brush->patchBrush = TRUE; + brush->pPatch = pm; + + pm->pSymbiot = brush; + pm->bSelected = false; + pm->bOverlay = false; // bleh, f*cks up, just have to wait for a proper function + pm->bDirty = true; // or get my own patch out.... + pm->nListID = -1; + + g_FuncTable.m_pfnCommitBrushHandleToEntity(brush, entity); + } + else*/ // patch to entity just plain dont work atm + + if(entity) + g_FuncTable.m_pfnCommitPatchHandleToEntity(nIndex, pm, texture, entity); + else + g_FuncTable.m_pfnCommitPatchHandleToMap(nIndex, pm, texture); + + QER_brush = pm->pSymbiot; +} + +void DPatch::LoadFromBrush_t(brush_t* brush) +{ + QER_brush = brush; + QER_patch = brush->pPatch; + + SetTexture(QER_patch->pShader->getName()); + + for(int x = 0; x < QER_patch->width; x++) + for(int y = 0; y < QER_patch->height; y++) + CopyDrawVert(&QER_patch->ctrl[x][y], &points[x][y]); + + width = QER_patch->width; + height = QER_patch->height; +} + +void DPatch::RemoveFromRadiant() +{ + if(QER_brush) + g_FuncTable.m_pfnDeleteBrushHandle(QER_brush); +} + +bool DPatch::ResetTextures(const char *oldTextureName, const char *newTextureName) +{ + if( !oldTextureName || !strcmp(texture, oldTextureName)) + { + strcpy(texture, newTextureName); + return TRUE; + } + + return FALSE; +} + +void Build1dArray(vec3_t* array, drawVert_t points[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT], + int startX, int startY, int number, bool horizontal, bool inverse) +{ + int x = startX, y = startY, i, step; + + if(inverse) + step = -1; + else + step = 1; + + for(i = 0; i < number; i++) + { + VectorCopy(points[x][y].xyz, array[i]); + + if(horizontal) + x+=step; + else + y+=step; + } +} + +void Print1dArray(vec3_t* array, int size) +{ + for(int i = 0; i < size; i++) + Sys_Printf("(%.0f %.0f %.0f)\t", array[i][0], array[i][1], array[i][2]); + Sys_Printf("\n"); +} + +bool Compare1dArrays(vec3_t* a1, vec3_t* a2, int size) +{ + int i; + bool equal = true; + + for(i = 0; i < size; i++) + { + if(!VectorCompare(a1[i], a2[size-i-1])) + { + equal = false; + break; + } + } + return equal; +} + +patch_merge_t DPatch::IsMergable(DPatch *other) +{ + int i, j; + vec3_t p1Array[4][MAX_PATCH_HEIGHT]; + vec3_t p2Array[4][MAX_PATCH_HEIGHT]; + + int p1ArraySizes[4]; + int p2ArraySizes[4]; + + patch_merge_t merge_info; + + Build1dArray(p1Array[0], this->points, 0, 0, this->width, true, false); + Build1dArray(p1Array[1], this->points, this->width-1, 0, this->height, false, false); + Build1dArray(p1Array[2], this->points, this->width-1, this->height-1, this->width, true, true); + Build1dArray(p1Array[3], this->points, 0, this->height-1, this->height, false, true); + + Build1dArray(p2Array[0], other->points, 0, 0, other->width, true, false); + Build1dArray(p2Array[1], other->points, other->width-1, 0, other->height, false, false); + Build1dArray(p2Array[2], other->points, other->width-1, other->height-1, other->width, true, true); + Build1dArray(p2Array[3], other->points, 0, other->height-1, other->height, false, true); + + p1ArraySizes[0] = this->width; + p1ArraySizes[1] = this->height; + p1ArraySizes[2] = this->width; + p1ArraySizes[3] = this->height; + + p2ArraySizes[0] = other->width; + p2ArraySizes[1] = other->height; + p2ArraySizes[2] = other->width; + p2ArraySizes[3] = other->height; + + for(i = 0; i < 4; i++) + { + for(j = 0; j < 4; j++) + { + if(p1ArraySizes[i] == p2ArraySizes[j]) + { + if(Compare1dArrays(p1Array[i], p2Array[j], p1ArraySizes[i])) + { + merge_info.pos1 = i; + merge_info.pos2 = j; + merge_info.mergable = true; + return merge_info; + } + } + } + } + + merge_info.mergable = false; + return merge_info; +} + +DPatch* DPatch::MergePatches(patch_merge_t merge_info, DPatch *p1, DPatch *p2) +{ + while(merge_info.pos1 != 2) + { + p1->Transpose(); + merge_info.pos1--; + if(merge_info.pos1 < 0) + merge_info.pos1 += 4; + } + + while(merge_info.pos2 != 0) + { + p2->Transpose(); + merge_info.pos2--; + if(merge_info.pos2 < 0) + merge_info.pos2 += 3; + } + + int newHeight = p1->height + p2->height - 1; + if(newHeight > MAX_PATCH_HEIGHT) + return NULL; + + DPatch* newPatch = new DPatch(); + + newPatch->height = newHeight; + newPatch->width = p1->width; + newPatch->SetTexture(p1->texture); + + int y = 0; + int i; + for(i = 0; i < p1->height; i++, y++) + for(int x = 0; x < p1->width; x++) + memcpy(&newPatch->points[x][y], &p1->points[x][i], sizeof(drawVert_t)); + + for(i = 1; i < p2->height; i++, y++) + for(int x = 0; x < p2->width; x++) + memcpy(&newPatch->points[x][y], &p2->points[x][i], sizeof(drawVert_t)); + +// newPatch->Invert(); + + return newPatch; +} + +void DPatch::Invert() +{ + drawVert_t vertTemp; + int i, j; + + for(i = 0 ; i < width ; i++ ) + { + for(j = 0; j < height / 2; j++) + { + memcpy(&vertTemp, &points[i][height - 1- j], sizeof (drawVert_t)); + memcpy(&points[i][height - 1 - j], &points[i][j], sizeof(drawVert_t)); + memcpy(&points[i][j], &vertTemp, sizeof(drawVert_t)); + } + } +} + +void DPatch::Transpose() +{ + int i, j, w; + drawVert_t dv; + + if ( width > height ) + { + for ( i = 0 ; i < height ; i++ ) + { + for ( j = i + 1 ; j < width ; j++ ) + { + if ( j < height ) + { + // swap the value + memcpy(&dv, &points[j][i], sizeof(drawVert_t)); + memcpy(&points[j][i], &points[i][j], sizeof(drawVert_t)); + memcpy(&points[i][j], &dv, sizeof(drawVert_t)); + } + else + { + // just copy + memcpy(&points[i][j], &points[j][i], sizeof(drawVert_t)); + } + } + } + } + else + { + for ( i = 0 ; i < width ; i++ ) + { + for ( j = i + 1 ; j < height ; j++ ) + { + if ( j < width ) + { + // swap the value + memcpy(&dv, &points[i][j], sizeof(drawVert_t)); + memcpy(&points[i][j], &points[j][i], sizeof(drawVert_t)); + memcpy(&points[j][i], &dv, sizeof(drawVert_t)); + } + else + { + // just copy + memcpy(&points[j][i], &points[i][j], sizeof(drawVert_t)); + } + } + } + } + + w = width; + width = height; + height = w; + + Invert(); +} + +list DPatch::Split(bool rows, bool cols) +{ + list patchList; + int i; + int x, y; + + if(rows && height >= 5) + { + for(i = 0; i < (height-1)/2; i++) + { + DPatch p; + + p.width = width; + p.height = 3; + p.SetTexture(texture); + + for(y = 0; y < 3; y++) + { + for(x = 0; x < p.width; x++) + { + memcpy(&p.points[x][y], &points[x][(i*2)+y], sizeof(drawVert_t)); + } + } + patchList.push_back(p); + } + + if(cols && width >= 5) + { + list patchList2; + + for(list::iterator patches = patchList.begin(); patches != patchList.end(); patches++) + { + list patchList3 = (*patches).Split(false, true); + + for(list::iterator patches2 = patchList3.begin(); patches2 != patchList3.end(); patches2++) + patchList2.push_front(*patches2); + } + + return patchList2; + } + } + else if(cols && width >= 5) + { + for(i = 0; i < (width-1)/2; i++) + { + DPatch p; + + p.height = height; + p.width = 3; + p.SetTexture(texture); + + for(x = 0; x < 3; x++) + { + for(y = 0; y < p.height; y++) + { + memcpy(&p.points[x][y], &points[(i*2)+x][y], sizeof(drawVert_t)); + } + } + + patchList.push_back(p); + } + } + + return patchList; +} diff --git a/contrib/bobtoolz/DPlane.cpp b/contrib/bobtoolz/DPlane.cpp index 2fe24ecf..f11241ec 100644 --- a/contrib/bobtoolz/DPlane.cpp +++ b/contrib/bobtoolz/DPlane.cpp @@ -1,256 +1,256 @@ -/* -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 -*/ - -// DPlane.cpp: implementation of the DPlane class. -// -////////////////////////////////////////////////////////////////////// - -#include "StdAfx.h" -#include "DPlane.h" -#include "DWinding.h" -#include "misc.h" - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -DPlane::DPlane(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* texData) -{ - MakeNormal( va, vb, vc, normal ); - if(VectorNormalize(normal, normal) == 0) // normalizes and returns length - Sys_ERROR("DPlane::DPlane: Bad Normal.\n"); - - _d = (normal[0]*va[0]) + (normal[1]*va[1]) + (normal[2]*va[2]); - - VectorCopy(va, points[0]); - VectorCopy(vb, points[1]); - VectorCopy(vc, points[2]); - - m_bChkOk = TRUE; - - if(texData) - memcpy(&texInfo, texData, sizeof(_QERFaceData)); - else - FillDefaultTexture(&texInfo, points[0], points[1], points[2], "textures/common/caulk"); -} - -DPlane::~DPlane() -{ - -} - -////////////////////////////////////////////////////////////////////// -// Implementation -////////////////////////////////////////////////////////////////////// - -vec_t DPlane::DistanceToPoint(vec3_t pnt) -{ - vec3_t tmp; - VectorSubtract(pnt, points[0], tmp); - return DotProduct(tmp, normal); -} - -bool DPlane::PlaneIntersection(DPlane *pl1, DPlane *pl2, vec3_t out) -{ - float a1, a2, a3; - float b1, b2, b3; - float c1, c2, c3; - - a1 = normal[0]; a2 = normal[1]; a3 = normal[2]; - b1 = pl1->normal[0]; b2 = pl1->normal[1]; b3 = pl1->normal[2]; - c1 = pl2->normal[0]; c2 = pl2->normal[1]; c3 = pl2->normal[2]; - - float d = Determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3); - - if(d == 0) - return FALSE; - - float v1 = _d; - float v2 = pl1->_d; - float v3 = pl2->_d; - - float d1 = Determinant3x3(v1, a2, a3, v2, b2, b3, v3, c2, c3); - float d2 = Determinant3x3(a1, v1, a3, b1, v2, b3, c1, v3, c3); - float d3 = Determinant3x3(a1, a2, v1, b1, b2, v2, c1, c2, v3); - - out[0] = d1/d; - out[1] = d2/d; - out[2] = d3/d; - - return TRUE; -} - -bool DPlane::IsRedundant(list& pointList) -{ - int cnt = 0; - - //list::const_iterator point=pointList.begin(); - for(list::const_iterator point=pointList.begin(); point!=pointList.end(); point++) - { - if(fabs(DistanceToPoint((*point)->_pnt)) < MAX_ROUND_ERROR) - cnt++; - - if(cnt == 3) - return FALSE; - } - return TRUE; -} - -bool DPlane::operator == (DPlane& other) -{ - vec3_t chk; - VectorSubtract(other.normal, normal, chk); - if(fabs(VectorLength(chk)) > MAX_ROUND_ERROR) - return FALSE; - - if(fabs(other._d - _d) > MAX_ROUND_ERROR) - return FALSE; - - return TRUE; -} - -bool DPlane::operator != (DPlane& other) -{ - vec3_t chk; - VectorAdd(other.normal, normal, chk); - if(fabs(VectorLength(chk)) > MAX_ROUND_ERROR) - return FALSE; - - return TRUE; -} - -DWinding* DPlane::BaseWindingForPlane() -{ - int i, x; - vec_t max, v; - vec3_t org, vright, vup; - -// find the major axis - - max = -131072; - x = -1; - for (i=0 ; i<3; i++) - { - v = (float)fabs(normal[i]); - if (v > max) - { - x = i; - max = v; - } - } - if (x==-1) - Sys_Printf ("BaseWindingForPlane: no axis found"); - - VectorCopy (vec3_origin, vup); - switch (x) - { - case 0: - case 1: - vup[2] = 1; - break; - case 2: - vup[0] = 1; - break; - } - - v = DotProduct (vup, normal); - VectorMA (vup, -v, normal, vup); - VectorNormalize (vup, vup); - - VectorScale (normal, _d, org); - - CrossProduct (vup, normal, vright); - - VectorScale (vup, 131072, vup); - VectorScale (vright, 131072, vright); - -// project a really big axis aligned box onto the plane - DWinding* w = new DWinding; - w->AllocWinding(4); - - VectorSubtract (org, vright, w->p[0]); - VectorAdd (w->p[0], vup, w->p[0]); - - VectorAdd (org, vright, w->p[1]); - VectorAdd (w->p[1], vup, w->p[1]); - - VectorAdd (org, vright, w->p[2]); - VectorSubtract (w->p[2], vup, w->p[2]); - - VectorSubtract (org, vright, w->p[3]); - VectorSubtract (w->p[3], vup, w->p[3]); - - return w; -} - -void DPlane::Rebuild() -{ - vec3_t v1, v2; - VectorSubtract(points[0], points[1], v1); - VectorSubtract(points[2], points[1], v2); - CrossProduct(v1, v2, normal); - - if(VectorNormalize(normal, normal) == 0) // normalizes and returns length - Sys_ERROR("DPlane::Rebuild: Bad Normal.\n"); - - _d = (normal[0]*points[0][0]) + (normal[1]*points[0][1]) + (normal[2]*points[0][2]); - - VectorCopy(points[0], texInfo.m_v1); - VectorCopy(points[1], texInfo.m_v2); - VectorCopy(points[2], texInfo.m_v3); -} - -bool DPlane::AddToBrush_t(brush_t *brush) -{ - if(m_bChkOk || !strcmp(texInfo.m_TextureName, "textures/common/caulk")) - { - g_FuncTable.m_pfnAddFaceData(brush, &texInfo); - return FALSE; - } - - strcpy(texInfo.m_TextureName, "textures/common/caulk"); - g_FuncTable.m_pfnAddFaceData(brush, &texInfo); - return TRUE; -} - -void DPlane::ScaleTexture() -{ } - -DPlane::DPlane(vec3_t va, vec3_t vb, vec3_t vc, const char* textureName, bool bDetail) -{ - vec3_t v1, v2; - VectorSubtract(va, vb, v1); - VectorSubtract(vc, vb, v2); - CrossProduct(v1, v2, normal); - - if(VectorNormalize(normal, normal) == 0) // normalizes and returns length - Sys_ERROR("DPlane::DPlane: Bad Normal.\n"); - - _d = (normal[0]*va[0]) + (normal[1]*va[1]) + (normal[2]*va[2]); - - VectorCopy(va, points[0]); - VectorCopy(vb, points[1]); - VectorCopy(vc, points[2]); - - m_bChkOk = TRUE; - - FillDefaultTexture(&texInfo, points[0], points[1], points[2], textureName); - if(bDetail) - texInfo.m_nContents |= FACE_DETAIL; -} +/* +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 +*/ + +// DPlane.cpp: implementation of the DPlane class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DPlane.h" +#include "DWinding.h" +#include "misc.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DPlane::DPlane(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* texData) +{ + MakeNormal( va, vb, vc, normal ); + if(VectorNormalize(normal, normal) == 0) // normalizes and returns length + Sys_ERROR("DPlane::DPlane: Bad Normal.\n"); + + _d = (normal[0]*va[0]) + (normal[1]*va[1]) + (normal[2]*va[2]); + + VectorCopy(va, points[0]); + VectorCopy(vb, points[1]); + VectorCopy(vc, points[2]); + + m_bChkOk = TRUE; + + if(texData) + memcpy(&texInfo, texData, sizeof(_QERFaceData)); + else + FillDefaultTexture(&texInfo, points[0], points[1], points[2], "textures/common/caulk"); +} + +DPlane::~DPlane() +{ + +} + +////////////////////////////////////////////////////////////////////// +// Implementation +////////////////////////////////////////////////////////////////////// + +vec_t DPlane::DistanceToPoint(vec3_t pnt) +{ + vec3_t tmp; + VectorSubtract(pnt, points[0], tmp); + return DotProduct(tmp, normal); +} + +bool DPlane::PlaneIntersection(DPlane *pl1, DPlane *pl2, vec3_t out) +{ + float a1, a2, a3; + float b1, b2, b3; + float c1, c2, c3; + + a1 = normal[0]; a2 = normal[1]; a3 = normal[2]; + b1 = pl1->normal[0]; b2 = pl1->normal[1]; b3 = pl1->normal[2]; + c1 = pl2->normal[0]; c2 = pl2->normal[1]; c3 = pl2->normal[2]; + + float d = Determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3); + + if(d == 0) + return FALSE; + + float v1 = _d; + float v2 = pl1->_d; + float v3 = pl2->_d; + + float d1 = Determinant3x3(v1, a2, a3, v2, b2, b3, v3, c2, c3); + float d2 = Determinant3x3(a1, v1, a3, b1, v2, b3, c1, v3, c3); + float d3 = Determinant3x3(a1, a2, v1, b1, b2, v2, c1, c2, v3); + + out[0] = d1/d; + out[1] = d2/d; + out[2] = d3/d; + + return TRUE; +} + +bool DPlane::IsRedundant(list& pointList) +{ + int cnt = 0; + + //list::const_iterator point=pointList.begin(); + for(list::const_iterator point=pointList.begin(); point!=pointList.end(); point++) + { + if(fabs(DistanceToPoint((*point)->_pnt)) < MAX_ROUND_ERROR) + cnt++; + + if(cnt == 3) + return FALSE; + } + return TRUE; +} + +bool DPlane::operator == (DPlane& other) +{ + vec3_t chk; + VectorSubtract(other.normal, normal, chk); + if(fabs(VectorLength(chk)) > MAX_ROUND_ERROR) + return FALSE; + + if(fabs(other._d - _d) > MAX_ROUND_ERROR) + return FALSE; + + return TRUE; +} + +bool DPlane::operator != (DPlane& other) +{ + vec3_t chk; + VectorAdd(other.normal, normal, chk); + if(fabs(VectorLength(chk)) > MAX_ROUND_ERROR) + return FALSE; + + return TRUE; +} + +DWinding* DPlane::BaseWindingForPlane() +{ + int i, x; + vec_t max, v; + vec3_t org, vright, vup; + +// find the major axis + + max = -131072; + x = -1; + for (i=0 ; i<3; i++) + { + v = (float)fabs(normal[i]); + if (v > max) + { + x = i; + max = v; + } + } + if (x==-1) + Sys_Printf ("BaseWindingForPlane: no axis found"); + + VectorCopy (vec3_origin, vup); + switch (x) + { + case 0: + case 1: + vup[2] = 1; + break; + case 2: + vup[0] = 1; + break; + } + + v = DotProduct (vup, normal); + VectorMA (vup, -v, normal, vup); + VectorNormalize (vup, vup); + + VectorScale (normal, _d, org); + + CrossProduct (vup, normal, vright); + + VectorScale (vup, 131072, vup); + VectorScale (vright, 131072, vright); + +// project a really big axis aligned box onto the plane + DWinding* w = new DWinding; + w->AllocWinding(4); + + VectorSubtract (org, vright, w->p[0]); + VectorAdd (w->p[0], vup, w->p[0]); + + VectorAdd (org, vright, w->p[1]); + VectorAdd (w->p[1], vup, w->p[1]); + + VectorAdd (org, vright, w->p[2]); + VectorSubtract (w->p[2], vup, w->p[2]); + + VectorSubtract (org, vright, w->p[3]); + VectorSubtract (w->p[3], vup, w->p[3]); + + return w; +} + +void DPlane::Rebuild() +{ + vec3_t v1, v2; + VectorSubtract(points[0], points[1], v1); + VectorSubtract(points[2], points[1], v2); + CrossProduct(v1, v2, normal); + + if(VectorNormalize(normal, normal) == 0) // normalizes and returns length + Sys_ERROR("DPlane::Rebuild: Bad Normal.\n"); + + _d = (normal[0]*points[0][0]) + (normal[1]*points[0][1]) + (normal[2]*points[0][2]); + + VectorCopy(points[0], texInfo.m_v1); + VectorCopy(points[1], texInfo.m_v2); + VectorCopy(points[2], texInfo.m_v3); +} + +bool DPlane::AddToBrush_t(brush_t *brush) +{ + if(m_bChkOk || !strcmp(texInfo.m_TextureName, "textures/common/caulk")) + { + g_FuncTable.m_pfnAddFaceData(brush, &texInfo); + return FALSE; + } + + strcpy(texInfo.m_TextureName, "textures/common/caulk"); + g_FuncTable.m_pfnAddFaceData(brush, &texInfo); + return TRUE; +} + +void DPlane::ScaleTexture() +{ } + +DPlane::DPlane(vec3_t va, vec3_t vb, vec3_t vc, const char* textureName, bool bDetail) +{ + vec3_t v1, v2; + VectorSubtract(va, vb, v1); + VectorSubtract(vc, vb, v2); + CrossProduct(v1, v2, normal); + + if(VectorNormalize(normal, normal) == 0) // normalizes and returns length + Sys_ERROR("DPlane::DPlane: Bad Normal.\n"); + + _d = (normal[0]*va[0]) + (normal[1]*va[1]) + (normal[2]*va[2]); + + VectorCopy(va, points[0]); + VectorCopy(vb, points[1]); + VectorCopy(vc, points[2]); + + m_bChkOk = TRUE; + + FillDefaultTexture(&texInfo, points[0], points[1], points[2], textureName); + if(bDetail) + texInfo.m_nContents |= FACE_DETAIL; +} diff --git a/contrib/bobtoolz/DPoint.cpp b/contrib/bobtoolz/DPoint.cpp index e99911fd..a56e91f0 100644 --- a/contrib/bobtoolz/DPoint.cpp +++ b/contrib/bobtoolz/DPoint.cpp @@ -1,52 +1,52 @@ -/* -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 -*/ - -// DPoint.cpp: implementation of the DPoint class. -// -////////////////////////////////////////////////////////////////////// - -#include "StdAfx.h" -#include "DPoint.h" - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -DPoint::DPoint() -{ - -} - -DPoint::~DPoint() -{ - -} - -////////////////////////////////////////////////////////////////////// -// Implementation -////////////////////////////////////////////////////////////////////// - -bool DPoint::operator ==(vec3_t other) -{ - vec3_t test; - VectorSubtract(other, _pnt, test); - if(fabs(VectorLength(test)) > MAX_ROUND_ERROR) - return FALSE; - return TRUE; -} +/* +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 +*/ + +// DPoint.cpp: implementation of the DPoint class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DPoint.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DPoint::DPoint() +{ + +} + +DPoint::~DPoint() +{ + +} + +////////////////////////////////////////////////////////////////////// +// Implementation +////////////////////////////////////////////////////////////////////// + +bool DPoint::operator ==(vec3_t other) +{ + vec3_t test; + VectorSubtract(other, _pnt, test); + if(fabs(VectorLength(test)) > MAX_ROUND_ERROR) + return FALSE; + return TRUE; +} diff --git a/contrib/bobtoolz/DShape.cpp b/contrib/bobtoolz/DShape.cpp index 83e68659..9418b73b 100644 --- a/contrib/bobtoolz/DShape.cpp +++ b/contrib/bobtoolz/DShape.cpp @@ -1,459 +1,459 @@ -/* -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 -*/ - -// DShape.cpp: implementation of the DShape class. -// -////////////////////////////////////////////////////////////////////// - -#include "StdAfx.h" -#include "DShape.h" - -//#include "dialogs-gtk.h" - -#include "misc.h" -#include "shapes.h" - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -bool bFacesAll[6] = {TRUE, TRUE, TRUE, TRUE, TRUE, TRUE}; - -DShape::DShape() -{ - m_nNextBrush = 0; -} - -DShape::~DShape() -{ - -} - -void DShape::BuildRegularPrism(vec3_t min, vec3_t max, int nSides, bool bAlignTop) -{ - vec3_t vc[MAX_POLYGON_FACES+2], vd[MAX_POLYGON_FACES+2]; - - vec3_t radius; - vec3_t origin; - - VectorSubtract(max, min, radius); - VectorScale(radius, 0.5f, radius); - // calc 3d radius and origin - VectorAdd(max, min, origin); - VectorScale(origin, 0.5f, origin); - - float phase = 0.0f; - - if(bAlignTop) - { - phase = -(Q_PI/nSides); - VectorScale(radius, static_cast< float >( 1/cos(phase) ), radius); - } - - //----- Build Polygon Vertices ----- - - int i; - for(i = 0; i < nSides; i++) - { - VectorCopy(origin, vc[i]); - VectorCopy(origin, vd[i]); - - vc[i][2] = min[2]; - vd[i][2] = max[2]; - - vc[i][0] += radius[0] * sinf( ( 2 * Q_PI * i / nSides ) + phase ); - vc[i][1] += radius[1] * cosf( ( 2 * Q_PI * i / nSides ) + phase ); - - vd[i][0] = vc[i][0]; - vd[i][1] = vc[i][1]; - } - - VectorCopy(vc[0], vc[nSides]); - VectorCopy(vd[0], vd[nSides]); - VectorCopy(vc[1], vc[nSides+1]); - VectorCopy(vd[1], vd[nSides+1]); - - //---------------------------------- - - DBrush* pB = m_Container.GetWorldSpawn()->NewBrush(m_nNextBrush++); - - for(i = 1; i <= nSides; i++) - pB->AddFace(vc[i-1], vc[i], vd[i], GetCurrentTexture(), FALSE); - - pB->AddFace(vc[2], vc[1], vc[0], "textures/common/caulk", FALSE); - pB->AddFace(vd[0], vd[1], vd[2], "textures/common/caulk", FALSE); -} - -void DShape::Commit() -{ - m_Container.GetWorldSpawn()->FixBrushes(FALSE); - m_Container.BuildInRadiant(TRUE); -} - -void DShape::BuildInversePrism(vec3_t min, vec3_t max, int nSides, bool bAlignTop) -{ - vec3_t va[MAX_POLYGON_FACES+1], vb[MAX_POLYGON_FACES+1]; - vec3_t radius; - vec3_t origin; - - VectorSubtract(max, min, radius); - VectorScale(radius, 0.5f, radius); - // calc 3d radius and origin - VectorAdd(max, min, origin); - VectorScale(origin, 0.5f, origin); - - float phase = 0.0f; - - if(bAlignTop) - { - phase = -(Q_PI/nSides); - VectorScale(radius, static_cast< float >( 1/cos(phase) ), radius); - } - - //----- Build Polygon Vertices ----- - - int i; - for(i = 0; i < nSides; i++) - { - VectorCopy(origin, va[i]); - VectorCopy(origin, vb[i]); - - va[i][2] = min[2]; - vb[i][2] = max[2]; - - va[i][0] += radius[0] * sinf( ( 2 * Q_PI * i / nSides ) + phase ); - va[i][1] += radius[1] * cosf( ( 2 * Q_PI * i / nSides ) + phase ); - - vb[i][0] = va[i][0]; - vb[i][1] = va[i][1]; - } - - VectorCopy(va[0], va[nSides]); - VectorCopy(vb[0], vb[nSides]); - - //---------------------------------- - - for(i = 1; i <= nSides; i++) - { - DBrush* pB = GetBoundingCube(min, max, "textures/common/caulk"); - - vec3_t top, bottom; - VectorCopy(va[i-1], top); - VectorCopy(va[i], bottom); - - if(va[i-1][1] > va[i][1]) - { - top[0] += 5; - bottom[0] += 5; - } - else // flip direction of plane on crossover - { - top[0] -= 5; - bottom[0] -= 5; - } - - if(top[1] != bottom[1]) // internal line is flat already if true - { - pB->AddFace(va[i-1], top, vb[i-1], "textures/common/caulk", FALSE); - pB->AddFace(va[i], vb[i], bottom, "textures/common/caulk", FALSE); - } // add cut-off planes - - pB->AddFace(va[i-1], vb[i-1], vb[i], GetCurrentTexture(), FALSE); - // add internal polygon plane - } -} - -void DShape::BuildBorderedPrism(vec3_t min, vec3_t max, int nSides, int nBorder, bool bAlignTop) -{ - vec3_t va[MAX_POLYGON_FACES+2], vb[MAX_POLYGON_FACES+2]; - vec3_t vc[MAX_POLYGON_FACES+2], vd[MAX_POLYGON_FACES+2]; - - vec3_t radius; - vec3_t origin; - - VectorSubtract(max, min, radius); - VectorScale(radius, 0.5f, radius); - // calc 3d radius and origin - VectorAdd(max, min, origin); - VectorScale(origin, 0.5f, origin); - - if(nBorder >= Min(radius[0], radius[1])) - { -// DoMessageBox("Border is too large", "Error", MB_OK); - return; - } - - float phase = 0.0f; - - if(bAlignTop) - { - phase = -(Q_PI/nSides); - VectorScale(radius, static_cast< float >( 1/cos(phase) ), radius); - } - - //----- Build Polygon Vertices ----- - - int i; - for(i = 0; i < nSides; i++) - { - VectorCopy(origin, va[i]); - VectorCopy(origin, vb[i]); - VectorCopy(origin, vc[i]); - VectorCopy(origin, vd[i]); - - va[i][2] = min[2]; - vb[i][2] = max[2]; - - va[i][0] += (radius[0] - nBorder) * sinf( ( 2 * Q_PI * i / nSides ) + phase ); - va[i][1] += (radius[1] - nBorder) * cosf( ( 2 * Q_PI * i / nSides ) + phase ); - - vb[i][0] = va[i][0]; - vb[i][1] = va[i][1]; - - - - vc[i][2] = min[2]; - vd[i][2] = max[2]; - - vc[i][0] += radius[0] * sinf( ( 2 * Q_PI * i / nSides ) + phase ); - vc[i][1] += radius[1] * cosf( ( 2 * Q_PI * i / nSides ) + phase ); - - vd[i][0] = vc[i][0]; - vd[i][1] = vc[i][1]; - } - - VectorCopy(va[0], va[nSides]); - VectorCopy(vb[0], vb[nSides]); - VectorCopy(va[1], va[nSides+1]); - VectorCopy(vb[1], vb[nSides+1]); - - VectorCopy(vc[0], vc[nSides]); - VectorCopy(vd[0], vd[nSides]); - VectorCopy(vc[1], vc[nSides+1]); - VectorCopy(vd[1], vd[nSides+1]); - - //---------------------------------- - - for(i = 1; i <= nSides; i++) - { - DBrush* pB = GetBoundingCube(min, max, "textures/common/caulk"); - - pB->AddFace(origin, vc[i-1], vd[i-1], "textures/common/caulk", FALSE); - pB->AddFace(origin, vd[i], vc[i], "textures/common/caulk", FALSE); - - pB->AddFace(vc[i-1], vc[i], vd[i], GetCurrentTexture(), FALSE); - pB->AddFace(vb[i], va[i], va[i-1], GetCurrentTexture(), FALSE); - } -} - -DBrush* DShape::GetBoundingCube_Ext(vec3_t min, vec3_t max, const char *textureName, bool* bUseFaces, bool detail) -{ - DBrush* pB = new DBrush; - //----- Build Outer Bounds --------- - - vec3_t v1, v2, v3, v5, v6, v7; - VectorCopy(min, v1); - VectorCopy(min, v2); - VectorCopy(min, v3); - VectorCopy(max, v5); - VectorCopy(max, v6); - VectorCopy(max, v7); - - v2[0] = max[0]; - v3[1] = max[1]; - - v6[0] = min[0]; - v7[1] = min[1]; - - //---------------------------------- - - //----- Add Six Cube Faces --------- - - if(bUseFaces[0]) - pB->AddFace(v1, v2, v3, textureName, detail); - if(bUseFaces[1]) - pB->AddFace(v1, v3, v6, textureName, detail); - if(bUseFaces[2]) - pB->AddFace(v1, v7, v2, textureName, detail); - - if(bUseFaces[3]) - pB->AddFace(v5, v6, v3, textureName, detail); - if(bUseFaces[4]) - pB->AddFace(v5, v2, v7, textureName, detail); - if(bUseFaces[5]) - pB->AddFace(v5, v7, v6, textureName, detail); - - //---------------------------------- - - return pB; -} - -DBrush* DShape::GetBoundingCube(vec3_t min, vec3_t max, const char *textureName, DEntity* ent, bool* bUseFaces) -{ - DBrush* pB; - if(ent == NULL) - pB = m_Container.GetWorldSpawn()->NewBrush(m_nNextBrush++); - else - pB = ent->NewBrush(m_nNextBrush++); - - //----- Build Outer Bounds --------- - - vec3_t v1, v2, v3, v5, v6, v7; - VectorCopy(min, v1); - VectorCopy(min, v2); - VectorCopy(min, v3); - VectorCopy(max, v5); - VectorCopy(max, v6); - VectorCopy(max, v7); - - v2[0] = max[0]; - v3[1] = max[1]; - - v6[0] = min[0]; - v7[1] = min[1]; - - //---------------------------------- - - //----- Add Six Cube Faces --------- - - if(bUseFaces[0]) - pB->AddFace(v1, v2, v3, textureName, FALSE); - if(bUseFaces[1]) - pB->AddFace(v1, v3, v6, textureName, FALSE); - if(bUseFaces[2]) - pB->AddFace(v1, v7, v2, textureName, FALSE); - - if(bUseFaces[3]) - pB->AddFace(v5, v6, v3, textureName, FALSE); - if(bUseFaces[4]) - pB->AddFace(v5, v2, v7, textureName, FALSE); - if(bUseFaces[5]) - pB->AddFace(v5, v7, v6, textureName, FALSE); - - //---------------------------------- - - return pB; -} - -bool DShape::BuildPit(vec3_t min, vec3_t max) -{ - if((max[2] - min[2]) < 196) - return FALSE; - - srand(time(NULL)); - - vec3_t centre; - VectorAdd(min, max, centre); - VectorScale(centre, 0.5f, centre); - - char buffer[256]; - - int team = (rand()%10000)+5000; - -// ************* SPEAKER *************** - sprintf(buffer, "t%i_1", team); - -// trigger for speaker - vec3_t triggerVoiceBtm; - VectorCopy(min, triggerVoiceBtm); - triggerVoiceBtm[2] = max[2] - 16; - - DEntity* triggerVoice = m_Container.AddEntity("trigger_multiple"); - GetBoundingCube(triggerVoiceBtm, max, "textures/common/trigger", triggerVoice); - triggerVoice->AddEPair("target", buffer); -//-------------------- - -// target for speaker - vec3_t voiceOrigin; - VectorCopy(centre, voiceOrigin); - voiceOrigin[2] = max[2]+16; - - - DEntity* targetVoice = m_Container.AddEntity("target_speaker"); - targetVoice->AddEPair("targetname", buffer); - - sprintf(buffer, "%f %f %f", voiceOrigin[0], voiceOrigin[1], voiceOrigin[2]); - targetVoice->AddEPair("origin", buffer); - targetVoice->AddEPair("spawnflags", "8"); - targetVoice->AddEPair("noise", "*falling1.wav"); -//-------------------- - -// *********** END SPEAKER ************* - -// ********* POWERUP REMOVAL *********** - sprintf(buffer, "t%i_2", team); - -// trigger for powerup removal - vec3_t triggerPwrRmvTop, triggerPwrRmvBtm; - VectorCopy(min, triggerPwrRmvBtm); - VectorCopy(max, triggerPwrRmvTop); - - triggerPwrRmvTop[2] = triggerVoiceBtm[2] - 64; - triggerPwrRmvBtm[2] = triggerPwrRmvTop[2] - 16; - - DEntity* triggerPwrRmv = m_Container.AddEntity("trigger_multiple"); - GetBoundingCube(triggerPwrRmvBtm, triggerPwrRmvTop, "textures/common/trigger", triggerPwrRmv); - triggerPwrRmv->AddEPair("target", buffer); -//-------------------- - -// target for powerup removal - vec3_t pwrRmvOrigin; - VectorCopy(centre, pwrRmvOrigin); - pwrRmvOrigin[2] = triggerPwrRmvTop[2]+16; - - DEntity* targetPwrRmv = m_Container.AddEntity("target_remove_powerups"); - targetPwrRmv->AddEPair("targetname", buffer); - - sprintf(buffer, "%f %f %f", pwrRmvOrigin[0], pwrRmvOrigin[1], pwrRmvOrigin[2]); - targetPwrRmv->AddEPair("origin", buffer); -//-------------------- - -// ****** END POWERUP REMOVAL ******** - -// ********* DAMAGE *********** - -// trigger for damage - vec3_t triggerDmgTop, triggerDmgBtm; - VectorCopy(min, triggerDmgBtm); - VectorCopy(max, triggerDmgTop); - - triggerDmgBtm[2] = min[2] + 64; - triggerDmgTop[2] = triggerDmgBtm[2] + 16; - - DEntity* triggerDmg = m_Container.AddEntity("trigger_hurt"); - GetBoundingCube(triggerDmgBtm, triggerDmgTop, "textures/common/trigger", triggerDmg); - triggerDmg->AddEPair("dmg", "9999"); - triggerDmg->AddEPair("spawnflags", "12"); -//-------------------- - -// ****** END DAMAGE ******** - -// ********* NODROP *********** - - vec3_t nodropTop; - VectorCopy(max, nodropTop); - - nodropTop[2] = min[2] + 64; - - GetBoundingCube(min, nodropTop, "textures/common/nodrop"); - -// ****** END NODROP ******** - - return TRUE; -} +/* +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 +*/ + +// DShape.cpp: implementation of the DShape class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DShape.h" + +//#include "dialogs-gtk.h" + +#include "misc.h" +#include "shapes.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +bool bFacesAll[6] = {TRUE, TRUE, TRUE, TRUE, TRUE, TRUE}; + +DShape::DShape() +{ + m_nNextBrush = 0; +} + +DShape::~DShape() +{ + +} + +void DShape::BuildRegularPrism(vec3_t min, vec3_t max, int nSides, bool bAlignTop) +{ + vec3_t vc[MAX_POLYGON_FACES+2], vd[MAX_POLYGON_FACES+2]; + + vec3_t radius; + vec3_t origin; + + VectorSubtract(max, min, radius); + VectorScale(radius, 0.5f, radius); + // calc 3d radius and origin + VectorAdd(max, min, origin); + VectorScale(origin, 0.5f, origin); + + float phase = 0.0f; + + if(bAlignTop) + { + phase = -(Q_PI/nSides); + VectorScale(radius, static_cast< float >( 1/cos(phase) ), radius); + } + + //----- Build Polygon Vertices ----- + + int i; + for(i = 0; i < nSides; i++) + { + VectorCopy(origin, vc[i]); + VectorCopy(origin, vd[i]); + + vc[i][2] = min[2]; + vd[i][2] = max[2]; + + vc[i][0] += radius[0] * sinf( ( 2 * Q_PI * i / nSides ) + phase ); + vc[i][1] += radius[1] * cosf( ( 2 * Q_PI * i / nSides ) + phase ); + + vd[i][0] = vc[i][0]; + vd[i][1] = vc[i][1]; + } + + VectorCopy(vc[0], vc[nSides]); + VectorCopy(vd[0], vd[nSides]); + VectorCopy(vc[1], vc[nSides+1]); + VectorCopy(vd[1], vd[nSides+1]); + + //---------------------------------- + + DBrush* pB = m_Container.GetWorldSpawn()->NewBrush(m_nNextBrush++); + + for(i = 1; i <= nSides; i++) + pB->AddFace(vc[i-1], vc[i], vd[i], GetCurrentTexture(), FALSE); + + pB->AddFace(vc[2], vc[1], vc[0], "textures/common/caulk", FALSE); + pB->AddFace(vd[0], vd[1], vd[2], "textures/common/caulk", FALSE); +} + +void DShape::Commit() +{ + m_Container.GetWorldSpawn()->FixBrushes(FALSE); + m_Container.BuildInRadiant(TRUE); +} + +void DShape::BuildInversePrism(vec3_t min, vec3_t max, int nSides, bool bAlignTop) +{ + vec3_t va[MAX_POLYGON_FACES+1], vb[MAX_POLYGON_FACES+1]; + vec3_t radius; + vec3_t origin; + + VectorSubtract(max, min, radius); + VectorScale(radius, 0.5f, radius); + // calc 3d radius and origin + VectorAdd(max, min, origin); + VectorScale(origin, 0.5f, origin); + + float phase = 0.0f; + + if(bAlignTop) + { + phase = -(Q_PI/nSides); + VectorScale(radius, static_cast< float >( 1/cos(phase) ), radius); + } + + //----- Build Polygon Vertices ----- + + int i; + for(i = 0; i < nSides; i++) + { + VectorCopy(origin, va[i]); + VectorCopy(origin, vb[i]); + + va[i][2] = min[2]; + vb[i][2] = max[2]; + + va[i][0] += radius[0] * sinf( ( 2 * Q_PI * i / nSides ) + phase ); + va[i][1] += radius[1] * cosf( ( 2 * Q_PI * i / nSides ) + phase ); + + vb[i][0] = va[i][0]; + vb[i][1] = va[i][1]; + } + + VectorCopy(va[0], va[nSides]); + VectorCopy(vb[0], vb[nSides]); + + //---------------------------------- + + for(i = 1; i <= nSides; i++) + { + DBrush* pB = GetBoundingCube(min, max, "textures/common/caulk"); + + vec3_t top, bottom; + VectorCopy(va[i-1], top); + VectorCopy(va[i], bottom); + + if(va[i-1][1] > va[i][1]) + { + top[0] += 5; + bottom[0] += 5; + } + else // flip direction of plane on crossover + { + top[0] -= 5; + bottom[0] -= 5; + } + + if(top[1] != bottom[1]) // internal line is flat already if true + { + pB->AddFace(va[i-1], top, vb[i-1], "textures/common/caulk", FALSE); + pB->AddFace(va[i], vb[i], bottom, "textures/common/caulk", FALSE); + } // add cut-off planes + + pB->AddFace(va[i-1], vb[i-1], vb[i], GetCurrentTexture(), FALSE); + // add internal polygon plane + } +} + +void DShape::BuildBorderedPrism(vec3_t min, vec3_t max, int nSides, int nBorder, bool bAlignTop) +{ + vec3_t va[MAX_POLYGON_FACES+2], vb[MAX_POLYGON_FACES+2]; + vec3_t vc[MAX_POLYGON_FACES+2], vd[MAX_POLYGON_FACES+2]; + + vec3_t radius; + vec3_t origin; + + VectorSubtract(max, min, radius); + VectorScale(radius, 0.5f, radius); + // calc 3d radius and origin + VectorAdd(max, min, origin); + VectorScale(origin, 0.5f, origin); + + if(nBorder >= Min(radius[0], radius[1])) + { +// DoMessageBox("Border is too large", "Error", MB_OK); + return; + } + + float phase = 0.0f; + + if(bAlignTop) + { + phase = -(Q_PI/nSides); + VectorScale(radius, static_cast< float >( 1/cos(phase) ), radius); + } + + //----- Build Polygon Vertices ----- + + int i; + for(i = 0; i < nSides; i++) + { + VectorCopy(origin, va[i]); + VectorCopy(origin, vb[i]); + VectorCopy(origin, vc[i]); + VectorCopy(origin, vd[i]); + + va[i][2] = min[2]; + vb[i][2] = max[2]; + + va[i][0] += (radius[0] - nBorder) * sinf( ( 2 * Q_PI * i / nSides ) + phase ); + va[i][1] += (radius[1] - nBorder) * cosf( ( 2 * Q_PI * i / nSides ) + phase ); + + vb[i][0] = va[i][0]; + vb[i][1] = va[i][1]; + + + + vc[i][2] = min[2]; + vd[i][2] = max[2]; + + vc[i][0] += radius[0] * sinf( ( 2 * Q_PI * i / nSides ) + phase ); + vc[i][1] += radius[1] * cosf( ( 2 * Q_PI * i / nSides ) + phase ); + + vd[i][0] = vc[i][0]; + vd[i][1] = vc[i][1]; + } + + VectorCopy(va[0], va[nSides]); + VectorCopy(vb[0], vb[nSides]); + VectorCopy(va[1], va[nSides+1]); + VectorCopy(vb[1], vb[nSides+1]); + + VectorCopy(vc[0], vc[nSides]); + VectorCopy(vd[0], vd[nSides]); + VectorCopy(vc[1], vc[nSides+1]); + VectorCopy(vd[1], vd[nSides+1]); + + //---------------------------------- + + for(i = 1; i <= nSides; i++) + { + DBrush* pB = GetBoundingCube(min, max, "textures/common/caulk"); + + pB->AddFace(origin, vc[i-1], vd[i-1], "textures/common/caulk", FALSE); + pB->AddFace(origin, vd[i], vc[i], "textures/common/caulk", FALSE); + + pB->AddFace(vc[i-1], vc[i], vd[i], GetCurrentTexture(), FALSE); + pB->AddFace(vb[i], va[i], va[i-1], GetCurrentTexture(), FALSE); + } +} + +DBrush* DShape::GetBoundingCube_Ext(vec3_t min, vec3_t max, const char *textureName, bool* bUseFaces, bool detail) +{ + DBrush* pB = new DBrush; + //----- Build Outer Bounds --------- + + vec3_t v1, v2, v3, v5, v6, v7; + VectorCopy(min, v1); + VectorCopy(min, v2); + VectorCopy(min, v3); + VectorCopy(max, v5); + VectorCopy(max, v6); + VectorCopy(max, v7); + + v2[0] = max[0]; + v3[1] = max[1]; + + v6[0] = min[0]; + v7[1] = min[1]; + + //---------------------------------- + + //----- Add Six Cube Faces --------- + + if(bUseFaces[0]) + pB->AddFace(v1, v2, v3, textureName, detail); + if(bUseFaces[1]) + pB->AddFace(v1, v3, v6, textureName, detail); + if(bUseFaces[2]) + pB->AddFace(v1, v7, v2, textureName, detail); + + if(bUseFaces[3]) + pB->AddFace(v5, v6, v3, textureName, detail); + if(bUseFaces[4]) + pB->AddFace(v5, v2, v7, textureName, detail); + if(bUseFaces[5]) + pB->AddFace(v5, v7, v6, textureName, detail); + + //---------------------------------- + + return pB; +} + +DBrush* DShape::GetBoundingCube(vec3_t min, vec3_t max, const char *textureName, DEntity* ent, bool* bUseFaces) +{ + DBrush* pB; + if(ent == NULL) + pB = m_Container.GetWorldSpawn()->NewBrush(m_nNextBrush++); + else + pB = ent->NewBrush(m_nNextBrush++); + + //----- Build Outer Bounds --------- + + vec3_t v1, v2, v3, v5, v6, v7; + VectorCopy(min, v1); + VectorCopy(min, v2); + VectorCopy(min, v3); + VectorCopy(max, v5); + VectorCopy(max, v6); + VectorCopy(max, v7); + + v2[0] = max[0]; + v3[1] = max[1]; + + v6[0] = min[0]; + v7[1] = min[1]; + + //---------------------------------- + + //----- Add Six Cube Faces --------- + + if(bUseFaces[0]) + pB->AddFace(v1, v2, v3, textureName, FALSE); + if(bUseFaces[1]) + pB->AddFace(v1, v3, v6, textureName, FALSE); + if(bUseFaces[2]) + pB->AddFace(v1, v7, v2, textureName, FALSE); + + if(bUseFaces[3]) + pB->AddFace(v5, v6, v3, textureName, FALSE); + if(bUseFaces[4]) + pB->AddFace(v5, v2, v7, textureName, FALSE); + if(bUseFaces[5]) + pB->AddFace(v5, v7, v6, textureName, FALSE); + + //---------------------------------- + + return pB; +} + +bool DShape::BuildPit(vec3_t min, vec3_t max) +{ + if((max[2] - min[2]) < 196) + return FALSE; + + srand(time(NULL)); + + vec3_t centre; + VectorAdd(min, max, centre); + VectorScale(centre, 0.5f, centre); + + char buffer[256]; + + int team = (rand()%10000)+5000; + +// ************* SPEAKER *************** + sprintf(buffer, "t%i_1", team); + +// trigger for speaker + vec3_t triggerVoiceBtm; + VectorCopy(min, triggerVoiceBtm); + triggerVoiceBtm[2] = max[2] - 16; + + DEntity* triggerVoice = m_Container.AddEntity("trigger_multiple"); + GetBoundingCube(triggerVoiceBtm, max, "textures/common/trigger", triggerVoice); + triggerVoice->AddEPair("target", buffer); +//-------------------- + +// target for speaker + vec3_t voiceOrigin; + VectorCopy(centre, voiceOrigin); + voiceOrigin[2] = max[2]+16; + + + DEntity* targetVoice = m_Container.AddEntity("target_speaker"); + targetVoice->AddEPair("targetname", buffer); + + sprintf(buffer, "%f %f %f", voiceOrigin[0], voiceOrigin[1], voiceOrigin[2]); + targetVoice->AddEPair("origin", buffer); + targetVoice->AddEPair("spawnflags", "8"); + targetVoice->AddEPair("noise", "*falling1.wav"); +//-------------------- + +// *********** END SPEAKER ************* + +// ********* POWERUP REMOVAL *********** + sprintf(buffer, "t%i_2", team); + +// trigger for powerup removal + vec3_t triggerPwrRmvTop, triggerPwrRmvBtm; + VectorCopy(min, triggerPwrRmvBtm); + VectorCopy(max, triggerPwrRmvTop); + + triggerPwrRmvTop[2] = triggerVoiceBtm[2] - 64; + triggerPwrRmvBtm[2] = triggerPwrRmvTop[2] - 16; + + DEntity* triggerPwrRmv = m_Container.AddEntity("trigger_multiple"); + GetBoundingCube(triggerPwrRmvBtm, triggerPwrRmvTop, "textures/common/trigger", triggerPwrRmv); + triggerPwrRmv->AddEPair("target", buffer); +//-------------------- + +// target for powerup removal + vec3_t pwrRmvOrigin; + VectorCopy(centre, pwrRmvOrigin); + pwrRmvOrigin[2] = triggerPwrRmvTop[2]+16; + + DEntity* targetPwrRmv = m_Container.AddEntity("target_remove_powerups"); + targetPwrRmv->AddEPair("targetname", buffer); + + sprintf(buffer, "%f %f %f", pwrRmvOrigin[0], pwrRmvOrigin[1], pwrRmvOrigin[2]); + targetPwrRmv->AddEPair("origin", buffer); +//-------------------- + +// ****** END POWERUP REMOVAL ******** + +// ********* DAMAGE *********** + +// trigger for damage + vec3_t triggerDmgTop, triggerDmgBtm; + VectorCopy(min, triggerDmgBtm); + VectorCopy(max, triggerDmgTop); + + triggerDmgBtm[2] = min[2] + 64; + triggerDmgTop[2] = triggerDmgBtm[2] + 16; + + DEntity* triggerDmg = m_Container.AddEntity("trigger_hurt"); + GetBoundingCube(triggerDmgBtm, triggerDmgTop, "textures/common/trigger", triggerDmg); + triggerDmg->AddEPair("dmg", "9999"); + triggerDmg->AddEPair("spawnflags", "12"); +//-------------------- + +// ****** END DAMAGE ******** + +// ********* NODROP *********** + + vec3_t nodropTop; + VectorCopy(max, nodropTop); + + nodropTop[2] = min[2] + 64; + + GetBoundingCube(min, nodropTop, "textures/common/nodrop"); + +// ****** END NODROP ******** + + return TRUE; +} diff --git a/contrib/bobtoolz/DTrainDrawer.cpp b/contrib/bobtoolz/DTrainDrawer.cpp index 83ddc3ec..f5796c80 100644 --- a/contrib/bobtoolz/DTrainDrawer.cpp +++ b/contrib/bobtoolz/DTrainDrawer.cpp @@ -1,358 +1,358 @@ -/* -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 -*/ - -#include "StdAfx.h" -#include "DPoint.h" - -#include "DTrainDrawer.h" -#include "DEPair.h" - -#include "misc.h" -#include "funchandlers.h" - -#include "dialogs/dialogs-gtk.h" - -DTrainDrawer::DTrainDrawer() { - refCount = 1; - m_bHooked = FALSE; - m_bDisplay = FALSE; - - BuildPaths(); -} - -DTrainDrawer::~DTrainDrawer(void) { - if(m_bHooked) - UnRegister(); - - ClearPoints(); - ClearSplines(); -} - -void DTrainDrawer::ClearSplines() { - for(list::const_iterator deadSpline = m_splineList.begin(); deadSpline != m_splineList.end(); deadSpline++) { - (*deadSpline)->m_pointList.clear(); - (*deadSpline)->m_vertexList.clear(); - delete (*deadSpline); - } - - m_splineList.clear(); -} - -void DTrainDrawer::ClearPoints() { - for(list::const_iterator deadPoint = m_pointList.begin(); deadPoint != m_pointList.end(); deadPoint++) { - delete *deadPoint; - } - - m_pointList.clear(); -} - -void DTrainDrawer::Register() { - g_QglTable.m_pfnHookGL2DWindow( this ); - g_QglTable.m_pfnHookGL3DWindow( this ); - m_bHooked = TRUE; -} - -void DTrainDrawer::UnRegister() { - g_QglTable.m_pfnUnHookGL2DWindow( this ); - g_QglTable.m_pfnUnHookGL3DWindow( this ); - m_bHooked = FALSE; -} - -void CalculateSpline_r(vec3_t* v, int count, vec3_t out, float tension) { - vec3_t dist; - - if(count < 2) { - return; - } - - if(count == 2) { - VectorSubtract( v[1], v[0], dist ); - VectorMA(v[0], tension, dist, out); - return; - } - - vec3_t* v2 = new vec3_t[count-1]; - - for( int i = 0; i < count-1; i++ ) { - VectorSubtract( v[i+1], v[i], dist ); - VectorMA(v[i], tension, dist, v2[i]); - } - - CalculateSpline_r( v2, count-1, out, tension); - - delete[] v2; -} - -void DTrainDrawer::Draw3D() { - - if(!m_bDisplay) { - return; - } - - g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); - - g_QglTable.m_pfn_qglDisable(GL_BLEND); - g_QglTable.m_pfn_qglDisable(GL_LINE_SMOOTH); - - g_QglTable.m_pfn_qglPushMatrix(); - - g_QglTable.m_pfn_qglLineWidth(2.0f); - g_QglTable.m_pfn_qglColor4f(1.0f, 1.0f, 1.0f, 1.0f); - - g_QglTable.m_pfn_qglEnable(GL_BLEND); - g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - g_QglTable.m_pfn_qglDisable(GL_POLYGON_SMOOTH); - - g_QglTable.m_pfn_qglDepthFunc(GL_ALWAYS); - - for(list::const_iterator sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { - splinePoint_t* pSP = (*sp); - - g_QglTable.m_pfn_qglBegin(GL_LINE_STRIP); - for(list::const_iterator v = pSP->m_vertexList.begin(); v != pSP->m_vertexList.end(); v++) { - g_QglTable.m_pfn_qglVertex3fv((*v)._pnt); - } - g_QglTable.m_pfn_qglEnd(); - - } - - g_QglTable.m_pfn_qglPopMatrix(); - g_QglTable.m_pfn_qglPopAttrib(); -} - -void DTrainDrawer::Draw2D(VIEWTYPE vt) { - - if(!m_bDisplay) { - return; - } - - g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); - - g_QglTable.m_pfn_qglDisable(GL_BLEND); - g_QglTable.m_pfn_qglDisable(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, 0.5f); - - g_QglTable.m_pfn_qglEnable(GL_BLEND); - g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - g_QglTable.m_pfn_qglDisable(GL_POLYGON_SMOOTH); - - g_QglTable.m_pfn_qglDepthFunc(GL_ALWAYS); - - g_QglTable.m_pfn_qglColor4f(1.f, 0.f, 0.f, 1.f); - - for(list::const_iterator sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { - splinePoint_t* pSP = (*sp); - - g_QglTable.m_pfn_qglBegin(GL_LINE_STRIP); - for(list::const_iterator v = pSP->m_vertexList.begin(); v != pSP->m_vertexList.end(); v++) { - g_QglTable.m_pfn_qglVertex3fv((*v)._pnt); - } - g_QglTable.m_pfn_qglEnd(); - - } - - g_QglTable.m_pfn_qglPopMatrix(); - g_QglTable.m_pfn_qglPopAttrib(); -} - -void AddSplineControl(const char* control, splinePoint_t* pSP) { - controlPoint_t cp; - strncpy(cp.strName, control, 64); - - pSP->m_pointList.push_front(cp); -} - -void DTrainDrawer::BuildPaths() { - int count = g_FuncTable.m_pfnGetEntityCount(); - - DEntity e; - - for(int i = 0; i < count; i++) { - entity_s* ent = (entity_s*)g_FuncTable.m_pfnGetEntityHandle(i); - e.ClearEPairs(); - e.LoadEPairList(*g_EntityTable.m_pfnGetEntityKeyValList(ent)); - - const char* classname = e.m_Classname.GetBuffer(); - const char* target; - const char* control; - const char* targetname; - vec3_t vOrigin; - - e.SpawnString("targetname", NULL, &targetname); - e.SpawnVector("origin", "0 0 0", vOrigin); - - if(!strcmp(classname, "info_train_spline_main")) { - if(!targetname) { - Sys_Printf( "info_train_spline_main with no targetname" ); - return; - } - - e.SpawnString("target", NULL, &target); - - if(!target) { - AddControlPoint( targetname, vOrigin ); - } else { - splinePoint_t* pSP = AddSplinePoint( targetname, target, vOrigin ); - - e.SpawnString("control", NULL, &control); - - if(control) { - AddSplineControl( control, pSP ); - - for(int j = 2;; j++) { - char buffer[16]; - sprintf(buffer, "control%i", j); - - e.SpawnString(buffer, NULL, &control); - if(!control) { - break; - } - - AddSplineControl( control, pSP ); - } - } - } - } else if(!strcmp(classname, "info_train_spline_control")) { - if(!targetname) { - Sys_Printf( "info_train_spline_control with no targetname" ); - return; - } - - AddControlPoint( targetname, vOrigin ); - } - } - - list::const_iterator sp; - for(sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { - splinePoint_t* pSP = (*sp); - - controlPoint_t* pTarget = FindControlPoint( pSP->strTarget ); - - if(!pTarget) { - Sys_Printf( "couldn't find target %s", pSP->strTarget ); - return; -// continue; - } - - pSP->pTarget = pTarget; - - - for(list::iterator cp = pSP->m_pointList.begin(); cp != pSP->m_pointList.end(); cp++) { - controlPoint_t* pControl = FindControlPoint( (*cp).strName ); - if(!pControl) { - Sys_Printf( "couldn't find control %s", (*cp).strName ); - return; - } - - VectorCopy(pControl->vOrigin, (*cp).vOrigin); - } - } - - m_bDisplay = TRUE; - Register(); - - for(sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { - splinePoint_t* pSP = (*sp); - DPoint out; - - if(!pSP->pTarget) { - continue; - } - - int count = pSP->m_pointList.size() + 2; - vec3_t* v = new vec3_t[count]; - - VectorCopy(pSP->point.vOrigin, v[0]); - - int i = 1; - for(list::reverse_iterator cp = pSP->m_pointList.rbegin(); cp != pSP->m_pointList.rend(); cp++) { - VectorCopy((*cp).vOrigin, v[i]); - i++; - } - VectorCopy(pSP->pTarget->vOrigin, v[i]); - - for (float tension = 0.0f; tension <= 1.f; tension += 0.01f) { - CalculateSpline_r(v, count, out._pnt, tension); - pSP->m_vertexList.push_front(out); - } - - delete[] v; - - VectorCopy(pSP->pTarget->vOrigin, out._pnt); - pSP->m_vertexList.push_front(out); - } - - -} - -void DTrainDrawer::AddControlPoint(const char* name, vec_t* origin) -{ - controlPoint_t* pCP = new controlPoint_t; - - strncpy(pCP->strName, name, 64); - VectorCopy( origin, pCP->vOrigin ); - - m_pointList.push_back( pCP ); -} - -splinePoint_t* DTrainDrawer::AddSplinePoint(const char* name, const char* target, vec_t* origin) -{ - splinePoint_t* pSP = new splinePoint_t; - - strncpy(pSP->point.strName, name, 64); - strncpy(pSP->strTarget, target, 64); - VectorCopy( origin, pSP->point.vOrigin ); - m_splineList.push_back( pSP ); - - return pSP; -} - -controlPoint_t* DTrainDrawer::FindControlPoint(const char* name) -{ - for(list::const_iterator cp = m_pointList.begin(); cp != m_pointList.end(); cp++) { - if(!strcmp(name, (*cp)->strName)) { - return (*cp); - } - } - - for(list::const_iterator sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { - if(!strcmp(name, (*sp)->point.strName)) { - return &((*sp)->point); - } - } - - return NULL; -} +/* +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 +*/ + +#include "StdAfx.h" +#include "DPoint.h" + +#include "DTrainDrawer.h" +#include "DEPair.h" + +#include "misc.h" +#include "funchandlers.h" + +#include "dialogs/dialogs-gtk.h" + +DTrainDrawer::DTrainDrawer() { + refCount = 1; + m_bHooked = FALSE; + m_bDisplay = FALSE; + + BuildPaths(); +} + +DTrainDrawer::~DTrainDrawer(void) { + if(m_bHooked) + UnRegister(); + + ClearPoints(); + ClearSplines(); +} + +void DTrainDrawer::ClearSplines() { + for(list::const_iterator deadSpline = m_splineList.begin(); deadSpline != m_splineList.end(); deadSpline++) { + (*deadSpline)->m_pointList.clear(); + (*deadSpline)->m_vertexList.clear(); + delete (*deadSpline); + } + + m_splineList.clear(); +} + +void DTrainDrawer::ClearPoints() { + for(list::const_iterator deadPoint = m_pointList.begin(); deadPoint != m_pointList.end(); deadPoint++) { + delete *deadPoint; + } + + m_pointList.clear(); +} + +void DTrainDrawer::Register() { + g_QglTable.m_pfnHookGL2DWindow( this ); + g_QglTable.m_pfnHookGL3DWindow( this ); + m_bHooked = TRUE; +} + +void DTrainDrawer::UnRegister() { + g_QglTable.m_pfnUnHookGL2DWindow( this ); + g_QglTable.m_pfnUnHookGL3DWindow( this ); + m_bHooked = FALSE; +} + +void CalculateSpline_r(vec3_t* v, int count, vec3_t out, float tension) { + vec3_t dist; + + if(count < 2) { + return; + } + + if(count == 2) { + VectorSubtract( v[1], v[0], dist ); + VectorMA(v[0], tension, dist, out); + return; + } + + vec3_t* v2 = new vec3_t[count-1]; + + for( int i = 0; i < count-1; i++ ) { + VectorSubtract( v[i+1], v[i], dist ); + VectorMA(v[i], tension, dist, v2[i]); + } + + CalculateSpline_r( v2, count-1, out, tension); + + delete[] v2; +} + +void DTrainDrawer::Draw3D() { + + if(!m_bDisplay) { + return; + } + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + g_QglTable.m_pfn_qglDisable(GL_BLEND); + g_QglTable.m_pfn_qglDisable(GL_LINE_SMOOTH); + + g_QglTable.m_pfn_qglPushMatrix(); + + g_QglTable.m_pfn_qglLineWidth(2.0f); + g_QglTable.m_pfn_qglColor4f(1.0f, 1.0f, 1.0f, 1.0f); + + g_QglTable.m_pfn_qglEnable(GL_BLEND); + g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + g_QglTable.m_pfn_qglDisable(GL_POLYGON_SMOOTH); + + g_QglTable.m_pfn_qglDepthFunc(GL_ALWAYS); + + for(list::const_iterator sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { + splinePoint_t* pSP = (*sp); + + g_QglTable.m_pfn_qglBegin(GL_LINE_STRIP); + for(list::const_iterator v = pSP->m_vertexList.begin(); v != pSP->m_vertexList.end(); v++) { + g_QglTable.m_pfn_qglVertex3fv((*v)._pnt); + } + g_QglTable.m_pfn_qglEnd(); + + } + + g_QglTable.m_pfn_qglPopMatrix(); + g_QglTable.m_pfn_qglPopAttrib(); +} + +void DTrainDrawer::Draw2D(VIEWTYPE vt) { + + if(!m_bDisplay) { + return; + } + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + g_QglTable.m_pfn_qglDisable(GL_BLEND); + g_QglTable.m_pfn_qglDisable(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, 0.5f); + + g_QglTable.m_pfn_qglEnable(GL_BLEND); + g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + g_QglTable.m_pfn_qglDisable(GL_POLYGON_SMOOTH); + + g_QglTable.m_pfn_qglDepthFunc(GL_ALWAYS); + + g_QglTable.m_pfn_qglColor4f(1.f, 0.f, 0.f, 1.f); + + for(list::const_iterator sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { + splinePoint_t* pSP = (*sp); + + g_QglTable.m_pfn_qglBegin(GL_LINE_STRIP); + for(list::const_iterator v = pSP->m_vertexList.begin(); v != pSP->m_vertexList.end(); v++) { + g_QglTable.m_pfn_qglVertex3fv((*v)._pnt); + } + g_QglTable.m_pfn_qglEnd(); + + } + + g_QglTable.m_pfn_qglPopMatrix(); + g_QglTable.m_pfn_qglPopAttrib(); +} + +void AddSplineControl(const char* control, splinePoint_t* pSP) { + controlPoint_t cp; + strncpy(cp.strName, control, 64); + + pSP->m_pointList.push_front(cp); +} + +void DTrainDrawer::BuildPaths() { + int count = g_FuncTable.m_pfnGetEntityCount(); + + DEntity e; + + for(int i = 0; i < count; i++) { + entity_s* ent = (entity_s*)g_FuncTable.m_pfnGetEntityHandle(i); + e.ClearEPairs(); + e.LoadEPairList(*g_EntityTable.m_pfnGetEntityKeyValList(ent)); + + const char* classname = e.m_Classname.GetBuffer(); + const char* target; + const char* control; + const char* targetname; + vec3_t vOrigin; + + e.SpawnString("targetname", NULL, &targetname); + e.SpawnVector("origin", "0 0 0", vOrigin); + + if(!strcmp(classname, "info_train_spline_main")) { + if(!targetname) { + Sys_Printf( "info_train_spline_main with no targetname" ); + return; + } + + e.SpawnString("target", NULL, &target); + + if(!target) { + AddControlPoint( targetname, vOrigin ); + } else { + splinePoint_t* pSP = AddSplinePoint( targetname, target, vOrigin ); + + e.SpawnString("control", NULL, &control); + + if(control) { + AddSplineControl( control, pSP ); + + for(int j = 2;; j++) { + char buffer[16]; + sprintf(buffer, "control%i", j); + + e.SpawnString(buffer, NULL, &control); + if(!control) { + break; + } + + AddSplineControl( control, pSP ); + } + } + } + } else if(!strcmp(classname, "info_train_spline_control")) { + if(!targetname) { + Sys_Printf( "info_train_spline_control with no targetname" ); + return; + } + + AddControlPoint( targetname, vOrigin ); + } + } + + list::const_iterator sp; + for(sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { + splinePoint_t* pSP = (*sp); + + controlPoint_t* pTarget = FindControlPoint( pSP->strTarget ); + + if(!pTarget) { + Sys_Printf( "couldn't find target %s", pSP->strTarget ); + return; +// continue; + } + + pSP->pTarget = pTarget; + + + for(list::iterator cp = pSP->m_pointList.begin(); cp != pSP->m_pointList.end(); cp++) { + controlPoint_t* pControl = FindControlPoint( (*cp).strName ); + if(!pControl) { + Sys_Printf( "couldn't find control %s", (*cp).strName ); + return; + } + + VectorCopy(pControl->vOrigin, (*cp).vOrigin); + } + } + + m_bDisplay = TRUE; + Register(); + + for(sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { + splinePoint_t* pSP = (*sp); + DPoint out; + + if(!pSP->pTarget) { + continue; + } + + int count = pSP->m_pointList.size() + 2; + vec3_t* v = new vec3_t[count]; + + VectorCopy(pSP->point.vOrigin, v[0]); + + int i = 1; + for(list::reverse_iterator cp = pSP->m_pointList.rbegin(); cp != pSP->m_pointList.rend(); cp++) { + VectorCopy((*cp).vOrigin, v[i]); + i++; + } + VectorCopy(pSP->pTarget->vOrigin, v[i]); + + for (float tension = 0.0f; tension <= 1.f; tension += 0.01f) { + CalculateSpline_r(v, count, out._pnt, tension); + pSP->m_vertexList.push_front(out); + } + + delete[] v; + + VectorCopy(pSP->pTarget->vOrigin, out._pnt); + pSP->m_vertexList.push_front(out); + } + + +} + +void DTrainDrawer::AddControlPoint(const char* name, vec_t* origin) +{ + controlPoint_t* pCP = new controlPoint_t; + + strncpy(pCP->strName, name, 64); + VectorCopy( origin, pCP->vOrigin ); + + m_pointList.push_back( pCP ); +} + +splinePoint_t* DTrainDrawer::AddSplinePoint(const char* name, const char* target, vec_t* origin) +{ + splinePoint_t* pSP = new splinePoint_t; + + strncpy(pSP->point.strName, name, 64); + strncpy(pSP->strTarget, target, 64); + VectorCopy( origin, pSP->point.vOrigin ); + m_splineList.push_back( pSP ); + + return pSP; +} + +controlPoint_t* DTrainDrawer::FindControlPoint(const char* name) +{ + for(list::const_iterator cp = m_pointList.begin(); cp != m_pointList.end(); cp++) { + if(!strcmp(name, (*cp)->strName)) { + return (*cp); + } + } + + for(list::const_iterator sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { + if(!strcmp(name, (*sp)->point.strName)) { + return &((*sp)->point); + } + } + + return NULL; +} diff --git a/contrib/bobtoolz/DTreePlanter.cpp b/contrib/bobtoolz/DTreePlanter.cpp index 8655b36a..985987df 100644 --- a/contrib/bobtoolz/DTreePlanter.cpp +++ b/contrib/bobtoolz/DTreePlanter.cpp @@ -1,287 +1,287 @@ -/* -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 -*/ - -#include "StdAfx.h" -#include "DTreePlanter.h" -#include "funchandlers.h" - -bool DTreePlanter::OnMouseMove(guint32 nFlags, gdouble x, gdouble y) { - return false; -} - -bool DTreePlanter::OnLButtonDown(guint32 nFlags, gdouble x, gdouble y) { - VIEWTYPE vt = m_XYWrapper->GetViewType(); - - switch(vt) { - case XY: - break; - case YZ: - case XZ: - default: - return false; - } - - vec3_t pt, vhit; - - m_XYWrapper->SnapToGrid( static_cast< int >( x ), static_cast< int >( y ), pt ); - - if(FindDropPoint(pt, vhit)) { - vhit[2] += m_offset; - - char buffer[128]; - DEntity e(m_entType); - - sprintf(buffer, "%i %i %i", (int)vhit[0], (int)vhit[1], (int)vhit[2]); - e.AddEPair("origin", buffer); - - if(m_autoLink) { - entity_t* pLastEntity = NULL; - entity_t* pThisEntity = NULL; - - int entNum = -1, lastEntNum = -1, entpos; - for(int i = 0; i < 256; i++) { - sprintf(buffer, m_linkName, i); - pThisEntity = FindEntityFromTargetname( buffer, &entNum ); - - if(pThisEntity) { - entpos = i; - lastEntNum = entNum; - pLastEntity = pThisEntity; - } - } - - if(!pLastEntity) { - sprintf(buffer, m_linkName, 0); - } else { - sprintf(buffer, m_linkName, entpos + 1); - } - - e.AddEPair( "targetname", buffer ); - - if(pLastEntity) { - DEntity e2; - e2.LoadFromEntity(lastEntNum, TRUE); - e2.AddEPair("target", buffer); - e2.RemoveFromRadiant(); - e2.BuildInRadiant(FALSE); - } - } - - if(m_setAngles) { - int angleYaw = (rand() % (m_maxYaw - m_minYaw + 1)) + m_minYaw; - int anglePitch = (rand() % (m_maxPitch - m_minPitch + 1)) + m_minPitch; - - sprintf(buffer, "%i %i 0", anglePitch, angleYaw); - e.AddEPair("angles", buffer); - } - - if(m_numModels) { - int treetype = rand() % m_numModels; - e.AddEPair("model", m_trees[treetype].name); - } - - if(m_useScale) { - float scale = (((rand()%1000)*0.001f) * (m_maxScale - m_minScale)) + m_minScale; - - sprintf(buffer, "%f", scale ); - e.AddEPair("modelscale", buffer); - } - - e.BuildInRadiant( FALSE ); - } - - if(m_autoLink) { - DoTrainPathPlot(); - } - - return true; -} - -bool DTreePlanter::OnLButtonUp(guint32 nFlags, gdouble x, gdouble y) { - return false; -} - -bool DTreePlanter::OnRButtonDown(guint32 nFlags, gdouble x, gdouble y) { - return false; -} - -bool DTreePlanter::OnRButtonUp(guint32 nFlags, gdouble x, gdouble y) { - return false; -} - -bool DTreePlanter::OnMButtonDown(guint32 nFlags, gdouble x, gdouble y) { - return false; -} - -bool DTreePlanter::OnMButtonUp(guint32 nFlags, gdouble x, gdouble y) { - return false; -} - -bool DTreePlanter::FindDropPoint(vec3_t in, vec3_t out) { - DPlane p1; - DPlane p2; - - vec3_t vUp = { 0, 0, 1 }; - vec3_t vForward = { 0, 1, 0 }; - vec3_t vLeft = { 1, 0, 0 }; - - in[2] = 65535; - - VectorCopy(in, p1.points[0]); - VectorCopy(in, p1.points[1]); - VectorCopy(in, p1.points[2]); - VectorMA(p1.points[1], 20, vUp, p1.points[1]); - VectorMA(p1.points[1], 20, vLeft, p1.points[2]); - - VectorCopy(in, p2.points[0]); - VectorCopy(in, p2.points[1]); - VectorCopy(in, p2.points[2]); - VectorMA(p1.points[1], 20, vUp, p2.points[1]); - VectorMA(p1.points[1], 20, vForward, p2.points[2]); - - p1.Rebuild(); - p2.Rebuild(); - - bool found = false; - vec3_t temp; - vec_t dist; - int cnt = m_world.GetIDMax(); - for(int i = 0; i < cnt; i++) { - DBrush* pBrush = m_world.GetBrushForID( i ); - - if(pBrush->IntersectsWith( &p1, &p2, temp )) { - vec3_t diff; - vec_t tempdist; - VectorSubtract(in, temp, diff); - tempdist = VectorLength( diff ); - if(!found || (tempdist < dist)) { - dist = tempdist; - VectorCopy( temp, out ); - found = true; - } - } - } - - return found; -} - -void DTreePlanter::DropEntsToGround( void ) { - // tell Radiant we want to access the selected brushes - g_FuncTable.m_pfnAllocateSelectedBrushHandles(); - - DEntity ent; - - int cnt = g_FuncTable.m_pfnSelectedBrushCount(); - for(int i = 0; i < cnt; i++) { - brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i); - - ent.LoadFromEntity(brush->owner, TRUE); - - DEPair* pEpair = ent.FindEPairByKey("origin"); - if(!pEpair) { - continue; - } - - vec3_t vec, out; - sscanf( pEpair->value.GetBuffer(), "%f %f %f", &vec[0], &vec[1], &vec[2]); - - FindDropPoint( vec, out ); - - char buffer[256]; - sprintf( buffer, "%f %f %f", out[0], out[1], out[2] ); - ent.AddEPair( "origin", buffer ); - ent.RemoveFromRadiant(); - ent.BuildInRadiant(FALSE); - } - - g_FuncTable.m_pfnReleaseSelectedBrushHandles(); -} - -void DTreePlanter::MakeChain( void ) { - char buffer[256]; - int i; - - for(i = 0; i < m_linkNum; i++) { - DEntity e("info_train_spline_main"); - - sprintf( buffer, "%s_pt%i", m_linkName, i ); - e.AddEPair( "targetname", buffer ); - - sprintf( buffer, "0 %i 0", i * 64 ); - e.AddEPair( "origin", buffer ); - - if(i != m_linkNum-1) { - sprintf( buffer, "%s_pt%i", m_linkName, i+1 ); - e.AddEPair( "target", buffer ); - - sprintf( buffer, "%s_ctl%i", m_linkName, i ); - e.AddEPair( "control", buffer ); - } - - e.BuildInRadiant( FALSE ); - } - - for(i = 0; i < m_linkNum-1; i++) { - DEntity e("info_train_spline_control"); - - sprintf( buffer, "%s_ctl%i", m_linkName, i ); - e.AddEPair( "targetname", buffer ); - - sprintf( buffer, "0 %i 0", (i * 64) + 32); - e.AddEPair( "origin", buffer ); - - e.BuildInRadiant( FALSE ); - } -} - -void DTreePlanter::SelectChain( void ) { -/* char buffer[256]; - - for(int i = 0; i < m_linkNum; i++) { - DEntity e("info_train_spline_main"); - - sprintf( buffer, "%s_pt%i", m_linkName, i ); - e.AddEPair( "targetname", buffer ); - - sprintf( buffer, "0 %i 0", i * 64 ); - e.AddEPair( "origin", buffer ); - - if(i != m_linkNum-1) { - sprintf( buffer, "%s_pt%i", m_linkName, i+1 ); - e.AddEPair( "target", buffer ); - - sprintf( buffer, "%s_ctl%i", m_linkName, i ); - e.AddEPair( "control", buffer ); - } - - e.BuildInRadiant( FALSE ); - } - - for(int i = 0; i < m_linkNum-1; i++) { - DEntity e("info_train_spline_control"); - - sprintf( buffer, "%s_ctl%i", m_linkName, i ); - e.AddEPair( "targetname", buffer ); - - sprintf( buffer, "0 %i 0", (i * 64) + 32); - e.AddEPair( "origin", buffer ); - - e.BuildInRadiant( FALSE ); - }*/ -} +/* +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 +*/ + +#include "StdAfx.h" +#include "DTreePlanter.h" +#include "funchandlers.h" + +bool DTreePlanter::OnMouseMove(guint32 nFlags, gdouble x, gdouble y) { + return false; +} + +bool DTreePlanter::OnLButtonDown(guint32 nFlags, gdouble x, gdouble y) { + VIEWTYPE vt = m_XYWrapper->GetViewType(); + + switch(vt) { + case XY: + break; + case YZ: + case XZ: + default: + return false; + } + + vec3_t pt, vhit; + + m_XYWrapper->SnapToGrid( static_cast< int >( x ), static_cast< int >( y ), pt ); + + if(FindDropPoint(pt, vhit)) { + vhit[2] += m_offset; + + char buffer[128]; + DEntity e(m_entType); + + sprintf(buffer, "%i %i %i", (int)vhit[0], (int)vhit[1], (int)vhit[2]); + e.AddEPair("origin", buffer); + + if(m_autoLink) { + entity_t* pLastEntity = NULL; + entity_t* pThisEntity = NULL; + + int entNum = -1, lastEntNum = -1, entpos; + for(int i = 0; i < 256; i++) { + sprintf(buffer, m_linkName, i); + pThisEntity = FindEntityFromTargetname( buffer, &entNum ); + + if(pThisEntity) { + entpos = i; + lastEntNum = entNum; + pLastEntity = pThisEntity; + } + } + + if(!pLastEntity) { + sprintf(buffer, m_linkName, 0); + } else { + sprintf(buffer, m_linkName, entpos + 1); + } + + e.AddEPair( "targetname", buffer ); + + if(pLastEntity) { + DEntity e2; + e2.LoadFromEntity(lastEntNum, TRUE); + e2.AddEPair("target", buffer); + e2.RemoveFromRadiant(); + e2.BuildInRadiant(FALSE); + } + } + + if(m_setAngles) { + int angleYaw = (rand() % (m_maxYaw - m_minYaw + 1)) + m_minYaw; + int anglePitch = (rand() % (m_maxPitch - m_minPitch + 1)) + m_minPitch; + + sprintf(buffer, "%i %i 0", anglePitch, angleYaw); + e.AddEPair("angles", buffer); + } + + if(m_numModels) { + int treetype = rand() % m_numModels; + e.AddEPair("model", m_trees[treetype].name); + } + + if(m_useScale) { + float scale = (((rand()%1000)*0.001f) * (m_maxScale - m_minScale)) + m_minScale; + + sprintf(buffer, "%f", scale ); + e.AddEPair("modelscale", buffer); + } + + e.BuildInRadiant( FALSE ); + } + + if(m_autoLink) { + DoTrainPathPlot(); + } + + return true; +} + +bool DTreePlanter::OnLButtonUp(guint32 nFlags, gdouble x, gdouble y) { + return false; +} + +bool DTreePlanter::OnRButtonDown(guint32 nFlags, gdouble x, gdouble y) { + return false; +} + +bool DTreePlanter::OnRButtonUp(guint32 nFlags, gdouble x, gdouble y) { + return false; +} + +bool DTreePlanter::OnMButtonDown(guint32 nFlags, gdouble x, gdouble y) { + return false; +} + +bool DTreePlanter::OnMButtonUp(guint32 nFlags, gdouble x, gdouble y) { + return false; +} + +bool DTreePlanter::FindDropPoint(vec3_t in, vec3_t out) { + DPlane p1; + DPlane p2; + + vec3_t vUp = { 0, 0, 1 }; + vec3_t vForward = { 0, 1, 0 }; + vec3_t vLeft = { 1, 0, 0 }; + + in[2] = 65535; + + VectorCopy(in, p1.points[0]); + VectorCopy(in, p1.points[1]); + VectorCopy(in, p1.points[2]); + VectorMA(p1.points[1], 20, vUp, p1.points[1]); + VectorMA(p1.points[1], 20, vLeft, p1.points[2]); + + VectorCopy(in, p2.points[0]); + VectorCopy(in, p2.points[1]); + VectorCopy(in, p2.points[2]); + VectorMA(p1.points[1], 20, vUp, p2.points[1]); + VectorMA(p1.points[1], 20, vForward, p2.points[2]); + + p1.Rebuild(); + p2.Rebuild(); + + bool found = false; + vec3_t temp; + vec_t dist; + int cnt = m_world.GetIDMax(); + for(int i = 0; i < cnt; i++) { + DBrush* pBrush = m_world.GetBrushForID( i ); + + if(pBrush->IntersectsWith( &p1, &p2, temp )) { + vec3_t diff; + vec_t tempdist; + VectorSubtract(in, temp, diff); + tempdist = VectorLength( diff ); + if(!found || (tempdist < dist)) { + dist = tempdist; + VectorCopy( temp, out ); + found = true; + } + } + } + + return found; +} + +void DTreePlanter::DropEntsToGround( void ) { + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + DEntity ent; + + int cnt = g_FuncTable.m_pfnSelectedBrushCount(); + for(int i = 0; i < cnt; i++) { + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i); + + ent.LoadFromEntity(brush->owner, TRUE); + + DEPair* pEpair = ent.FindEPairByKey("origin"); + if(!pEpair) { + continue; + } + + vec3_t vec, out; + sscanf( pEpair->value.GetBuffer(), "%f %f %f", &vec[0], &vec[1], &vec[2]); + + FindDropPoint( vec, out ); + + char buffer[256]; + sprintf( buffer, "%f %f %f", out[0], out[1], out[2] ); + ent.AddEPair( "origin", buffer ); + ent.RemoveFromRadiant(); + ent.BuildInRadiant(FALSE); + } + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DTreePlanter::MakeChain( void ) { + char buffer[256]; + int i; + + for(i = 0; i < m_linkNum; i++) { + DEntity e("info_train_spline_main"); + + sprintf( buffer, "%s_pt%i", m_linkName, i ); + e.AddEPair( "targetname", buffer ); + + sprintf( buffer, "0 %i 0", i * 64 ); + e.AddEPair( "origin", buffer ); + + if(i != m_linkNum-1) { + sprintf( buffer, "%s_pt%i", m_linkName, i+1 ); + e.AddEPair( "target", buffer ); + + sprintf( buffer, "%s_ctl%i", m_linkName, i ); + e.AddEPair( "control", buffer ); + } + + e.BuildInRadiant( FALSE ); + } + + for(i = 0; i < m_linkNum-1; i++) { + DEntity e("info_train_spline_control"); + + sprintf( buffer, "%s_ctl%i", m_linkName, i ); + e.AddEPair( "targetname", buffer ); + + sprintf( buffer, "0 %i 0", (i * 64) + 32); + e.AddEPair( "origin", buffer ); + + e.BuildInRadiant( FALSE ); + } +} + +void DTreePlanter::SelectChain( void ) { +/* char buffer[256]; + + for(int i = 0; i < m_linkNum; i++) { + DEntity e("info_train_spline_main"); + + sprintf( buffer, "%s_pt%i", m_linkName, i ); + e.AddEPair( "targetname", buffer ); + + sprintf( buffer, "0 %i 0", i * 64 ); + e.AddEPair( "origin", buffer ); + + if(i != m_linkNum-1) { + sprintf( buffer, "%s_pt%i", m_linkName, i+1 ); + e.AddEPair( "target", buffer ); + + sprintf( buffer, "%s_ctl%i", m_linkName, i ); + e.AddEPair( "control", buffer ); + } + + e.BuildInRadiant( FALSE ); + } + + for(int i = 0; i < m_linkNum-1; i++) { + DEntity e("info_train_spline_control"); + + sprintf( buffer, "%s_ctl%i", m_linkName, i ); + e.AddEPair( "targetname", buffer ); + + sprintf( buffer, "0 %i 0", (i * 64) + 32); + e.AddEPair( "origin", buffer ); + + e.BuildInRadiant( FALSE ); + }*/ +} diff --git a/contrib/bobtoolz/DVisDrawer.cpp b/contrib/bobtoolz/DVisDrawer.cpp index b954268f..318b7bc8 100644 --- a/contrib/bobtoolz/DVisDrawer.cpp +++ b/contrib/bobtoolz/DVisDrawer.cpp @@ -1,179 +1,179 @@ -/* -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 DVisDrawer class. -// -////////////////////////////////////////////////////////////////////// - -#include "StdAfx.h" -#include "DPoint.h" -#include "DVisDrawer.h" -#include "misc.h" -#include "funchandlers.h" - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -DVisDrawer::DVisDrawer() -{ - refCount = 1; - m_bHooked = FALSE; - m_list = NULL; -} - -DVisDrawer::~DVisDrawer() -{ - if(m_bHooked) - UnRegister(); - - g_VisView = NULL; -} - -////////////////////////////////////////////////////////////////////// -// Implementation -////////////////////////////////////////////////////////////////////// - -void DVisDrawer::Draw2D(VIEWTYPE vt) -{ - if(!m_list) - return; - - g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); - - g_QglTable.m_pfn_qglDisable(GL_BLEND); - g_QglTable.m_pfn_qglDisable(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, 0.5f); - - g_QglTable.m_pfn_qglEnable(GL_BLEND); - g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - g_QglTable.m_pfn_qglDisable(GL_POLYGON_SMOOTH); - - g_QglTable.m_pfn_qglDepthFunc(GL_ALWAYS); - - //bleh - list::const_iterator l=m_list->begin(); - - for(; l != m_list->end(); l++) - { - DWinding* w = *l; - - g_QglTable.m_pfn_qglColor4f(w->clr[0], w->clr[1], w->clr[2], 0.5f); - - g_QglTable.m_pfn_qglBegin(GL_POLYGON); - for(int i = 0; i < w->numpoints; i++) { - g_QglTable.m_pfn_qglVertex3f((w->p[i])[0], (w->p[i])[1], (w->p[i])[2]); - } - g_QglTable.m_pfn_qglEnd(); - } - - - g_QglTable.m_pfn_qglPopMatrix(); - - g_QglTable.m_pfn_qglPopAttrib(); -} - -void DVisDrawer::Draw3D() -{ - if(!m_list) - return; - - g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); - - g_QglTable.m_pfn_qglColor4f(1.0, 0.0, 0.0, 0.5f); - -// g_QglTable.m_pfn_qglHint(GL_FOG_HINT, GL_NICEST); - -// g_QglTable.m_pfn_qglDisable(GL_CULL_FACE); - g_QglTable.m_pfn_qglDisable(GL_LINE_SMOOTH); - -// g_QglTable.m_pfn_qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); -// g_QglTable.m_pfn_qglShadeModel(GL_SMOOTH); - - g_QglTable.m_pfn_qglEnable(GL_BLEND); - g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - g_QglTable.m_pfn_qglDisable(GL_POLYGON_SMOOTH); - - g_QglTable.m_pfn_qglDepthFunc(GL_ALWAYS); - - //bleh - list::const_iterator l=m_list->begin(); - - for(; l != m_list->end(); l++) - { - DWinding* w = *l; - - g_QglTable.m_pfn_qglColor4f(w->clr[0], w->clr[1], w->clr[2], 0.5f); - - g_QglTable.m_pfn_qglBegin(GL_POLYGON); - for(int i = 0; i < w->numpoints; i++) { - g_QglTable.m_pfn_qglVertex3f((w->p[i])[0], (w->p[i])[1], (w->p[i])[2]); - } - g_QglTable.m_pfn_qglEnd(); - } - - g_QglTable.m_pfn_qglPopAttrib(); -} - -void DVisDrawer::Register() -{ - g_QglTable.m_pfnHookGL2DWindow( this ); - g_QglTable.m_pfnHookGL3DWindow( this ); - m_bHooked = TRUE; -} - -void DVisDrawer::UnRegister() -{ - g_QglTable.m_pfnUnHookGL2DWindow( this ); - g_QglTable.m_pfnUnHookGL3DWindow( this ); - m_bHooked = FALSE; -} - -void DVisDrawer::SetList(std::list *pointList) -{ - if(m_list) - ClearPoints(); - - m_list = pointList; -} - -void DVisDrawer::ClearPoints() -{ - list::const_iterator deadPoint=m_list->begin(); - for(; deadPoint!=m_list->end(); deadPoint++) - delete *deadPoint; - m_list->clear(); -} +/* +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 DVisDrawer class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DPoint.h" +#include "DVisDrawer.h" +#include "misc.h" +#include "funchandlers.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DVisDrawer::DVisDrawer() +{ + refCount = 1; + m_bHooked = FALSE; + m_list = NULL; +} + +DVisDrawer::~DVisDrawer() +{ + if(m_bHooked) + UnRegister(); + + g_VisView = NULL; +} + +////////////////////////////////////////////////////////////////////// +// Implementation +////////////////////////////////////////////////////////////////////// + +void DVisDrawer::Draw2D(VIEWTYPE vt) +{ + if(!m_list) + return; + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + g_QglTable.m_pfn_qglDisable(GL_BLEND); + g_QglTable.m_pfn_qglDisable(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, 0.5f); + + g_QglTable.m_pfn_qglEnable(GL_BLEND); + g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + g_QglTable.m_pfn_qglDisable(GL_POLYGON_SMOOTH); + + g_QglTable.m_pfn_qglDepthFunc(GL_ALWAYS); + + //bleh + list::const_iterator l=m_list->begin(); + + for(; l != m_list->end(); l++) + { + DWinding* w = *l; + + g_QglTable.m_pfn_qglColor4f(w->clr[0], w->clr[1], w->clr[2], 0.5f); + + g_QglTable.m_pfn_qglBegin(GL_POLYGON); + for(int i = 0; i < w->numpoints; i++) { + g_QglTable.m_pfn_qglVertex3f((w->p[i])[0], (w->p[i])[1], (w->p[i])[2]); + } + g_QglTable.m_pfn_qglEnd(); + } + + + g_QglTable.m_pfn_qglPopMatrix(); + + g_QglTable.m_pfn_qglPopAttrib(); +} + +void DVisDrawer::Draw3D() +{ + if(!m_list) + return; + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + g_QglTable.m_pfn_qglColor4f(1.0, 0.0, 0.0, 0.5f); + +// g_QglTable.m_pfn_qglHint(GL_FOG_HINT, GL_NICEST); + +// g_QglTable.m_pfn_qglDisable(GL_CULL_FACE); + g_QglTable.m_pfn_qglDisable(GL_LINE_SMOOTH); + +// g_QglTable.m_pfn_qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +// g_QglTable.m_pfn_qglShadeModel(GL_SMOOTH); + + g_QglTable.m_pfn_qglEnable(GL_BLEND); + g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + g_QglTable.m_pfn_qglDisable(GL_POLYGON_SMOOTH); + + g_QglTable.m_pfn_qglDepthFunc(GL_ALWAYS); + + //bleh + list::const_iterator l=m_list->begin(); + + for(; l != m_list->end(); l++) + { + DWinding* w = *l; + + g_QglTable.m_pfn_qglColor4f(w->clr[0], w->clr[1], w->clr[2], 0.5f); + + g_QglTable.m_pfn_qglBegin(GL_POLYGON); + for(int i = 0; i < w->numpoints; i++) { + g_QglTable.m_pfn_qglVertex3f((w->p[i])[0], (w->p[i])[1], (w->p[i])[2]); + } + g_QglTable.m_pfn_qglEnd(); + } + + g_QglTable.m_pfn_qglPopAttrib(); +} + +void DVisDrawer::Register() +{ + g_QglTable.m_pfnHookGL2DWindow( this ); + g_QglTable.m_pfnHookGL3DWindow( this ); + m_bHooked = TRUE; +} + +void DVisDrawer::UnRegister() +{ + g_QglTable.m_pfnUnHookGL2DWindow( this ); + g_QglTable.m_pfnUnHookGL3DWindow( this ); + m_bHooked = FALSE; +} + +void DVisDrawer::SetList(std::list *pointList) +{ + if(m_list) + ClearPoints(); + + m_list = pointList; +} + +void DVisDrawer::ClearPoints() +{ + list::const_iterator deadPoint=m_list->begin(); + for(; deadPoint!=m_list->end(); deadPoint++) + delete *deadPoint; + m_list->clear(); +} diff --git a/contrib/bobtoolz/DWinding.cpp b/contrib/bobtoolz/DWinding.cpp index b99ede0a..118d6be3 100644 --- a/contrib/bobtoolz/DWinding.cpp +++ b/contrib/bobtoolz/DWinding.cpp @@ -1,483 +1,483 @@ -/* -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 -*/ - -// DWinding.cpp: implementation of the DWinding class. -// -////////////////////////////////////////////////////////////////////// - -#include "StdAfx.h" -#include "DWinding.h" -#include "DPlane.h" -#include "misc.h" - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -DWinding::DWinding() -{ - numpoints = 0; - p = NULL; -} - -DWinding::~DWinding() -{ - if(p) - delete[] p; -} - -////////////////////////////////////////////////////////////////////// -// Implementation -////////////////////////////////////////////////////////////////////// - -#define BOGUS_RANGE 4096 - -void DWinding::AllocWinding(int points) -{ - numpoints = points; - if(p) - delete[] p; - p = new vec3_t[points]; -} - -vec_t DWinding::WindingArea() -{ - vec3_t d1, d2, cross; - vec_t total; - - total = 0; - for (int i = 2; i < numpoints ; i++) - { - VectorSubtract (p[i-1], p[0], d1); - VectorSubtract (p[i], p[0], d2); - - CrossProduct (d1, d2, cross); - - total += 0.5f * VectorLength ( cross ); - } - - return total; -} - -void DWinding::RemoveColinearPoints() -{ - vec3_t p2[MAX_POINTS_ON_WINDING]; - - int nump = 0; - for (int i = 0; i < numpoints; i++) - { - int j = (i+1)%numpoints; - int k = (i+numpoints-1)%numpoints; - - vec3_t v1, v2; - VectorSubtract (p[j], p[i], v1); - VectorSubtract (p[i], p[k], v2); - VectorNormalize(v1, v1); - VectorNormalize(v2, v2); - - if (DotProduct(v1, v2) < 0.999) - { - VectorCopy (p[i], p2[nump]); - nump++; - } - } - - if (nump == numpoints) - return; - - AllocWinding(nump); - memcpy (p, p2, nump*sizeof(vec3_t)); -} - -DPlane* DWinding::WindingPlane() -{ - DPlane* newPlane = new DPlane(p[0], p[1], p[2], NULL); - return newPlane; -} - -void DWinding::WindingBounds(vec3_t mins, vec3_t maxs) -{ - if(numpoints == 0) - return; - - VectorCopy(mins, p[0]); - VectorCopy(maxs, p[0]); - - for (int i = 1; i < numpoints ;i++) - { - for (int j = 0; j < 3; j++) - { - vec_t v = p[i][j]; - if (v < mins[j]) - mins[j] = v; - if (v > maxs[j]) - maxs[j] = v; - } - } -} - -void DWinding::WindingCentre(vec3_t centre) -{ - VectorCopy (vec3_origin, centre); - for (int i = 0; i < numpoints; i++) - VectorAdd (p[i], centre, centre); - - float scale = 1.0f/numpoints; - VectorScale (centre, scale, centre); -} - - -DWinding* DWinding::CopyWinding() -{ - DWinding* c = new DWinding; - c->AllocWinding(numpoints); - memcpy (c->p, p, numpoints*sizeof(vec3_t)); - return c; -} - - -int DWinding::WindingOnPlaneSide(vec3_t normal, vec_t dist) -{ - bool front = FALSE; - bool back = FALSE; - - for (int i = 0; i < numpoints; i++) - { - vec_t d = DotProduct (p[i], normal) - dist; - if (d < -ON_EPSILON) - { - if (front) - return SIDE_CROSS; - back = TRUE; - continue; - } - if (d > ON_EPSILON) - { - if (back) - return SIDE_CROSS; - front = TRUE; - continue; - } - } - - if (back) - return SIDE_BACK; - if (front) - return SIDE_FRONT; - return SIDE_ON; -} - -void DWinding::CheckWinding() -{ - vec_t *p1, *p2; - vec_t edgedist; - vec3_t dir, edgenormal; - - if (numpoints < 3) - Sys_Printf ("CheckWinding: %i points", numpoints); - - vec_t area = WindingArea(); - if (area < 1) - Sys_Printf ("CheckWinding: %f area", area); - - DPlane* wPlane = WindingPlane (); - int i; - for (i = 0; i < numpoints; i++) - { - p1 = p[i]; - - int j; - for (j = 0; j < 3; j++) - if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE) - Sys_Printf ("CheckFace: BUGUS_RANGE: %f", p1[j]); - - j = i + 1 == numpoints ? 0 : i + 1; - - // check the point is on the face plane - vec_t d = DotProduct (p1, wPlane->normal) - wPlane->_d; - if (d < -ON_EPSILON || d > ON_EPSILON) - Sys_Printf ("CheckWinding: point off plane"); - - // check the edge isnt degenerate - p2 = p[j]; - VectorSubtract (p2, p1, dir); - - if (VectorLength (dir) < ON_EPSILON) - Sys_Printf ("CheckWinding: degenerate edge"); - - CrossProduct (wPlane->normal, dir, edgenormal); - VectorNormalize (edgenormal, edgenormal); - edgedist = DotProduct (p1, edgenormal); - - // all other points must be on front side - for (j = 0 ; j < numpoints ; j++) - { - if (j == i) - continue; - - d = DotProduct (p[j], edgenormal); - if (d > (edgedist + ON_EPSILON)) - Sys_Printf ("CheckWinding: non-convex"); - } - } - - delete wPlane; -} - -DWinding* DWinding::ReverseWinding() -{ - DWinding* c = new DWinding; - c->AllocWinding(numpoints); - - for (int i = 0; i < numpoints ; i++) - VectorCopy (p[numpoints-1-i], c->p[i]); - - return c; -} - -bool DWinding::ChopWindingInPlace(DPlane* chopPlane, vec_t epsilon) -{ - vec_t dists[MAX_POINTS_ON_WINDING+4]; - int sides[MAX_POINTS_ON_WINDING+4]; - int counts[3]; - vec_t *p1, *p2; - vec3_t mid; - - counts[0] = counts[1] = counts[2] = 0; - -// determine sides for each point - int i; - for (i = 0; i < numpoints; i++) - { - vec_t dot = DotProduct (p[i], chopPlane->normal); - dot -= chopPlane->_d; - dists[i] = dot; - - if (dot > epsilon) - sides[i] = SIDE_FRONT; - else if (dot < -epsilon) - sides[i] = SIDE_BACK; - else - sides[i] = SIDE_ON; - - counts[sides[i]]++; - } - sides[i] = sides[0]; - dists[i] = dists[0]; - - if (!counts[0]) - { - delete this; - return FALSE; - } - - if (!counts[1]) - return TRUE; - - int maxpts = numpoints+4; // cant use counts[0]+2 because - // of fp grouping errors - - DWinding* f = new DWinding; - f->AllocWinding(maxpts); - f->numpoints = 0; - - for (i = 0; i < numpoints; i++) - { - p1 = p[i]; - - if (sides[i] == SIDE_ON) - { - VectorCopy (p1, f->p[f->numpoints]); - f->numpoints++; - continue; - } - - if (sides[i] == SIDE_FRONT) - { - VectorCopy (p1, f->p[f->numpoints]); - f->numpoints++; - } - - if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) - continue; - - // generate a split point - p2 = p[(i+1)%numpoints]; - - vec_t dot = dists[i] / (dists[i]-dists[i+1]); - for (int j = 0; j < 3; j++) - { - if (chopPlane->normal[j] == 1) - mid[j] = chopPlane->_d; - else if (chopPlane->normal[j] == -1) - mid[j] = -chopPlane->_d; - else - mid[j] = p1[j] + dot*(p2[j]-p1[j]); - } - - VectorCopy (mid, f->p[f->numpoints]); - f->numpoints++; - } - - if (f->numpoints > maxpts) - Sys_Printf ("ClipWinding: points exceeded estimate"); - if (f->numpoints > MAX_POINTS_ON_WINDING) - Sys_Printf ("ClipWinding: MAX_POINTS_ON_WINDING"); - - delete[] p; - p = f->p; - f->p = NULL; - delete f; - return TRUE; -} - -void DWinding::ClipWindingEpsilon(DPlane* chopPlane, vec_t epsilon, DWinding **front, DWinding **back) -{ - vec_t dists[MAX_POINTS_ON_WINDING+4]; - int sides[MAX_POINTS_ON_WINDING+4]; - int counts[3]; - vec_t *p1, *p2; - vec3_t mid; - - counts[0] = counts[1] = counts[2] = 0; - -// determine sides for each point - int i; - for (i = 0; i < numpoints; i++) - { - vec_t dot = -chopPlane->DistanceToPoint(p[i]); - dists[i] = dot; - - if (dot > epsilon) - sides[i] = SIDE_FRONT; - else if (dot < -epsilon) - sides[i] = SIDE_BACK; - else - sides[i] = SIDE_ON; - - counts[sides[i]]++; - } - sides[i] = sides[0]; - dists[i] = dists[0]; - - *front = *back = NULL; - - if (!counts[0]) - { - *back = CopyWinding(); - return; - } - if (!counts[1]) - { - *front = CopyWinding(); - return; - } - - int maxpts = numpoints+4; // cant use counts[0]+2 because - // of fp grouping errors - - DWinding* f = new DWinding; - DWinding* b = new DWinding; - - f->AllocWinding(maxpts); - f->numpoints = 0; - - b->AllocWinding(maxpts); - b->numpoints = 0; - - *front = f; - *back = b; - - for (i = 0; i < numpoints ; i++) - { - p1 = p[i]; - - if (sides[i] == SIDE_ON) - { - VectorCopy (p1, f->p[f->numpoints]); - f->numpoints++; - VectorCopy (p1, b->p[b->numpoints]); - b->numpoints++; - continue; - } - - if (sides[i] == SIDE_FRONT) - { - VectorCopy (p1, f->p[f->numpoints]); - f->numpoints++; - } - if (sides[i] == SIDE_BACK) - { - VectorCopy (p1, b->p[b->numpoints]); - b->numpoints++; - } - - if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) - continue; - - // generate a split point - p2 = p[(i+1)%numpoints]; - - vec_t dot = dists[i] / (dists[i]-dists[i+1]); - for (int j = 0; j < 3; j++) - { - if (chopPlane->normal[j] == 1) - mid[j] = chopPlane->_d; - else if (chopPlane->normal[j] == -1) - mid[j] = -chopPlane->_d; - else - mid[j] = p1[j] + dot*(p2[j]-p1[j]); - } - - VectorCopy (mid, f->p[f->numpoints]); - f->numpoints++; - VectorCopy (mid, b->p[b->numpoints]); - b->numpoints++; - } - - if (f->numpoints > maxpts || b->numpoints > maxpts) - Sys_Printf ("ClipWinding: points exceeded estimate"); - if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING) - Sys_Printf ("ClipWinding: MAX_POINTS_ON_WINDING"); -} - -bool DWinding::ChopWinding(DPlane* chopPlane) -{ - DWinding *f, *b; - - ClipWindingEpsilon (chopPlane, (float)ON_EPSILON, &f, &b); - - if (b) - delete (b); - - - if(!f) - { - delete this; - return FALSE; - } - - delete[] p; - p = f->p; - f->p = NULL; - numpoints = f->numpoints; - delete f; - - return TRUE; -} +/* +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 +*/ + +// DWinding.cpp: implementation of the DWinding class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DWinding.h" +#include "DPlane.h" +#include "misc.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DWinding::DWinding() +{ + numpoints = 0; + p = NULL; +} + +DWinding::~DWinding() +{ + if(p) + delete[] p; +} + +////////////////////////////////////////////////////////////////////// +// Implementation +////////////////////////////////////////////////////////////////////// + +#define BOGUS_RANGE 4096 + +void DWinding::AllocWinding(int points) +{ + numpoints = points; + if(p) + delete[] p; + p = new vec3_t[points]; +} + +vec_t DWinding::WindingArea() +{ + vec3_t d1, d2, cross; + vec_t total; + + total = 0; + for (int i = 2; i < numpoints ; i++) + { + VectorSubtract (p[i-1], p[0], d1); + VectorSubtract (p[i], p[0], d2); + + CrossProduct (d1, d2, cross); + + total += 0.5f * VectorLength ( cross ); + } + + return total; +} + +void DWinding::RemoveColinearPoints() +{ + vec3_t p2[MAX_POINTS_ON_WINDING]; + + int nump = 0; + for (int i = 0; i < numpoints; i++) + { + int j = (i+1)%numpoints; + int k = (i+numpoints-1)%numpoints; + + vec3_t v1, v2; + VectorSubtract (p[j], p[i], v1); + VectorSubtract (p[i], p[k], v2); + VectorNormalize(v1, v1); + VectorNormalize(v2, v2); + + if (DotProduct(v1, v2) < 0.999) + { + VectorCopy (p[i], p2[nump]); + nump++; + } + } + + if (nump == numpoints) + return; + + AllocWinding(nump); + memcpy (p, p2, nump*sizeof(vec3_t)); +} + +DPlane* DWinding::WindingPlane() +{ + DPlane* newPlane = new DPlane(p[0], p[1], p[2], NULL); + return newPlane; +} + +void DWinding::WindingBounds(vec3_t mins, vec3_t maxs) +{ + if(numpoints == 0) + return; + + VectorCopy(mins, p[0]); + VectorCopy(maxs, p[0]); + + for (int i = 1; i < numpoints ;i++) + { + for (int j = 0; j < 3; j++) + { + vec_t v = p[i][j]; + if (v < mins[j]) + mins[j] = v; + if (v > maxs[j]) + maxs[j] = v; + } + } +} + +void DWinding::WindingCentre(vec3_t centre) +{ + VectorCopy (vec3_origin, centre); + for (int i = 0; i < numpoints; i++) + VectorAdd (p[i], centre, centre); + + float scale = 1.0f/numpoints; + VectorScale (centre, scale, centre); +} + + +DWinding* DWinding::CopyWinding() +{ + DWinding* c = new DWinding; + c->AllocWinding(numpoints); + memcpy (c->p, p, numpoints*sizeof(vec3_t)); + return c; +} + + +int DWinding::WindingOnPlaneSide(vec3_t normal, vec_t dist) +{ + bool front = FALSE; + bool back = FALSE; + + for (int i = 0; i < numpoints; i++) + { + vec_t d = DotProduct (p[i], normal) - dist; + if (d < -ON_EPSILON) + { + if (front) + return SIDE_CROSS; + back = TRUE; + continue; + } + if (d > ON_EPSILON) + { + if (back) + return SIDE_CROSS; + front = TRUE; + continue; + } + } + + if (back) + return SIDE_BACK; + if (front) + return SIDE_FRONT; + return SIDE_ON; +} + +void DWinding::CheckWinding() +{ + vec_t *p1, *p2; + vec_t edgedist; + vec3_t dir, edgenormal; + + if (numpoints < 3) + Sys_Printf ("CheckWinding: %i points", numpoints); + + vec_t area = WindingArea(); + if (area < 1) + Sys_Printf ("CheckWinding: %f area", area); + + DPlane* wPlane = WindingPlane (); + int i; + for (i = 0; i < numpoints; i++) + { + p1 = p[i]; + + int j; + for (j = 0; j < 3; j++) + if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE) + Sys_Printf ("CheckFace: BUGUS_RANGE: %f", p1[j]); + + j = i + 1 == numpoints ? 0 : i + 1; + + // check the point is on the face plane + vec_t d = DotProduct (p1, wPlane->normal) - wPlane->_d; + if (d < -ON_EPSILON || d > ON_EPSILON) + Sys_Printf ("CheckWinding: point off plane"); + + // check the edge isnt degenerate + p2 = p[j]; + VectorSubtract (p2, p1, dir); + + if (VectorLength (dir) < ON_EPSILON) + Sys_Printf ("CheckWinding: degenerate edge"); + + CrossProduct (wPlane->normal, dir, edgenormal); + VectorNormalize (edgenormal, edgenormal); + edgedist = DotProduct (p1, edgenormal); + + // all other points must be on front side + for (j = 0 ; j < numpoints ; j++) + { + if (j == i) + continue; + + d = DotProduct (p[j], edgenormal); + if (d > (edgedist + ON_EPSILON)) + Sys_Printf ("CheckWinding: non-convex"); + } + } + + delete wPlane; +} + +DWinding* DWinding::ReverseWinding() +{ + DWinding* c = new DWinding; + c->AllocWinding(numpoints); + + for (int i = 0; i < numpoints ; i++) + VectorCopy (p[numpoints-1-i], c->p[i]); + + return c; +} + +bool DWinding::ChopWindingInPlace(DPlane* chopPlane, vec_t epsilon) +{ + vec_t dists[MAX_POINTS_ON_WINDING+4]; + int sides[MAX_POINTS_ON_WINDING+4]; + int counts[3]; + vec_t *p1, *p2; + vec3_t mid; + + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + int i; + for (i = 0; i < numpoints; i++) + { + vec_t dot = DotProduct (p[i], chopPlane->normal); + dot -= chopPlane->_d; + dists[i] = dot; + + if (dot > epsilon) + sides[i] = SIDE_FRONT; + else if (dot < -epsilon) + sides[i] = SIDE_BACK; + else + sides[i] = SIDE_ON; + + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + if (!counts[0]) + { + delete this; + return FALSE; + } + + if (!counts[1]) + return TRUE; + + int maxpts = numpoints+4; // cant use counts[0]+2 because + // of fp grouping errors + + DWinding* f = new DWinding; + f->AllocWinding(maxpts); + f->numpoints = 0; + + for (i = 0; i < numpoints; i++) + { + p1 = p[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = p[(i+1)%numpoints]; + + vec_t dot = dists[i] / (dists[i]-dists[i+1]); + for (int j = 0; j < 3; j++) + { + if (chopPlane->normal[j] == 1) + mid[j] = chopPlane->_d; + else if (chopPlane->normal[j] == -1) + mid[j] = -chopPlane->_d; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, f->p[f->numpoints]); + f->numpoints++; + } + + if (f->numpoints > maxpts) + Sys_Printf ("ClipWinding: points exceeded estimate"); + if (f->numpoints > MAX_POINTS_ON_WINDING) + Sys_Printf ("ClipWinding: MAX_POINTS_ON_WINDING"); + + delete[] p; + p = f->p; + f->p = NULL; + delete f; + return TRUE; +} + +void DWinding::ClipWindingEpsilon(DPlane* chopPlane, vec_t epsilon, DWinding **front, DWinding **back) +{ + vec_t dists[MAX_POINTS_ON_WINDING+4]; + int sides[MAX_POINTS_ON_WINDING+4]; + int counts[3]; + vec_t *p1, *p2; + vec3_t mid; + + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + int i; + for (i = 0; i < numpoints; i++) + { + vec_t dot = -chopPlane->DistanceToPoint(p[i]); + dists[i] = dot; + + if (dot > epsilon) + sides[i] = SIDE_FRONT; + else if (dot < -epsilon) + sides[i] = SIDE_BACK; + else + sides[i] = SIDE_ON; + + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + *front = *back = NULL; + + if (!counts[0]) + { + *back = CopyWinding(); + return; + } + if (!counts[1]) + { + *front = CopyWinding(); + return; + } + + int maxpts = numpoints+4; // cant use counts[0]+2 because + // of fp grouping errors + + DWinding* f = new DWinding; + DWinding* b = new DWinding; + + f->AllocWinding(maxpts); + f->numpoints = 0; + + b->AllocWinding(maxpts); + b->numpoints = 0; + + *front = f; + *back = b; + + for (i = 0; i < numpoints ; i++) + { + p1 = p[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + VectorCopy (p1, b->p[b->numpoints]); + b->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + } + if (sides[i] == SIDE_BACK) + { + VectorCopy (p1, b->p[b->numpoints]); + b->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = p[(i+1)%numpoints]; + + vec_t dot = dists[i] / (dists[i]-dists[i+1]); + for (int j = 0; j < 3; j++) + { + if (chopPlane->normal[j] == 1) + mid[j] = chopPlane->_d; + else if (chopPlane->normal[j] == -1) + mid[j] = -chopPlane->_d; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, f->p[f->numpoints]); + f->numpoints++; + VectorCopy (mid, b->p[b->numpoints]); + b->numpoints++; + } + + if (f->numpoints > maxpts || b->numpoints > maxpts) + Sys_Printf ("ClipWinding: points exceeded estimate"); + if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING) + Sys_Printf ("ClipWinding: MAX_POINTS_ON_WINDING"); +} + +bool DWinding::ChopWinding(DPlane* chopPlane) +{ + DWinding *f, *b; + + ClipWindingEpsilon (chopPlane, (float)ON_EPSILON, &f, &b); + + if (b) + delete (b); + + + if(!f) + { + delete this; + return FALSE; + } + + delete[] p; + p = f->p; + f->p = NULL; + numpoints = f->numpoints; + delete f; + + return TRUE; +} diff --git a/contrib/bobtoolz/ScriptParser.cpp b/contrib/bobtoolz/ScriptParser.cpp index c94175e1..012e531a 100644 --- a/contrib/bobtoolz/ScriptParser.cpp +++ b/contrib/bobtoolz/ScriptParser.cpp @@ -1,267 +1,267 @@ -#include "StdAfx.h" -#include "ScriptParser.h" - -CScriptParser::CScriptParser(void): - m_pScript(NULL), - m_pScriptSection(NULL), - m_pLastScriptSection(NULL), - m_pToken(NULL) { - ClearBuffer(); -} - -CScriptParser::~CScriptParser(void) { - ClearBuffer(); -} - -void CScriptParser::ClearBuffer(void) { - if(m_pScript) { - delete[] m_pScript; - m_pScript = NULL; - } - if(m_pToken) { - delete[] m_pToken; - m_pToken = NULL; - } - m_pScriptSection = NULL; - m_pLastScriptSection = NULL; - memset(m_breakChars, 0, sizeof(m_breakChars)); -} - -const char* CScriptParser::MakeToken(const char* pToken) { - if(m_pToken) { - delete[] m_pToken; - m_pToken = NULL; - } - - if(!pToken) { - pToken = ""; - } - - int len = static_cast(strlen(pToken)); - - m_pToken = new char[len + 1]; - m_pToken[len] = '\0'; - strcpy(m_pToken, pToken); - - return m_pToken; -} - -#define MAX_TOKEN_STRING 1024 -// Should NEVER return NULL -const char* CScriptParser::GetToken(bool bAllowLinebreaks) { - int c = 0, len; - char token[MAX_TOKEN_STRING]; - bool bNewLines = false; - - m_pLastScriptSection = m_pScriptSection; - - len = 0; - *token = '\0'; - - if(!m_pScript || !m_pScriptSection) { - return MakeToken(token); - } - - while ( true ) { - SkipWhitespace( &bNewLines ); - if ( !*m_pScriptSection ) { - return MakeToken(token); - } - if ( bNewLines && !bAllowLinebreaks ) { - return MakeToken(token); - } - - c = *m_pScriptSection; - - if ( c == '/' && m_pScriptSection[1] == '/' ) { // C style comments - m_pScriptSection += 2; - while (*m_pScriptSection && *m_pScriptSection != '\n') { - m_pScriptSection++; - } - } else if ( c=='/' && m_pScriptSection[1] == '*' ) { // C++ style comments - m_pScriptSection += 2; - while ( *m_pScriptSection && ( *m_pScriptSection != '*' || m_pScriptSection[1] != '/' ) ) { - m_pScriptSection++; - } - if ( *m_pScriptSection ) { - m_pScriptSection += 2; - } - } else { - break; - } - } - - if (c == '\"') { - m_pScriptSection++; - while ( true ) { - c = *m_pScriptSection++; - if (c=='\"' || !c) { - token[len] = 0; - return MakeToken(token); - } - if (len < MAX_TOKEN_STRING) { - token[len] = c; - len++; - } - } - } - - do { - if(len > 0 && IsBreakChar(*m_pScriptSection)) { - break; - } - - if (len < MAX_TOKEN_STRING) { - token[len] = c; - len++; - } - m_pScriptSection++; - - if(IsBreakChar(c)) { - break; - } - - c = *m_pScriptSection; - } while (c > 32); - - if (len == MAX_TOKEN_STRING) { - len = 0; - } - token[len] = 0; - - return MakeToken(token); -} - -void CScriptParser::SkipWhitespace(bool* pbNewLines) { - int c; - - if(!m_pScript || !m_pScriptSection) { - return; - } - - while( (c = *m_pScriptSection) <= ' ') { - if( !c ) { - return; - } - if( c == '\n' ) { - *pbNewLines = true; - } - m_pScriptSection++; - } -} - -void CScriptParser::SkipBracedSection(void) { - const char *token; - int depth; - - depth = 0; - do { - token = GetToken( true ); - if( token[1] == 0 ) { - if( *token == '{' ) { - depth++; - } else if( *token == '}' ) { - depth--; - } - } - } while( depth && *m_pScriptSection ); -} - -void CScriptParser::SkipRestOfLine(void) { - char *p; - int c; - - p = m_pScriptSection; - while ( (c = *p++) != 0 ) { - if ( c == '\n' ) { - break; - } - } - m_pScriptSection = p; -} - -void CScriptParser::UndoGetToken(void) { - if(!m_pLastScriptSection) { - return; - } - m_pScriptSection = m_pLastScriptSection; - m_pLastScriptSection = NULL; -} - -void CScriptParser::ResetParseSession(void) { - if(!m_pScript) { - return; - } - - m_pScriptSection = m_pScript; - m_pLastScriptSection = NULL; -} - -char* CScriptParser::GetBufferCopy(void) { - if(!m_pScript) { - return NULL; - } - - int len = static_cast(strlen(m_pScript)); - char* pBuffer = new char[len + 1]; - strcpy(pBuffer, m_pScript); - return pBuffer; -} - -int CScriptParser::GetTokenOffset(void) { - if(!m_pScript || !m_pScriptSection) { - return 0; - } - - return static_cast(m_pScriptSection - m_pScript); -} - -void CScriptParser::LoadScript(const char* pScript) { - ClearBuffer(); - - int len = static_cast(strlen(pScript)); - if(len <= 0) { - return; - } - - m_pScript = new char[len + 1]; - m_pScript[len] = '\0'; - - strcpy(m_pScript, pScript); - m_pScriptSection = m_pScript; -} - -void CScriptParser::AddBreakChar(char c) { - for(int i = 0; i < SP_MAX_BREAKCHARS; i++) { - if(!m_breakChars[i]) { - m_breakChars[i] = c; - return; - } - } - - // TODO: Error: max break chars hit -} - -bool CScriptParser::IsBreakChar(char c) { - for(int i = 0; i < SP_MAX_BREAKCHARS; i++) { - if(!m_breakChars[i]) { - return false; - } - if(m_breakChars[i] == c) { - return true; - } - } - return false; -} - -void CScriptParser::SetScript(char* pScript) { - ClearBuffer(); - - int len = static_cast(strlen(pScript)); - if(len <= 0) { - return; - } - - m_pScript = pScript; - m_pScriptSection = m_pScript; -} +#include "StdAfx.h" +#include "ScriptParser.h" + +CScriptParser::CScriptParser(void): + m_pScript(NULL), + m_pScriptSection(NULL), + m_pLastScriptSection(NULL), + m_pToken(NULL) { + ClearBuffer(); +} + +CScriptParser::~CScriptParser(void) { + ClearBuffer(); +} + +void CScriptParser::ClearBuffer(void) { + if(m_pScript) { + delete[] m_pScript; + m_pScript = NULL; + } + if(m_pToken) { + delete[] m_pToken; + m_pToken = NULL; + } + m_pScriptSection = NULL; + m_pLastScriptSection = NULL; + memset(m_breakChars, 0, sizeof(m_breakChars)); +} + +const char* CScriptParser::MakeToken(const char* pToken) { + if(m_pToken) { + delete[] m_pToken; + m_pToken = NULL; + } + + if(!pToken) { + pToken = ""; + } + + int len = static_cast(strlen(pToken)); + + m_pToken = new char[len + 1]; + m_pToken[len] = '\0'; + strcpy(m_pToken, pToken); + + return m_pToken; +} + +#define MAX_TOKEN_STRING 1024 +// Should NEVER return NULL +const char* CScriptParser::GetToken(bool bAllowLinebreaks) { + int c = 0, len; + char token[MAX_TOKEN_STRING]; + bool bNewLines = false; + + m_pLastScriptSection = m_pScriptSection; + + len = 0; + *token = '\0'; + + if(!m_pScript || !m_pScriptSection) { + return MakeToken(token); + } + + while ( true ) { + SkipWhitespace( &bNewLines ); + if ( !*m_pScriptSection ) { + return MakeToken(token); + } + if ( bNewLines && !bAllowLinebreaks ) { + return MakeToken(token); + } + + c = *m_pScriptSection; + + if ( c == '/' && m_pScriptSection[1] == '/' ) { // C style comments + m_pScriptSection += 2; + while (*m_pScriptSection && *m_pScriptSection != '\n') { + m_pScriptSection++; + } + } else if ( c=='/' && m_pScriptSection[1] == '*' ) { // C++ style comments + m_pScriptSection += 2; + while ( *m_pScriptSection && ( *m_pScriptSection != '*' || m_pScriptSection[1] != '/' ) ) { + m_pScriptSection++; + } + if ( *m_pScriptSection ) { + m_pScriptSection += 2; + } + } else { + break; + } + } + + if (c == '\"') { + m_pScriptSection++; + while ( true ) { + c = *m_pScriptSection++; + if (c=='\"' || !c) { + token[len] = 0; + return MakeToken(token); + } + if (len < MAX_TOKEN_STRING) { + token[len] = c; + len++; + } + } + } + + do { + if(len > 0 && IsBreakChar(*m_pScriptSection)) { + break; + } + + if (len < MAX_TOKEN_STRING) { + token[len] = c; + len++; + } + m_pScriptSection++; + + if(IsBreakChar(c)) { + break; + } + + c = *m_pScriptSection; + } while (c > 32); + + if (len == MAX_TOKEN_STRING) { + len = 0; + } + token[len] = 0; + + return MakeToken(token); +} + +void CScriptParser::SkipWhitespace(bool* pbNewLines) { + int c; + + if(!m_pScript || !m_pScriptSection) { + return; + } + + while( (c = *m_pScriptSection) <= ' ') { + if( !c ) { + return; + } + if( c == '\n' ) { + *pbNewLines = true; + } + m_pScriptSection++; + } +} + +void CScriptParser::SkipBracedSection(void) { + const char *token; + int depth; + + depth = 0; + do { + token = GetToken( true ); + if( token[1] == 0 ) { + if( *token == '{' ) { + depth++; + } else if( *token == '}' ) { + depth--; + } + } + } while( depth && *m_pScriptSection ); +} + +void CScriptParser::SkipRestOfLine(void) { + char *p; + int c; + + p = m_pScriptSection; + while ( (c = *p++) != 0 ) { + if ( c == '\n' ) { + break; + } + } + m_pScriptSection = p; +} + +void CScriptParser::UndoGetToken(void) { + if(!m_pLastScriptSection) { + return; + } + m_pScriptSection = m_pLastScriptSection; + m_pLastScriptSection = NULL; +} + +void CScriptParser::ResetParseSession(void) { + if(!m_pScript) { + return; + } + + m_pScriptSection = m_pScript; + m_pLastScriptSection = NULL; +} + +char* CScriptParser::GetBufferCopy(void) { + if(!m_pScript) { + return NULL; + } + + int len = static_cast(strlen(m_pScript)); + char* pBuffer = new char[len + 1]; + strcpy(pBuffer, m_pScript); + return pBuffer; +} + +int CScriptParser::GetTokenOffset(void) { + if(!m_pScript || !m_pScriptSection) { + return 0; + } + + return static_cast(m_pScriptSection - m_pScript); +} + +void CScriptParser::LoadScript(const char* pScript) { + ClearBuffer(); + + int len = static_cast(strlen(pScript)); + if(len <= 0) { + return; + } + + m_pScript = new char[len + 1]; + m_pScript[len] = '\0'; + + strcpy(m_pScript, pScript); + m_pScriptSection = m_pScript; +} + +void CScriptParser::AddBreakChar(char c) { + for(int i = 0; i < SP_MAX_BREAKCHARS; i++) { + if(!m_breakChars[i]) { + m_breakChars[i] = c; + return; + } + } + + // TODO: Error: max break chars hit +} + +bool CScriptParser::IsBreakChar(char c) { + for(int i = 0; i < SP_MAX_BREAKCHARS; i++) { + if(!m_breakChars[i]) { + return false; + } + if(m_breakChars[i] == c) { + return true; + } + } + return false; +} + +void CScriptParser::SetScript(char* pScript) { + ClearBuffer(); + + int len = static_cast(strlen(pScript)); + if(len <= 0) { + return; + } + + m_pScript = pScript; + m_pScriptSection = m_pScript; +} diff --git a/contrib/bobtoolz/StdAfx.cpp b/contrib/bobtoolz/StdAfx.cpp index eab4b5a5..1a02f66b 100644 --- a/contrib/bobtoolz/StdAfx.cpp +++ b/contrib/bobtoolz/StdAfx.cpp @@ -1,25 +1,25 @@ -/* -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 -*/ - -// stdafx.cpp : source file that includes just the standard includes -// plugin.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "StdAfx.h" - +/* +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 +*/ + +// stdafx.cpp : source file that includes just the standard includes +// plugin.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "StdAfx.h" + diff --git a/contrib/bobtoolz/bobToolz-GTK.cpp b/contrib/bobtoolz/bobToolz-GTK.cpp index 1e55c31c..e0db8f36 100644 --- a/contrib/bobtoolz/bobToolz-GTK.cpp +++ b/contrib/bobtoolz/bobToolz-GTK.cpp @@ -1,297 +1,297 @@ -/* -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 -*/ - -#include "StdAfx.h" - -#include "funchandlers.h" -#include "misc.h" - -#include "dialogs/dialogs-gtk.h" -#include "../../libs/cmdlib.h" - -// Radiant function table -_QERFuncTable_1 g_FuncTable; -_QERAppDataTable g_AppDataTable; -_QERBrushTable g_BrushTable; -_QERShadersTable g_ShadersTable; // vvvvvvvvvvvvvvvvvvvv -_QERSelectedFaceTable g_SelectedFaceTable; // to get texture sizes -_QERQglTable g_QglTable; // for path plotting (hooking to DBobView) -_QERUITable g_MessageTable; // for path plotting (listening for update) -_QEREntityTable g_EntityTable; - -// plugin name -char* PLUGIN_NAME = "bobToolz"; - -// commands in the menu -static char* PLUGIN_COMMANDS = "About...,-,Reset Textures...,PitOMatic,-,Vis Viewer,Brush Cleanup,Polygon Builder,Caulk Selection,-,Tree Planter,Drop Entity,Plot Splines,-,Merge Patches,Split patches,Turn edge"; - -// globals -GtkWidget *g_pRadiantWnd = NULL; - -static const char *PLUGIN_ABOUT = "bobToolz for SDRadiant\n" - "by digibob (digibob@splashdamage.com)\n" - "http://www.splashdamage.com\n\n" - "Additional Contributors:\n" - "MarsMattel, RR2DO2\n"; - -extern "C" const char* QERPlug_Init( void* hApp, void* pMainWidget ) { - g_pRadiantWnd = (GtkWidget*)pMainWidget; - - return "bobToolz for GTKradiant"; -} - -extern "C" const char* QERPlug_GetName() { - return PLUGIN_NAME; -} - -extern "C" const char* QERPlug_GetCommandList() { - return PLUGIN_COMMANDS; -} - -extern "C" void QERPlug_Dispatch (const char *p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) { - LoadLists(); - - if( !stricmp( p, "brush cleanup" ) ) { - DoFixBrushes(); - } else if( !stricmp( p, "polygon builder" ) ) { - DoPolygonsTB(); - } else if( !stricmp( p, "caulk selection" ) ) { - DoCaulkSelection(); - } else if( !stricmp( p, "tree planter" ) ) { - DoTreePlanter(); - } else if( !stricmp( p, "plot splines" ) ) { - DoTrainPathPlot(); - } else if( !stricmp( p, "drop entity" ) ) { - DoDropEnts(); - } else if( !stricmp( p, "merge patches" ) ) { - DoMergePatches(); - } else if( !stricmp( p, "split patches" ) ) { - DoSplitPatch(); - } else if( !stricmp( p, "turn edge" ) ) { - DoFlipTerrain(); - } else if( !stricmp(p, "reset textures...") ) { - DoResetTextures(); - } else if( !stricmp(p, "pitomatic") ) { - DoPitBuilder(vMin, vMax); - } else if( !stricmp(p, "vis viewer") ) { - DoVisAnalyse(); - } else if( !stricmp(p, "about...") ) { - DoMessageBox(PLUGIN_ABOUT, "About", IDOK); - } -} - -#define NUM_TOOLBARBUTTONS 9 - -unsigned int ToolbarButtonCount( void ) { - return NUM_TOOLBARBUTTONS; -} - -// Load a xpm file and return a pixmap widget. -GtkWidget* new_pixmap (char* filename) { - GdkPixmap *gdkpixmap; - GdkBitmap *mask; - GtkWidget *pixmap; - - g_FuncTable.m_pfnLoadBitmap(filename, (void **)&gdkpixmap, (void **)&mask); - pixmap = gtk_pixmap_new (gdkpixmap, mask); - - gdk_pixmap_unref (gdkpixmap); - gdk_pixmap_unref (mask); - - return pixmap; -} - -class CBobtoolzToolbarButton : public IToolbarButton -{ -public: - virtual const char* getImage() const - { - switch( mIndex ) { - case 0: return "bobtoolz_cleanup.bmp"; - case 1: return "bobtoolz_poly.bmp"; - case 2: return "bobtoolz_caulk.bmp"; - case 3: return "bobtoolz_treeplanter.bmp"; - case 4: return "bobtoolz_trainpathplot.bmp"; - case 5: return "bobtoolz_dropent.bmp"; - case 6: return "bobtoolz_merge.bmp"; - case 7: return "bobtoolz_split.bmp"; - case 8: return "bobtoolz_turnedge.bmp"; - } - return NULL; - } - virtual EType getType() const - { - switch( mIndex ) { - case 3: return eToggleButton; - default: return eButton; - } - } - virtual const char* getText() const - { - switch( mIndex ) { - case 0: return "Cleanup"; - case 1: return "Polygons"; - case 2: return "Caulk"; - case 3: return "Tree Planter"; - case 4: return "Plot Splines"; - case 5: return "Drop Entity"; - case 6: return "Merge Patches"; - case 7: return "Split Patches"; - case 8: return "Flip Terrain"; - } - return NULL; - } - virtual const char* getTooltip() const - { - switch( mIndex ) { - case 0: return "Brush Cleanup"; - case 1: return "Polygons"; - case 2: return "Caulk selection"; - case 3: return "Tree Planter"; - case 4: return "Plot Splines"; - case 5: return "Drop Entity"; - case 6: return "Merge Patches"; - case 7: return "Split Patches"; - case 8: return "Flip Terrain"; - } - return NULL; - } - - virtual void activate() const - { - LoadLists(); - - switch( mIndex ) { - case 0: DoFixBrushes(); break; - case 1: DoPolygonsTB(); break; - case 2: DoCaulkSelection(); break; - case 3: DoTreePlanter(); break; - case 4: DoTrainPathPlot(); break; - case 5: DoDropEnts(); break; - case 6: DoMergePatches(); break; - case 7: DoSplitPatch(); break; - case 8: DoFlipTerrain(); break; - } - } - - int mIndex; -}; - -CBobtoolzToolbarButton g_bobtoolzToolbarButtons[NUM_TOOLBARBUTTONS]; - -const IToolbarButton* GetToolbarButton(unsigned int index) -{ - g_bobtoolzToolbarButtons[index].mIndex = index; - return &g_bobtoolzToolbarButtons[index]; -} - -// ============================================================================= -// SYNAPSE - -class CSynapseClientBobtoolz : public CSynapseClient -{ -public: - // CSynapseClient API - bool RequestAPI(APIDescriptor_t *pAPI); - const char* GetInfo(); - - CSynapseClientBobtoolz() { } - virtual ~CSynapseClientBobtoolz() { } -}; - - -CSynapseServer* g_pSynapseServer = NULL; -CSynapseClientBobtoolz 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, BOBTOOLZ_MINOR, sizeof(_QERPlugToolbarTable)); - g_SynapseClient.AddAPI(PLUGIN_MAJOR, BOBTOOLZ_MINOR, sizeof(_QERPluginTable)); - - g_SynapseClient.AddAPI(DATA_MAJOR, NULL, sizeof(g_AppDataTable), SYN_REQUIRE, &g_AppDataTable); - g_SynapseClient.AddAPI(BRUSH_MAJOR, NULL, sizeof(g_BrushTable), SYN_REQUIRE, &g_BrushTable); - g_SynapseClient.AddAPI(SHADERS_MAJOR, "*", sizeof(g_ShadersTable), SYN_REQUIRE, &g_ShadersTable); - g_SynapseClient.AddAPI(ENTITY_MAJOR, NULL, sizeof(g_EntityTable), SYN_REQUIRE, &g_EntityTable); - g_SynapseClient.AddAPI(SELECTEDFACE_MAJOR, NULL, sizeof(g_SelectedFaceTable), SYN_REQUIRE, &g_SelectedFaceTable); - g_SynapseClient.AddAPI(UI_MAJOR, NULL, sizeof(g_MessageTable), SYN_REQUIRE, &g_MessageTable); - 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); - - return &g_SynapseClient; -} - -bool CSynapseClientBobtoolz::RequestAPI(APIDescriptor_t *pAPI) -{ - if( !strcmp(pAPI->minor_name, BOBTOOLZ_MINOR) ) - { - 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; - } - else 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* CSynapseClientBobtoolz::GetInfo() -{ - return "bobToolz module built " __DATE__ " " RADIANT_VERSION; -} - -char* GetFilename(char* buffer, const char* filename) { - strcpy(buffer, g_pSynapseServer->GetModuleFilename(&g_SynapseClient)); - StripFilename( buffer ); - strcat(buffer, "/"); - strcat(buffer, filename); - buffer = UnixToDosPath(buffer); - return buffer; -} +/* +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 +*/ + +#include "StdAfx.h" + +#include "funchandlers.h" +#include "misc.h" + +#include "dialogs/dialogs-gtk.h" +#include "../../libs/cmdlib.h" + +// Radiant function table +_QERFuncTable_1 g_FuncTable; +_QERAppDataTable g_AppDataTable; +_QERBrushTable g_BrushTable; +_QERShadersTable g_ShadersTable; // vvvvvvvvvvvvvvvvvvvv +_QERSelectedFaceTable g_SelectedFaceTable; // to get texture sizes +_QERQglTable g_QglTable; // for path plotting (hooking to DBobView) +_QERUITable g_MessageTable; // for path plotting (listening for update) +_QEREntityTable g_EntityTable; + +// plugin name +char* PLUGIN_NAME = "bobToolz"; + +// commands in the menu +static char* PLUGIN_COMMANDS = "About...,-,Reset Textures...,PitOMatic,-,Vis Viewer,Brush Cleanup,Polygon Builder,Caulk Selection,-,Tree Planter,Drop Entity,Plot Splines,-,Merge Patches,Split patches,Turn edge"; + +// globals +GtkWidget *g_pRadiantWnd = NULL; + +static const char *PLUGIN_ABOUT = "bobToolz for SDRadiant\n" + "by digibob (digibob@splashdamage.com)\n" + "http://www.splashdamage.com\n\n" + "Additional Contributors:\n" + "MarsMattel, RR2DO2\n"; + +extern "C" const char* QERPlug_Init( void* hApp, void* pMainWidget ) { + g_pRadiantWnd = (GtkWidget*)pMainWidget; + + return "bobToolz for GTKradiant"; +} + +extern "C" const char* QERPlug_GetName() { + return PLUGIN_NAME; +} + +extern "C" const char* QERPlug_GetCommandList() { + return PLUGIN_COMMANDS; +} + +extern "C" void QERPlug_Dispatch (const char *p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) { + LoadLists(); + + if( !stricmp( p, "brush cleanup" ) ) { + DoFixBrushes(); + } else if( !stricmp( p, "polygon builder" ) ) { + DoPolygonsTB(); + } else if( !stricmp( p, "caulk selection" ) ) { + DoCaulkSelection(); + } else if( !stricmp( p, "tree planter" ) ) { + DoTreePlanter(); + } else if( !stricmp( p, "plot splines" ) ) { + DoTrainPathPlot(); + } else if( !stricmp( p, "drop entity" ) ) { + DoDropEnts(); + } else if( !stricmp( p, "merge patches" ) ) { + DoMergePatches(); + } else if( !stricmp( p, "split patches" ) ) { + DoSplitPatch(); + } else if( !stricmp( p, "turn edge" ) ) { + DoFlipTerrain(); + } else if( !stricmp(p, "reset textures...") ) { + DoResetTextures(); + } else if( !stricmp(p, "pitomatic") ) { + DoPitBuilder(vMin, vMax); + } else if( !stricmp(p, "vis viewer") ) { + DoVisAnalyse(); + } else if( !stricmp(p, "about...") ) { + DoMessageBox(PLUGIN_ABOUT, "About", IDOK); + } +} + +#define NUM_TOOLBARBUTTONS 9 + +unsigned int ToolbarButtonCount( void ) { + return NUM_TOOLBARBUTTONS; +} + +// Load a xpm file and return a pixmap widget. +GtkWidget* new_pixmap (char* filename) { + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + + g_FuncTable.m_pfnLoadBitmap(filename, (void **)&gdkpixmap, (void **)&mask); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + + gdk_pixmap_unref (gdkpixmap); + gdk_pixmap_unref (mask); + + return pixmap; +} + +class CBobtoolzToolbarButton : public IToolbarButton +{ +public: + virtual const char* getImage() const + { + switch( mIndex ) { + case 0: return "bobtoolz_cleanup.bmp"; + case 1: return "bobtoolz_poly.bmp"; + case 2: return "bobtoolz_caulk.bmp"; + case 3: return "bobtoolz_treeplanter.bmp"; + case 4: return "bobtoolz_trainpathplot.bmp"; + case 5: return "bobtoolz_dropent.bmp"; + case 6: return "bobtoolz_merge.bmp"; + case 7: return "bobtoolz_split.bmp"; + case 8: return "bobtoolz_turnedge.bmp"; + } + return NULL; + } + virtual EType getType() const + { + switch( mIndex ) { + case 3: return eToggleButton; + default: return eButton; + } + } + virtual const char* getText() const + { + switch( mIndex ) { + case 0: return "Cleanup"; + case 1: return "Polygons"; + case 2: return "Caulk"; + case 3: return "Tree Planter"; + case 4: return "Plot Splines"; + case 5: return "Drop Entity"; + case 6: return "Merge Patches"; + case 7: return "Split Patches"; + case 8: return "Flip Terrain"; + } + return NULL; + } + virtual const char* getTooltip() const + { + switch( mIndex ) { + case 0: return "Brush Cleanup"; + case 1: return "Polygons"; + case 2: return "Caulk selection"; + case 3: return "Tree Planter"; + case 4: return "Plot Splines"; + case 5: return "Drop Entity"; + case 6: return "Merge Patches"; + case 7: return "Split Patches"; + case 8: return "Flip Terrain"; + } + return NULL; + } + + virtual void activate() const + { + LoadLists(); + + switch( mIndex ) { + case 0: DoFixBrushes(); break; + case 1: DoPolygonsTB(); break; + case 2: DoCaulkSelection(); break; + case 3: DoTreePlanter(); break; + case 4: DoTrainPathPlot(); break; + case 5: DoDropEnts(); break; + case 6: DoMergePatches(); break; + case 7: DoSplitPatch(); break; + case 8: DoFlipTerrain(); break; + } + } + + int mIndex; +}; + +CBobtoolzToolbarButton g_bobtoolzToolbarButtons[NUM_TOOLBARBUTTONS]; + +const IToolbarButton* GetToolbarButton(unsigned int index) +{ + g_bobtoolzToolbarButtons[index].mIndex = index; + return &g_bobtoolzToolbarButtons[index]; +} + +// ============================================================================= +// SYNAPSE + +class CSynapseClientBobtoolz : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + + CSynapseClientBobtoolz() { } + virtual ~CSynapseClientBobtoolz() { } +}; + + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientBobtoolz 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, BOBTOOLZ_MINOR, sizeof(_QERPlugToolbarTable)); + g_SynapseClient.AddAPI(PLUGIN_MAJOR, BOBTOOLZ_MINOR, sizeof(_QERPluginTable)); + + g_SynapseClient.AddAPI(DATA_MAJOR, NULL, sizeof(g_AppDataTable), SYN_REQUIRE, &g_AppDataTable); + g_SynapseClient.AddAPI(BRUSH_MAJOR, NULL, sizeof(g_BrushTable), SYN_REQUIRE, &g_BrushTable); + g_SynapseClient.AddAPI(SHADERS_MAJOR, "*", sizeof(g_ShadersTable), SYN_REQUIRE, &g_ShadersTable); + g_SynapseClient.AddAPI(ENTITY_MAJOR, NULL, sizeof(g_EntityTable), SYN_REQUIRE, &g_EntityTable); + g_SynapseClient.AddAPI(SELECTEDFACE_MAJOR, NULL, sizeof(g_SelectedFaceTable), SYN_REQUIRE, &g_SelectedFaceTable); + g_SynapseClient.AddAPI(UI_MAJOR, NULL, sizeof(g_MessageTable), SYN_REQUIRE, &g_MessageTable); + 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); + + return &g_SynapseClient; +} + +bool CSynapseClientBobtoolz::RequestAPI(APIDescriptor_t *pAPI) +{ + if( !strcmp(pAPI->minor_name, BOBTOOLZ_MINOR) ) + { + 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; + } + else 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* CSynapseClientBobtoolz::GetInfo() +{ + return "bobToolz module built " __DATE__ " " RADIANT_VERSION; +} + +char* GetFilename(char* buffer, const char* filename) { + strcpy(buffer, g_pSynapseServer->GetModuleFilename(&g_SynapseClient)); + StripFilename( buffer ); + strcat(buffer, "/"); + strcat(buffer, filename); + buffer = UnixToDosPath(buffer); + return buffer; +} diff --git a/contrib/bobtoolz/bsploader.cpp b/contrib/bobtoolz/bsploader.cpp index 5c2ee582..2fc05afd 100644 --- a/contrib/bobtoolz/bsploader.cpp +++ b/contrib/bobtoolz/bsploader.cpp @@ -1,258 +1,258 @@ -#include "StdAfx.h" -#include "./dialogs/dialogs-gtk.h" -#include "bsploader.h" -#include "../../libs/cmdlib.h" - -int numnodes; -int numplanes; -int numleafs; -int numleafsurfaces; -int numVisBytes; -int numDrawVerts; -int numDrawSurfaces; -int numbrushes; -int numbrushsides; -int numleafbrushes; - -byte *visBytes = NULL; -dnode_t *dnodes = NULL; -dplane_t *dplanes = NULL; -dleaf_t *dleafs = NULL; -qdrawVert_t *drawVerts = NULL; -dsurface_t *drawSurfaces = NULL; -int *dleafsurfaces = NULL; -dbrush_t *dbrushes = NULL; -dbrushside_t *dbrushsides = NULL; -int *dleafbrushes = NULL; - -#define BSP_IDENT (('P'<<24)+('S'<<16)+('B'<<8)+'I') -#define Q3_BSP_VERSION 46 -#define WOLF_BSP_VERSION 47 - -/* -================ -FileLength -================ -*/ -int FileLength (FILE *f) -{ - int pos; - int end; - - pos = ftell (f); - fseek (f, 0, SEEK_END); - end = ftell (f); - fseek (f, pos, SEEK_SET); - - return end; -} - -/* -============== -LoadFile -============== -*/ -qboolean LoadFile( const char *filename, byte **bufferptr) -{ - FILE *f; - int length; - byte *buffer; - - f = fopen(filename, "rb"); - if(!f) - return false; - - length = FileLength (f); - buffer = new byte[length+1]; - buffer[length] = 0; - fread(buffer, 1, length, f); - fclose (f); - - *bufferptr = buffer; - return true; -} - -/*int LittleLong (int l) -{ - return l; -} - -float LittleFloat (float l) -{ - return l; -}*/ - -/* -============= -SwapBlock - -If all values are 32 bits, this can be used to swap everything -============= -*/ -void SwapBlock( int *block, int sizeOfBlock ) { - int i; - - sizeOfBlock >>= 2; - for ( i = 0 ; i < sizeOfBlock ; i++ ) { - block[i] = LittleLong( block[i] ); - } -} - -/* -============= -SwapBSPFile - -Byte swaps all data in a bsp file. -============= -*/ -void SwapBSPFile( void ) { - int i; - - // models -// SwapBlock( (int *)dmodels, nummodels * sizeof( dmodels[0] ) ); - - // shaders (don't swap the name) -// for ( i = 0 ; i < numShaders ; i++ ) { -// dshaders[i].contentFlags = LittleLong( dshaders[i].contentFlags ); -// dshaders[i].surfaceFlags = LittleLong( dshaders[i].surfaceFlags ); -// } - - // planes - SwapBlock( (int *)dplanes, numplanes * sizeof( dplanes[0] ) ); - - // nodes - SwapBlock( (int *)dnodes, numnodes * sizeof( dnodes[0] ) ); - - // leafs - SwapBlock( (int *)dleafs, numleafs * sizeof( dleafs[0] ) ); - - // leaffaces - SwapBlock( (int *)dleafsurfaces, numleafsurfaces * sizeof( dleafsurfaces[0] ) ); - - // leafbrushes - SwapBlock( (int *)dleafbrushes, numleafbrushes * sizeof( dleafbrushes[0] ) ); - - // brushes - SwapBlock( (int *)dbrushes, numbrushes * sizeof( dbrushes[0] ) ); - - // brushsides - SwapBlock( (int *)dbrushsides, numbrushsides * sizeof( dbrushsides[0] ) ); - - // vis - ((int *)&visBytes)[0] = LittleLong( ((int *)&visBytes)[0] ); - ((int *)&visBytes)[1] = LittleLong( ((int *)&visBytes)[1] ); - - // drawverts (don't swap colors ) - for ( i = 0 ; i < numDrawVerts ; i++ ) { - drawVerts[i].lightmap[0] = LittleFloat( drawVerts[i].lightmap[0] ); - drawVerts[i].lightmap[1] = LittleFloat( drawVerts[i].lightmap[1] ); - drawVerts[i].st[0] = LittleFloat( drawVerts[i].st[0] ); - drawVerts[i].st[1] = LittleFloat( drawVerts[i].st[1] ); - drawVerts[i].xyz[0] = LittleFloat( drawVerts[i].xyz[0] ); - drawVerts[i].xyz[1] = LittleFloat( drawVerts[i].xyz[1] ); - drawVerts[i].xyz[2] = LittleFloat( drawVerts[i].xyz[2] ); - drawVerts[i].normal[0] = LittleFloat( drawVerts[i].normal[0] ); - drawVerts[i].normal[1] = LittleFloat( drawVerts[i].normal[1] ); - drawVerts[i].normal[2] = LittleFloat( drawVerts[i].normal[2] ); - } - - // drawindexes -// SwapBlock( (int *)drawIndexes, numDrawIndexes * sizeof( drawIndexes[0] ) ); - - // drawsurfs - SwapBlock( (int *)drawSurfaces, numDrawSurfaces * sizeof( drawSurfaces[0] ) ); - - // fogs -// for ( i = 0 ; i < numFogs ; i++ ) { -// dfogs[i].brushNum = LittleLong( dfogs[i].brushNum ); -// dfogs[i].visibleSide = LittleLong( dfogs[i].visibleSide ); -// } -} - -/* -============= -CopyLump -============= -*/ -int CopyLump( dheader_t *header, int lump, void **dest, int size ) { - int length, ofs; - - length = header->lumps[lump].filelen; - ofs = header->lumps[lump].fileofs; - - if(length == 0) - return 0; - - *dest = new byte[length]; - memcpy( *dest, (byte *)header + ofs, length ); - - return length / size; -} - -/* -============= -LoadBSPFile -============= -*/ -qboolean LoadBSPFile( const char *filename ) { - dheader_t *header; - - // load the file header - if(!LoadFile (filename, (byte **)&header)) - return false; - - // swap the header - SwapBlock( (int *)header, sizeof(*header) ); - - if ( header->ident != BSP_IDENT ) { - DoMessageBox( "Cant find a valid IBSP file", "Error", MB_OK); - return false; - } - if ( (header->version != Q3_BSP_VERSION) && - (header->version != WOLF_BSP_VERSION) ) { - DoMessageBox( "File is incorrect version", "Error", MB_OK); - return false; - } - - numbrushsides = CopyLump( header, LUMP_BRUSHES, (void**)&dbrushsides, sizeof(dbrushside_t) ); - numbrushes = CopyLump( header, LUMP_BRUSHES, (void**)&dbrushes, sizeof(dbrush_t) ); - numplanes = CopyLump( header, LUMP_PLANES, (void**)&dplanes, sizeof(dplane_t) ); - numleafs = CopyLump( header, LUMP_LEAFS, (void**)&dleafs, sizeof(dleaf_t) ); - numnodes = CopyLump( header, LUMP_NODES, (void**)&dnodes, sizeof(dnode_t) ); - numDrawVerts = CopyLump( header, LUMP_DRAWVERTS, (void**)&drawVerts, sizeof(qdrawVert_t) ); - numDrawSurfaces = CopyLump( header, LUMP_SURFACES, (void**)&drawSurfaces, sizeof(dsurface_t) ); - numleafsurfaces = CopyLump( header, LUMP_LEAFSURFACES, (void**)&dleafsurfaces, sizeof(int) ); - numVisBytes = CopyLump( header, LUMP_VISIBILITY, (void**)&visBytes, 1 ); - numleafbrushes = CopyLump( header, LUMP_LEAFBRUSHES, (void**)&dleafbrushes, sizeof(int) ); - - delete header; // everything has been copied out - - // swap everything - SwapBSPFile(); - - return true; -} - -void FreeBSPData() -{ - if(visBytes) - delete visBytes; - if(dnodes) - delete dnodes; - if(dplanes) - delete dplanes; - if(dleafs) - delete dleafs; - if(drawVerts) - delete drawVerts; - if(drawSurfaces) - delete drawSurfaces; - if(dleafsurfaces) - delete dleafsurfaces; - if(dleafbrushes) - delete dleafbrushes; - if(dbrushes) - delete dbrushes; - if(dbrushsides) - delete dbrushsides; -} +#include "StdAfx.h" +#include "./dialogs/dialogs-gtk.h" +#include "bsploader.h" +#include "../../libs/cmdlib.h" + +int numnodes; +int numplanes; +int numleafs; +int numleafsurfaces; +int numVisBytes; +int numDrawVerts; +int numDrawSurfaces; +int numbrushes; +int numbrushsides; +int numleafbrushes; + +byte *visBytes = NULL; +dnode_t *dnodes = NULL; +dplane_t *dplanes = NULL; +dleaf_t *dleafs = NULL; +qdrawVert_t *drawVerts = NULL; +dsurface_t *drawSurfaces = NULL; +int *dleafsurfaces = NULL; +dbrush_t *dbrushes = NULL; +dbrushside_t *dbrushsides = NULL; +int *dleafbrushes = NULL; + +#define BSP_IDENT (('P'<<24)+('S'<<16)+('B'<<8)+'I') +#define Q3_BSP_VERSION 46 +#define WOLF_BSP_VERSION 47 + +/* +================ +FileLength +================ +*/ +int FileLength (FILE *f) +{ + int pos; + int end; + + pos = ftell (f); + fseek (f, 0, SEEK_END); + end = ftell (f); + fseek (f, pos, SEEK_SET); + + return end; +} + +/* +============== +LoadFile +============== +*/ +qboolean LoadFile( const char *filename, byte **bufferptr) +{ + FILE *f; + int length; + byte *buffer; + + f = fopen(filename, "rb"); + if(!f) + return false; + + length = FileLength (f); + buffer = new byte[length+1]; + buffer[length] = 0; + fread(buffer, 1, length, f); + fclose (f); + + *bufferptr = buffer; + return true; +} + +/*int LittleLong (int l) +{ + return l; +} + +float LittleFloat (float l) +{ + return l; +}*/ + +/* +============= +SwapBlock + +If all values are 32 bits, this can be used to swap everything +============= +*/ +void SwapBlock( int *block, int sizeOfBlock ) { + int i; + + sizeOfBlock >>= 2; + for ( i = 0 ; i < sizeOfBlock ; i++ ) { + block[i] = LittleLong( block[i] ); + } +} + +/* +============= +SwapBSPFile + +Byte swaps all data in a bsp file. +============= +*/ +void SwapBSPFile( void ) { + int i; + + // models +// SwapBlock( (int *)dmodels, nummodels * sizeof( dmodels[0] ) ); + + // shaders (don't swap the name) +// for ( i = 0 ; i < numShaders ; i++ ) { +// dshaders[i].contentFlags = LittleLong( dshaders[i].contentFlags ); +// dshaders[i].surfaceFlags = LittleLong( dshaders[i].surfaceFlags ); +// } + + // planes + SwapBlock( (int *)dplanes, numplanes * sizeof( dplanes[0] ) ); + + // nodes + SwapBlock( (int *)dnodes, numnodes * sizeof( dnodes[0] ) ); + + // leafs + SwapBlock( (int *)dleafs, numleafs * sizeof( dleafs[0] ) ); + + // leaffaces + SwapBlock( (int *)dleafsurfaces, numleafsurfaces * sizeof( dleafsurfaces[0] ) ); + + // leafbrushes + SwapBlock( (int *)dleafbrushes, numleafbrushes * sizeof( dleafbrushes[0] ) ); + + // brushes + SwapBlock( (int *)dbrushes, numbrushes * sizeof( dbrushes[0] ) ); + + // brushsides + SwapBlock( (int *)dbrushsides, numbrushsides * sizeof( dbrushsides[0] ) ); + + // vis + ((int *)&visBytes)[0] = LittleLong( ((int *)&visBytes)[0] ); + ((int *)&visBytes)[1] = LittleLong( ((int *)&visBytes)[1] ); + + // drawverts (don't swap colors ) + for ( i = 0 ; i < numDrawVerts ; i++ ) { + drawVerts[i].lightmap[0] = LittleFloat( drawVerts[i].lightmap[0] ); + drawVerts[i].lightmap[1] = LittleFloat( drawVerts[i].lightmap[1] ); + drawVerts[i].st[0] = LittleFloat( drawVerts[i].st[0] ); + drawVerts[i].st[1] = LittleFloat( drawVerts[i].st[1] ); + drawVerts[i].xyz[0] = LittleFloat( drawVerts[i].xyz[0] ); + drawVerts[i].xyz[1] = LittleFloat( drawVerts[i].xyz[1] ); + drawVerts[i].xyz[2] = LittleFloat( drawVerts[i].xyz[2] ); + drawVerts[i].normal[0] = LittleFloat( drawVerts[i].normal[0] ); + drawVerts[i].normal[1] = LittleFloat( drawVerts[i].normal[1] ); + drawVerts[i].normal[2] = LittleFloat( drawVerts[i].normal[2] ); + } + + // drawindexes +// SwapBlock( (int *)drawIndexes, numDrawIndexes * sizeof( drawIndexes[0] ) ); + + // drawsurfs + SwapBlock( (int *)drawSurfaces, numDrawSurfaces * sizeof( drawSurfaces[0] ) ); + + // fogs +// for ( i = 0 ; i < numFogs ; i++ ) { +// dfogs[i].brushNum = LittleLong( dfogs[i].brushNum ); +// dfogs[i].visibleSide = LittleLong( dfogs[i].visibleSide ); +// } +} + +/* +============= +CopyLump +============= +*/ +int CopyLump( dheader_t *header, int lump, void **dest, int size ) { + int length, ofs; + + length = header->lumps[lump].filelen; + ofs = header->lumps[lump].fileofs; + + if(length == 0) + return 0; + + *dest = new byte[length]; + memcpy( *dest, (byte *)header + ofs, length ); + + return length / size; +} + +/* +============= +LoadBSPFile +============= +*/ +qboolean LoadBSPFile( const char *filename ) { + dheader_t *header; + + // load the file header + if(!LoadFile (filename, (byte **)&header)) + return false; + + // swap the header + SwapBlock( (int *)header, sizeof(*header) ); + + if ( header->ident != BSP_IDENT ) { + DoMessageBox( "Cant find a valid IBSP file", "Error", MB_OK); + return false; + } + if ( (header->version != Q3_BSP_VERSION) && + (header->version != WOLF_BSP_VERSION) ) { + DoMessageBox( "File is incorrect version", "Error", MB_OK); + return false; + } + + numbrushsides = CopyLump( header, LUMP_BRUSHES, (void**)&dbrushsides, sizeof(dbrushside_t) ); + numbrushes = CopyLump( header, LUMP_BRUSHES, (void**)&dbrushes, sizeof(dbrush_t) ); + numplanes = CopyLump( header, LUMP_PLANES, (void**)&dplanes, sizeof(dplane_t) ); + numleafs = CopyLump( header, LUMP_LEAFS, (void**)&dleafs, sizeof(dleaf_t) ); + numnodes = CopyLump( header, LUMP_NODES, (void**)&dnodes, sizeof(dnode_t) ); + numDrawVerts = CopyLump( header, LUMP_DRAWVERTS, (void**)&drawVerts, sizeof(qdrawVert_t) ); + numDrawSurfaces = CopyLump( header, LUMP_SURFACES, (void**)&drawSurfaces, sizeof(dsurface_t) ); + numleafsurfaces = CopyLump( header, LUMP_LEAFSURFACES, (void**)&dleafsurfaces, sizeof(int) ); + numVisBytes = CopyLump( header, LUMP_VISIBILITY, (void**)&visBytes, 1 ); + numleafbrushes = CopyLump( header, LUMP_LEAFBRUSHES, (void**)&dleafbrushes, sizeof(int) ); + + delete header; // everything has been copied out + + // swap everything + SwapBSPFile(); + + return true; +} + +void FreeBSPData() +{ + if(visBytes) + delete visBytes; + if(dnodes) + delete dnodes; + if(dplanes) + delete dplanes; + if(dleafs) + delete dleafs; + if(drawVerts) + delete drawVerts; + if(drawSurfaces) + delete drawSurfaces; + if(dleafsurfaces) + delete dleafsurfaces; + if(dleafbrushes) + delete dleafbrushes; + if(dbrushes) + delete dbrushes; + if(dbrushsides) + delete dbrushsides; +} diff --git a/contrib/bobtoolz/cportals.cpp b/contrib/bobtoolz/cportals.cpp index d56c6b4c..d05591c3 100644 --- a/contrib/bobtoolz/cportals.cpp +++ b/contrib/bobtoolz/cportals.cpp @@ -1,340 +1,340 @@ -/* -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 -*/ - -#include "StdAfx.h" -#include "CPortals.h" -#include "misc.h" - -#define LINE_BUF 1000 -#define MSG_PREFIX "bobToolz plugin: " - -// these classes are far less of a mess than my code was, -// thanq to G.DeWan 4 the prtview source on which it was based - -CBspPortal::CBspPortal() -{ - memset(this, 0, sizeof(CBspPortal)); -} - -CBspPortal::~CBspPortal() -{ - delete[] point; -} - -void ClampFloat(float* p) -{ - double i; - double frac = modf(*p, &i); - - if(!frac) - return; - - if(fabs(*p - ceil(*p)) < MAX_ROUND_ERROR) - *p = ceilf(*p); - - if(fabs(*p - floor(*p)) < MAX_ROUND_ERROR) - *p = floorf(*p); -} - -bool CBspPortal::Build(char *def, unsigned int pointCnt, bool bInverse) -{ - char *c = def; - unsigned int n; - - point_count = pointCnt; - - if(point_count < 3) - return FALSE; - - point = new CBspPoint[point_count]; - - for(n = 0; n < point_count; n++) - { - for(; *c != 0 && *c != '('; c++); - - if(*c == 0) - return FALSE; - - c++; - - int x; - if(bInverse) - x = point_count - n - 1; - else - x = n; - - sscanf(c, "%f %f %f", &point[x].p[0], &point[x].p[1], &point[x].p[2]); - - ClampFloat(&point[x].p[0]); - ClampFloat(&point[x].p[1]); - ClampFloat(&point[x].p[2]); - } - - return TRUE; -} - -CPortals::CPortals() -{ - memset(this, 0, sizeof(CPortals)); -} - -CPortals::~CPortals() -{ - Purge(); -} - -void CPortals::Purge() -{ - if(node) - delete[] node; - node = NULL; - node_count = 0; -} - -void CPortals::Load() -{ - char buf[LINE_BUF+1]; - - memset(buf, 0, LINE_BUF + 1); - - Purge(); - - Sys_Printf(MSG_PREFIX "Loading portal file %s.\n", fn); - - FILE *in; - - in = fopen(fn, "rt"); - - if(in == NULL) - { - Sys_Printf(" ERROR - could not open file.\n"); - - return; - } - - if(!fgets(buf, LINE_BUF, in)) - { - fclose(in); - - Sys_Printf(" ERROR - File ended prematurely.\n"); - - return; - } - - if(strncmp("PRT1", buf, 4) != 0) - { - fclose(in); - - Sys_Printf(" ERROR - File header indicates wrong file type (should be \"PRT1\").\n"); - - return; - } - - if(!fgets(buf, LINE_BUF, in)) - { - fclose(in); - - Sys_Printf(" ERROR - File ended prematurely.\n"); - - return; - } - - sscanf(buf, "%u", &node_count); - - if(node_count > 0xFFFF) - { - fclose(in); - - node_count = 0; - - Sys_Printf(" ERROR - Extreme number of nodes, aborting.\n"); - - return; - } - - if(!fgets(buf, LINE_BUF, in)) - { - fclose(in); - - node_count = 0; - - Sys_Printf(" ERROR - File ended prematurely.\n"); - - return; - } - - unsigned int p_count; - sscanf(buf, "%u", &p_count); - - if(!fgets(buf, LINE_BUF, in)) - { - fclose(in); - - node_count = 0; - - Sys_Printf(" ERROR - File ended prematurely.\n"); - - return; - } - - unsigned int p_count2; - sscanf(buf, "%u", &p_count2); - - node = new CBspNode[node_count]; - - unsigned int i; - for(i = 0; i < p_count; i++) - { - if(!fgets(buf, LINE_BUF, in)) - { - fclose(in); - - node_count = 0; - - Sys_Printf(" ERROR - File ended prematurely.\n"); - - return; - } - - unsigned int dummy, node1, node2; - sscanf(buf, "%u %u %u", &dummy, &node1, &node2); - - node[node1].portal_count++; - node[node2].portal_count++; - } - - for(i = 0; i < p_count2; i++) - { - if(!fgets(buf, LINE_BUF, in)) - { - fclose(in); - - node_count = 0; - - Sys_Printf(" ERROR - File ended prematurely.\n"); - - return; - } - - unsigned int dummy, node1; - sscanf(buf, "%u %u", &dummy, &node1); - - node[node1].portal_count++; - } - - for(i = 0; i < node_count; i++) - node[i].portal = new CBspPortal[node[i].portal_count]; - - fclose(in); - - in = fopen(fn, "rt"); - - fgets(buf, LINE_BUF, in); - fgets(buf, LINE_BUF, in); - fgets(buf, LINE_BUF, in); - fgets(buf, LINE_BUF, in); - - unsigned int n; - for(n = 0; n < p_count; n++) - { - if(!fgets(buf, LINE_BUF, in)) - { - fclose(in); - - Purge(); - - Sys_Printf(" ERROR - Could not find information for portal number %d of %d.\n", n + 1, p_count); - - return; - } - - unsigned int pCount, node1, node2; - sscanf(buf, "%u %u %u", &pCount, &node1, &node2); - - if(!node[node1].AddPortal(buf, pCount, FALSE)) - { - fclose(in); - - Purge(); - - Sys_Printf(" ERROR - Information for portal number %d of %d is not formatted correctly.\n", n + 1, p_count); - - return; - } - - if(!node[node2].AddPortal(buf, pCount, TRUE)) - { - fclose(in); - - Purge(); - - Sys_Printf(" ERROR - Information for portal number %d of %d is not formatted correctly.\n", n + 1, p_count); - - return; - } - } - - for(n = 0; n < p_count2; n++) - { - if(!fgets(buf, LINE_BUF, in)) - { - fclose(in); - - Purge(); - - Sys_Printf(" ERROR - Could not find information for portal number %d of %d.\n", n + 1, p_count); - - return; - } - - unsigned int pCount, node1; - sscanf(buf, "%u %u", &pCount, &node1); - - if(!node[node1].AddPortal(buf, pCount, FALSE)) - { - fclose(in); - - Purge(); - - Sys_Printf(" ERROR - Information for portal number %d of %d is not formatted correctly.\n", n + 1, p_count); - - return; - } - } - - fclose(in); -} - -CBspNode::CBspNode() -{ - portal = NULL; - portal_count = 0; - portal_next = 0; -} - -CBspNode::~CBspNode() -{ - if(portal != NULL) - delete[] portal; -} - -bool CBspNode::AddPortal(char *def, unsigned int pointCnt, bool bInverse) -{ - return portal[portal_next++].Build(def, pointCnt, bInverse); -} +/* +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 +*/ + +#include "StdAfx.h" +#include "CPortals.h" +#include "misc.h" + +#define LINE_BUF 1000 +#define MSG_PREFIX "bobToolz plugin: " + +// these classes are far less of a mess than my code was, +// thanq to G.DeWan 4 the prtview source on which it was based + +CBspPortal::CBspPortal() +{ + memset(this, 0, sizeof(CBspPortal)); +} + +CBspPortal::~CBspPortal() +{ + delete[] point; +} + +void ClampFloat(float* p) +{ + double i; + double frac = modf(*p, &i); + + if(!frac) + return; + + if(fabs(*p - ceil(*p)) < MAX_ROUND_ERROR) + *p = ceilf(*p); + + if(fabs(*p - floor(*p)) < MAX_ROUND_ERROR) + *p = floorf(*p); +} + +bool CBspPortal::Build(char *def, unsigned int pointCnt, bool bInverse) +{ + char *c = def; + unsigned int n; + + point_count = pointCnt; + + if(point_count < 3) + return FALSE; + + point = new CBspPoint[point_count]; + + for(n = 0; n < point_count; n++) + { + for(; *c != 0 && *c != '('; c++); + + if(*c == 0) + return FALSE; + + c++; + + int x; + if(bInverse) + x = point_count - n - 1; + else + x = n; + + sscanf(c, "%f %f %f", &point[x].p[0], &point[x].p[1], &point[x].p[2]); + + ClampFloat(&point[x].p[0]); + ClampFloat(&point[x].p[1]); + ClampFloat(&point[x].p[2]); + } + + return TRUE; +} + +CPortals::CPortals() +{ + memset(this, 0, sizeof(CPortals)); +} + +CPortals::~CPortals() +{ + Purge(); +} + +void CPortals::Purge() +{ + if(node) + delete[] node; + node = NULL; + node_count = 0; +} + +void CPortals::Load() +{ + char buf[LINE_BUF+1]; + + memset(buf, 0, LINE_BUF + 1); + + Purge(); + + Sys_Printf(MSG_PREFIX "Loading portal file %s.\n", fn); + + FILE *in; + + in = fopen(fn, "rt"); + + if(in == NULL) + { + Sys_Printf(" ERROR - could not open file.\n"); + + return; + } + + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + if(strncmp("PRT1", buf, 4) != 0) + { + fclose(in); + + Sys_Printf(" ERROR - File header indicates wrong file type (should be \"PRT1\").\n"); + + return; + } + + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + sscanf(buf, "%u", &node_count); + + if(node_count > 0xFFFF) + { + fclose(in); + + node_count = 0; + + Sys_Printf(" ERROR - Extreme number of nodes, aborting.\n"); + + return; + } + + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + node_count = 0; + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + unsigned int p_count; + sscanf(buf, "%u", &p_count); + + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + node_count = 0; + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + unsigned int p_count2; + sscanf(buf, "%u", &p_count2); + + node = new CBspNode[node_count]; + + unsigned int i; + for(i = 0; i < p_count; i++) + { + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + node_count = 0; + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + unsigned int dummy, node1, node2; + sscanf(buf, "%u %u %u", &dummy, &node1, &node2); + + node[node1].portal_count++; + node[node2].portal_count++; + } + + for(i = 0; i < p_count2; i++) + { + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + node_count = 0; + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + unsigned int dummy, node1; + sscanf(buf, "%u %u", &dummy, &node1); + + node[node1].portal_count++; + } + + for(i = 0; i < node_count; i++) + node[i].portal = new CBspPortal[node[i].portal_count]; + + fclose(in); + + in = fopen(fn, "rt"); + + fgets(buf, LINE_BUF, in); + fgets(buf, LINE_BUF, in); + fgets(buf, LINE_BUF, in); + fgets(buf, LINE_BUF, in); + + unsigned int n; + for(n = 0; n < p_count; n++) + { + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + Purge(); + + Sys_Printf(" ERROR - Could not find information for portal number %d of %d.\n", n + 1, p_count); + + return; + } + + unsigned int pCount, node1, node2; + sscanf(buf, "%u %u %u", &pCount, &node1, &node2); + + if(!node[node1].AddPortal(buf, pCount, FALSE)) + { + fclose(in); + + Purge(); + + Sys_Printf(" ERROR - Information for portal number %d of %d is not formatted correctly.\n", n + 1, p_count); + + return; + } + + if(!node[node2].AddPortal(buf, pCount, TRUE)) + { + fclose(in); + + Purge(); + + Sys_Printf(" ERROR - Information for portal number %d of %d is not formatted correctly.\n", n + 1, p_count); + + return; + } + } + + for(n = 0; n < p_count2; n++) + { + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + Purge(); + + Sys_Printf(" ERROR - Could not find information for portal number %d of %d.\n", n + 1, p_count); + + return; + } + + unsigned int pCount, node1; + sscanf(buf, "%u %u", &pCount, &node1); + + if(!node[node1].AddPortal(buf, pCount, FALSE)) + { + fclose(in); + + Purge(); + + Sys_Printf(" ERROR - Information for portal number %d of %d is not formatted correctly.\n", n + 1, p_count); + + return; + } + } + + fclose(in); +} + +CBspNode::CBspNode() +{ + portal = NULL; + portal_count = 0; + portal_next = 0; +} + +CBspNode::~CBspNode() +{ + if(portal != NULL) + delete[] portal; +} + +bool CBspNode::AddPortal(char *def, unsigned int pointCnt, bool bInverse) +{ + return portal[portal_next++].Build(def, pointCnt, bInverse); +} diff --git a/contrib/bobtoolz/ctfToolz-GTK.cpp b/contrib/bobtoolz/ctfToolz-GTK.cpp index e73a27d0..271931ab 100644 --- a/contrib/bobtoolz/ctfToolz-GTK.cpp +++ b/contrib/bobtoolz/ctfToolz-GTK.cpp @@ -1,97 +1,97 @@ -/* -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 -*/ - -#include "StdAfx.h" - -#include "funchandlers.h" -#include "misc.h" - -#include "dialogs/dialogs-gtk.h" - -// Radiant function table -_QERFuncTable_1 g_FuncTable; -_QERAppBSPFrontendTable g_BSPTable; // for map name - -BOOL g_bBSPInitDone = FALSE; - -// plugin name -static const char *PLUGIN_NAME = "ctfToolz"; - -// commands in the menu -static const char *PLUGIN_COMMANDS = "About...,Colour Changer...,Swap Light Colours,Change Angles 180,Swap Spawn Points"; - -// globals -GtkWidget *g_pRadiantWnd=NULL; - -static const char *PLUGIN_ABOUT = "ctfToolz for GtkRadiant\n" - "by djbob\n" - "http://www.planetquake.com/toolz\n\n"; - -extern "C" LPVOID WINAPI QERPlug_GetFuncTable() -{ - return &g_FuncTable; -} - -extern "C" LPCSTR WINAPI QERPlug_Init(HMODULE hApp, GtkWidget* pMainWidget) -{ - g_pRadiantWnd = pMainWidget; - memset(&g_FuncTable, 0, sizeof(_QERFuncTable_1)); - g_FuncTable.m_fVersion = QER_PLUG_VERSION; - g_FuncTable.m_nSize = sizeof(_QERFuncTable_1); - - return "ctfToolz for GTKradiant"; -} - -extern "C" LPCSTR WINAPI QERPlug_GetName() -{ - return (char*)PLUGIN_NAME; -} - -extern "C" LPCSTR WINAPI QERPlug_GetCommandList() -{ - return (char*)PLUGIN_COMMANDS; -} - -extern "C" void WINAPI QERPlug_Dispatch (LPCSTR p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) -{ - LoadLists(); - - if (!g_bBSPInitDone) - { - g_BSPTable.m_nSize = sizeof(_QERAppBSPFrontendTable); - if ( g_FuncTable.m_pfnRequestInterface( QERAppBSPFrontendTable_GUID, static_cast(&g_BSPTable) ) ) - g_bBSPInitDone = TRUE; - else - { - Sys_ERROR("_QERAppBSPFrontendTable interface request failed\n"); - return; - } - } - - if(!strcmp(p, "About...")) - DoMessageBox(PLUGIN_ABOUT, "About", IDOK); - else if(!strcmp(p, "Colour Changer...")) - DoCTFColourChanger(); - else if(!strcmp(p, "Swap Light Colours")) - DoSwapLights(); - else if(!strcmp(p, "Change Angles 180")) - DoChangeAngles(); - else if(!strcmp(p, "Swap Spawn Points")) - DoSwapSpawns(); -} +/* +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 +*/ + +#include "StdAfx.h" + +#include "funchandlers.h" +#include "misc.h" + +#include "dialogs/dialogs-gtk.h" + +// Radiant function table +_QERFuncTable_1 g_FuncTable; +_QERAppBSPFrontendTable g_BSPTable; // for map name + +BOOL g_bBSPInitDone = FALSE; + +// plugin name +static const char *PLUGIN_NAME = "ctfToolz"; + +// commands in the menu +static const char *PLUGIN_COMMANDS = "About...,Colour Changer...,Swap Light Colours,Change Angles 180,Swap Spawn Points"; + +// globals +GtkWidget *g_pRadiantWnd=NULL; + +static const char *PLUGIN_ABOUT = "ctfToolz for GtkRadiant\n" + "by djbob\n" + "http://www.planetquake.com/toolz\n\n"; + +extern "C" LPVOID WINAPI QERPlug_GetFuncTable() +{ + return &g_FuncTable; +} + +extern "C" LPCSTR WINAPI QERPlug_Init(HMODULE hApp, GtkWidget* pMainWidget) +{ + g_pRadiantWnd = pMainWidget; + memset(&g_FuncTable, 0, sizeof(_QERFuncTable_1)); + g_FuncTable.m_fVersion = QER_PLUG_VERSION; + g_FuncTable.m_nSize = sizeof(_QERFuncTable_1); + + return "ctfToolz for GTKradiant"; +} + +extern "C" LPCSTR WINAPI QERPlug_GetName() +{ + return (char*)PLUGIN_NAME; +} + +extern "C" LPCSTR WINAPI QERPlug_GetCommandList() +{ + return (char*)PLUGIN_COMMANDS; +} + +extern "C" void WINAPI QERPlug_Dispatch (LPCSTR p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) +{ + LoadLists(); + + if (!g_bBSPInitDone) + { + g_BSPTable.m_nSize = sizeof(_QERAppBSPFrontendTable); + if ( g_FuncTable.m_pfnRequestInterface( QERAppBSPFrontendTable_GUID, static_cast(&g_BSPTable) ) ) + g_bBSPInitDone = TRUE; + else + { + Sys_ERROR("_QERAppBSPFrontendTable interface request failed\n"); + return; + } + } + + if(!strcmp(p, "About...")) + DoMessageBox(PLUGIN_ABOUT, "About", IDOK); + else if(!strcmp(p, "Colour Changer...")) + DoCTFColourChanger(); + else if(!strcmp(p, "Swap Light Colours")) + DoSwapLights(); + else if(!strcmp(p, "Change Angles 180")) + DoChangeAngles(); + else if(!strcmp(p, "Swap Spawn Points")) + DoSwapSpawns(); +} diff --git a/contrib/bobtoolz/dialogs/AboutDialog.cpp b/contrib/bobtoolz/dialogs/AboutDialog.cpp index 250a231c..e5d37038 100644 --- a/contrib/bobtoolz/dialogs/AboutDialog.cpp +++ b/contrib/bobtoolz/dialogs/AboutDialog.cpp @@ -1,62 +1,62 @@ -/* -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 -*/ - -// AboutDialog.cpp : implementation file -// - -#include "../StdAfx.h" -#include "AboutDialog.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -//static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CAboutDialog dialog - - -CAboutDialog::CAboutDialog(CWnd* pParent /*=NULL*/) - : CDialog(CAboutDialog::IDD, pParent) -{ - //{{AFX_DATA_INIT(CAboutDialog) - // NOTE: the ClassWizard will add member initialization here - //}}AFX_DATA_INIT -} - - -void CAboutDialog::DoDataExchange(CDataExchange* pDX) -{ - CDialog::DoDataExchange(pDX); - //{{AFX_DATA_MAP(CAboutDialog) - // NOTE: the ClassWizard will add DDX and DDV calls here - //}}AFX_DATA_MAP -} - - -BEGIN_MESSAGE_MAP(CAboutDialog, CDialog) - //{{AFX_MSG_MAP(CAboutDialog) - // NOTE: the ClassWizard will add message map macros here - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CAboutDialog message handlers - +/* +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 +*/ + +// AboutDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "AboutDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +//static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CAboutDialog dialog + + +CAboutDialog::CAboutDialog(CWnd* pParent /*=NULL*/) + : CDialog(CAboutDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CAboutDialog) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT +} + + +void CAboutDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAboutDialog) + // NOTE: the ClassWizard will add DDX and DDV calls here + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CAboutDialog, CDialog) + //{{AFX_MSG_MAP(CAboutDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CAboutDialog message handlers + diff --git a/contrib/bobtoolz/dialogs/AutoCaulkDialog.cpp b/contrib/bobtoolz/dialogs/AutoCaulkDialog.cpp index ba5f109c..fd46b7fb 100644 --- a/contrib/bobtoolz/dialogs/AutoCaulkDialog.cpp +++ b/contrib/bobtoolz/dialogs/AutoCaulkDialog.cpp @@ -1,63 +1,63 @@ -/* -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 -*/ - -// AutoCaulkDialog.cpp : implementation file -// - -#include "../StdAfx.h" -#include "../bobtoolz.h" -#include "AutoCaulkDialog.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CAutoCaulkDialog dialog - - -CAutoCaulkDialog::CAutoCaulkDialog(CWnd* pParent /*=NULL*/) - : CDialog(CAutoCaulkDialog::IDD, pParent) -{ - //{{AFX_DATA_INIT(CAutoCaulkDialog) - // NOTE: the ClassWizard will add member initialization here - //}}AFX_DATA_INIT -} - - -void CAutoCaulkDialog::DoDataExchange(CDataExchange* pDX) -{ - CDialog::DoDataExchange(pDX); - //{{AFX_DATA_MAP(CAutoCaulkDialog) - DDX_Control(pDX, IDC_PROGRESS2, m_prog2); - DDX_Control(pDX, IDC_PROGRESS1, m_prog1); - //}}AFX_DATA_MAP -} - - -BEGIN_MESSAGE_MAP(CAutoCaulkDialog, CDialog) - //{{AFX_MSG_MAP(CAutoCaulkDialog) - // NOTE: the ClassWizard will add message map macros here - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CAutoCaulkDialog message handlers +/* +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 +*/ + +// AutoCaulkDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "../bobtoolz.h" +#include "AutoCaulkDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CAutoCaulkDialog dialog + + +CAutoCaulkDialog::CAutoCaulkDialog(CWnd* pParent /*=NULL*/) + : CDialog(CAutoCaulkDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CAutoCaulkDialog) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT +} + + +void CAutoCaulkDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAutoCaulkDialog) + DDX_Control(pDX, IDC_PROGRESS2, m_prog2); + DDX_Control(pDX, IDC_PROGRESS1, m_prog1); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CAutoCaulkDialog, CDialog) + //{{AFX_MSG_MAP(CAutoCaulkDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CAutoCaulkDialog message handlers diff --git a/contrib/bobtoolz/dialogs/AutoCaulkStartDialog.cpp b/contrib/bobtoolz/dialogs/AutoCaulkStartDialog.cpp index 3eca76f8..857df71a 100644 --- a/contrib/bobtoolz/dialogs/AutoCaulkStartDialog.cpp +++ b/contrib/bobtoolz/dialogs/AutoCaulkStartDialog.cpp @@ -1,66 +1,66 @@ -/* -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 -*/ - -// AutoCaulkStartDialog.cpp : implementation file -// - -#include "../StdAfx.h" -#include "../bobtoolz.h" -#include "AutoCaulkStartDialog.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CAutoCaulkStartDialog dialog - - -CAutoCaulkStartDialog::CAutoCaulkStartDialog(CWnd* pParent /*=NULL*/) - : CDialog(CAutoCaulkStartDialog::IDD, pParent) -{ - //{{AFX_DATA_INIT(CAutoCaulkStartDialog) - m_bAllowDestruction = FALSE; - m_Warning1 = _T(""); - m_nMode = 0; - //}}AFX_DATA_INIT -} - - -void CAutoCaulkStartDialog::DoDataExchange(CDataExchange* pDX) -{ - CDialog::DoDataExchange(pDX); - //{{AFX_DATA_MAP(CAutoCaulkStartDialog) - DDX_Check(pDX, IDC_KILLBRUSHES_CHECK, m_bAllowDestruction); - DDX_Text(pDX, IDC_WARNING1_STATIC, m_Warning1); - DDX_Radio(pDX, IDC_AC_NORMAL_RADIO, m_nMode); - //}}AFX_DATA_MAP -} - - -BEGIN_MESSAGE_MAP(CAutoCaulkStartDialog, CDialog) - //{{AFX_MSG_MAP(CAutoCaulkStartDialog) - // NOTE: the ClassWizard will add message map macros here - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CAutoCaulkStartDialog message handlers +/* +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 +*/ + +// AutoCaulkStartDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "../bobtoolz.h" +#include "AutoCaulkStartDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CAutoCaulkStartDialog dialog + + +CAutoCaulkStartDialog::CAutoCaulkStartDialog(CWnd* pParent /*=NULL*/) + : CDialog(CAutoCaulkStartDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CAutoCaulkStartDialog) + m_bAllowDestruction = FALSE; + m_Warning1 = _T(""); + m_nMode = 0; + //}}AFX_DATA_INIT +} + + +void CAutoCaulkStartDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAutoCaulkStartDialog) + DDX_Check(pDX, IDC_KILLBRUSHES_CHECK, m_bAllowDestruction); + DDX_Text(pDX, IDC_WARNING1_STATIC, m_Warning1); + DDX_Radio(pDX, IDC_AC_NORMAL_RADIO, m_nMode); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CAutoCaulkStartDialog, CDialog) + //{{AFX_MSG_MAP(CAutoCaulkStartDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CAutoCaulkStartDialog message handlers diff --git a/contrib/bobtoolz/dialogs/DoorDialog.cpp b/contrib/bobtoolz/dialogs/DoorDialog.cpp index 159d6e15..2a1829d5 100644 --- a/contrib/bobtoolz/dialogs/DoorDialog.cpp +++ b/contrib/bobtoolz/dialogs/DoorDialog.cpp @@ -1,92 +1,92 @@ -/* -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 -*/ - -// DoorDialog.cpp : implementation file -// - -#include "../StdAfx.h" -#include "DoorDialog.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CDoorDialog dialog - - -CDoorDialog::CDoorDialog(CWnd* pParent /*=NULL*/) - : CDialog(CDoorDialog::IDD, pParent) -{ - //{{AFX_DATA_INIT(CDoorDialog) - m_fbTextureName = _T(""); - m_bSclMainHor = TRUE; - m_bSclMainVert = TRUE; - m_bSclTrimHor = TRUE; - m_bSclTrimVert = FALSE; - m_trimTextureName = _T(""); - m_trimTexSetBox = _T(""); - m_mainTexSetBox = _T(""); - m_doorDirection = -1; - //}}AFX_DATA_INIT -} - - -void CDoorDialog::DoDataExchange(CDataExchange* pDX) -{ - CDialog::DoDataExchange(pDX); - //{{AFX_DATA_MAP(CDoorDialog) - DDX_Text(pDX, IDC_FBTEXTURE_EDIT, m_fbTextureName); - DDX_Check(pDX, IDC_TEXSCALE1_CHECK, m_bSclMainHor); - DDX_Check(pDX, IDC_TEXSCALE2_CHECK, m_bSclMainVert); - DDX_Check(pDX, IDC_TEXSCALE3_CHECK, m_bSclTrimHor); - DDX_Check(pDX, IDC_TEXSCALE4_CHECK, m_bSclTrimVert); - DDX_Text(pDX, IDC_TRIMTEXTURE_EDIT, m_trimTextureName); - DDX_CBString(pDX, IDC_TRIMTEX_COMBO, m_trimTexSetBox); - DDX_CBString(pDX, IDC_MAINTEX_COMBO, m_mainTexSetBox); - DDX_Radio(pDX, IDC_DIR_NS_RADIO, m_doorDirection); - //}}AFX_DATA_MAP -} - - -BEGIN_MESSAGE_MAP(CDoorDialog, CDialog) - //{{AFX_MSG_MAP(CDoorDialog) - ON_BN_CLICKED(IDC_SET_MAINTEX_BTN, OnSetMaintexBtn) - ON_BN_CLICKED(IDC_SET_TRIMTEX_BTN, OnSetTrimtexBtn) - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CDoorDialog message handlers - -void CDoorDialog::OnSetMaintexBtn() -{ - UpdateData(TRUE); - m_fbTextureName = m_mainTexSetBox; - UpdateData(FALSE); -} - -void CDoorDialog::OnSetTrimtexBtn() -{ - UpdateData(TRUE); - m_trimTextureName = m_trimTexSetBox; - UpdateData(FALSE); -} +/* +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 +*/ + +// DoorDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "DoorDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CDoorDialog dialog + + +CDoorDialog::CDoorDialog(CWnd* pParent /*=NULL*/) + : CDialog(CDoorDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CDoorDialog) + m_fbTextureName = _T(""); + m_bSclMainHor = TRUE; + m_bSclMainVert = TRUE; + m_bSclTrimHor = TRUE; + m_bSclTrimVert = FALSE; + m_trimTextureName = _T(""); + m_trimTexSetBox = _T(""); + m_mainTexSetBox = _T(""); + m_doorDirection = -1; + //}}AFX_DATA_INIT +} + + +void CDoorDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CDoorDialog) + DDX_Text(pDX, IDC_FBTEXTURE_EDIT, m_fbTextureName); + DDX_Check(pDX, IDC_TEXSCALE1_CHECK, m_bSclMainHor); + DDX_Check(pDX, IDC_TEXSCALE2_CHECK, m_bSclMainVert); + DDX_Check(pDX, IDC_TEXSCALE3_CHECK, m_bSclTrimHor); + DDX_Check(pDX, IDC_TEXSCALE4_CHECK, m_bSclTrimVert); + DDX_Text(pDX, IDC_TRIMTEXTURE_EDIT, m_trimTextureName); + DDX_CBString(pDX, IDC_TRIMTEX_COMBO, m_trimTexSetBox); + DDX_CBString(pDX, IDC_MAINTEX_COMBO, m_mainTexSetBox); + DDX_Radio(pDX, IDC_DIR_NS_RADIO, m_doorDirection); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CDoorDialog, CDialog) + //{{AFX_MSG_MAP(CDoorDialog) + ON_BN_CLICKED(IDC_SET_MAINTEX_BTN, OnSetMaintexBtn) + ON_BN_CLICKED(IDC_SET_TRIMTEX_BTN, OnSetTrimtexBtn) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CDoorDialog message handlers + +void CDoorDialog::OnSetMaintexBtn() +{ + UpdateData(TRUE); + m_fbTextureName = m_mainTexSetBox; + UpdateData(FALSE); +} + +void CDoorDialog::OnSetTrimtexBtn() +{ + UpdateData(TRUE); + m_trimTextureName = m_trimTexSetBox; + UpdateData(FALSE); +} diff --git a/contrib/bobtoolz/dialogs/IntersectDialog.cpp b/contrib/bobtoolz/dialogs/IntersectDialog.cpp index 8ffc0fb3..63a42d02 100644 --- a/contrib/bobtoolz/dialogs/IntersectDialog.cpp +++ b/contrib/bobtoolz/dialogs/IntersectDialog.cpp @@ -1,65 +1,65 @@ -/* -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 -*/ - -// IntersectDialog.cpp : implementation file -// - -#include "../StdAfx.h" -#include "IntersectDialog.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CIntersectDialog dialog - - -CIntersectDialog::CIntersectDialog(CWnd* pParent /*=NULL*/) - : CDialog(CIntersectDialog::IDD, pParent) -{ - //{{AFX_DATA_INIT(CIntersectDialog) - m_nBrushOptions = 1; - m_bUseDetail = FALSE; - m_bDuplicateOnly = FALSE; - //}}AFX_DATA_INIT -} - - -void CIntersectDialog::DoDataExchange(CDataExchange* pDX) -{ - CDialog::DoDataExchange(pDX); - //{{AFX_DATA_MAP(CIntersectDialog) - DDX_Radio(pDX, IDC_WHOLEMAP_RADIO, m_nBrushOptions); - DDX_Check(pDX, IDC_DETAIL_INCLUDE_CHECK, m_bUseDetail); - DDX_Check(pDX, IDC_DUPLICATEONLY_CHECK, m_bDuplicateOnly); - //}}AFX_DATA_MAP -} - - -BEGIN_MESSAGE_MAP(CIntersectDialog, CDialog) - //{{AFX_MSG_MAP(CIntersectDialog) - // NOTE: the ClassWizard will add message map macros here - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CIntersectDialog message handlers +/* +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 +*/ + +// IntersectDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "IntersectDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CIntersectDialog dialog + + +CIntersectDialog::CIntersectDialog(CWnd* pParent /*=NULL*/) + : CDialog(CIntersectDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CIntersectDialog) + m_nBrushOptions = 1; + m_bUseDetail = FALSE; + m_bDuplicateOnly = FALSE; + //}}AFX_DATA_INIT +} + + +void CIntersectDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CIntersectDialog) + DDX_Radio(pDX, IDC_WHOLEMAP_RADIO, m_nBrushOptions); + DDX_Check(pDX, IDC_DETAIL_INCLUDE_CHECK, m_bUseDetail); + DDX_Check(pDX, IDC_DUPLICATEONLY_CHECK, m_bDuplicateOnly); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CIntersectDialog, CDialog) + //{{AFX_MSG_MAP(CIntersectDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CIntersectDialog message handlers diff --git a/contrib/bobtoolz/dialogs/IntersectInfoDialog.cpp b/contrib/bobtoolz/dialogs/IntersectInfoDialog.cpp index 77a63985..f7684a9e 100644 --- a/contrib/bobtoolz/dialogs/IntersectInfoDialog.cpp +++ b/contrib/bobtoolz/dialogs/IntersectInfoDialog.cpp @@ -1,61 +1,61 @@ -/* -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 -*/ - -// IntersectInfoDialog.cpp : implementation file -// - -#include "../StdAfx.h" -#include "../bobtoolz.h" -#include "IntersectInfoDialog.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CIntersectInfoDialog dialog - - -CIntersectInfoDialog::CIntersectInfoDialog(CWnd* pParent /*=NULL*/) - : CDialog(CIntersectInfoDialog::IDD, pParent) -{ - //{{AFX_DATA_INIT(CIntersectInfoDialog) - //}}AFX_DATA_INIT -} - - -void CIntersectInfoDialog::DoDataExchange(CDataExchange* pDX) -{ - CDialog::DoDataExchange(pDX); - //{{AFX_DATA_MAP(CIntersectInfoDialog) - DDX_Control(pDX, IDC_PROGRESS1, m_prog1); - //}}AFX_DATA_MAP -} - - -BEGIN_MESSAGE_MAP(CIntersectInfoDialog, CDialog) - //{{AFX_MSG_MAP(CIntersectInfoDialog) - // NOTE: the ClassWizard will add message map macros here - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CIntersectInfoDialog message handlers +/* +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 +*/ + +// IntersectInfoDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "../bobtoolz.h" +#include "IntersectInfoDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CIntersectInfoDialog dialog + + +CIntersectInfoDialog::CIntersectInfoDialog(CWnd* pParent /*=NULL*/) + : CDialog(CIntersectInfoDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CIntersectInfoDialog) + //}}AFX_DATA_INIT +} + + +void CIntersectInfoDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CIntersectInfoDialog) + DDX_Control(pDX, IDC_PROGRESS1, m_prog1); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CIntersectInfoDialog, CDialog) + //{{AFX_MSG_MAP(CIntersectInfoDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CIntersectInfoDialog message handlers diff --git a/contrib/bobtoolz/dialogs/PolygonDialog.cpp b/contrib/bobtoolz/dialogs/PolygonDialog.cpp index e4342192..f0a38d6e 100644 --- a/contrib/bobtoolz/dialogs/PolygonDialog.cpp +++ b/contrib/bobtoolz/dialogs/PolygonDialog.cpp @@ -1,116 +1,116 @@ -/* -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 -*/ - -// PolygonDialog.cpp : implementation file -// - -#include "../StdAfx.h" -#include "PolygonDialog.h" -#include "../shapes.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CPolygonDialog dialog - - -CPolygonDialog::CPolygonDialog(CWnd* pParent /*=NULL*/) - : CDialog(CPolygonDialog::IDD, pParent) -{ - //{{AFX_DATA_INIT(CPolygonDialog) - m_nSideCount = 3; - m_bInverse = FALSE; - m_bBorder = FALSE; - m_nBorderSize = 8; - m_bAlignTop = FALSE; - //}}AFX_DATA_INIT -} - -void CPolygonDialog::DoDataExchange(CDataExchange* pDX) -{ - CDialog::DoDataExchange(pDX); - //{{AFX_DATA_MAP(CPolygonDialog) - DDX_Text(pDX, IDC_EDIT1, m_nSideCount); - DDV_MinMaxUInt(pDX, m_nSideCount, 3, MAX_POLYGON_FACES); - DDX_Check(pDX, IDC_INVERSE_CHK, m_bInverse); - DDX_Check(pDX, IDC_BORDER_CHK, m_bBorder); - DDX_Text(pDX, IDC_BORDER_EDIT, m_nBorderSize); - DDV_MinMaxUInt(pDX, m_nBorderSize, 1, 1024); - DDX_Check(pDX, IDC_ALIGN_CHK, m_bAlignTop); - //}}AFX_DATA_MAP -} - - -BEGIN_MESSAGE_MAP(CPolygonDialog, CDialog) - //{{AFX_MSG_MAP(CPolygonDialog) - ON_BN_CLICKED(IDC_BORDER_CHK, OnBorderChkClicked) - ON_BN_CLICKED(IDC_INVERSE_CHK, OnInverseChkClickrd) - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CPolygonDialog message handlers - -BOOL CPolygonDialog::OnInitDialog() -{ - CDialog::OnInitDialog(); - - EnableBordered(!GetChkBool(IDC_INVERSE_CHK)); - EnableBorderEdit(!GetChkBool(IDC_INVERSE_CHK) && GetChkBool(IDC_BORDER_CHK)); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -void CPolygonDialog::EnableBordered(BOOL bEnable) -{ - CWnd* dtlChk = GetDlgItem(IDC_BORDER_CHK); - if(dtlChk) - dtlChk->EnableWindow(bEnable); -} - -void CPolygonDialog::EnableBorderEdit(BOOL bEnable) -{ - CWnd* dtlChk = GetDlgItem(IDC_BORDER_EDIT); - if(dtlChk) - dtlChk->EnableWindow(bEnable); -} - -void CPolygonDialog::OnBorderChkClicked() -{ - EnableBorderEdit(!GetChkBool(IDC_INVERSE_CHK) && GetChkBool(IDC_BORDER_CHK)); -} - -void CPolygonDialog::OnInverseChkClickrd() -{ - EnableBordered(!GetChkBool(IDC_INVERSE_CHK)); - EnableBorderEdit(!GetChkBool(IDC_INVERSE_CHK) && GetChkBool(IDC_BORDER_CHK)); -} - -BOOL CPolygonDialog::GetChkBool(int nID) -{ - CButton* btn = (CButton*)GetDlgItem(nID); - if(btn) - return btn->GetCheck(); - return FALSE; -} +/* +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 +*/ + +// PolygonDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "PolygonDialog.h" +#include "../shapes.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CPolygonDialog dialog + + +CPolygonDialog::CPolygonDialog(CWnd* pParent /*=NULL*/) + : CDialog(CPolygonDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CPolygonDialog) + m_nSideCount = 3; + m_bInverse = FALSE; + m_bBorder = FALSE; + m_nBorderSize = 8; + m_bAlignTop = FALSE; + //}}AFX_DATA_INIT +} + +void CPolygonDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CPolygonDialog) + DDX_Text(pDX, IDC_EDIT1, m_nSideCount); + DDV_MinMaxUInt(pDX, m_nSideCount, 3, MAX_POLYGON_FACES); + DDX_Check(pDX, IDC_INVERSE_CHK, m_bInverse); + DDX_Check(pDX, IDC_BORDER_CHK, m_bBorder); + DDX_Text(pDX, IDC_BORDER_EDIT, m_nBorderSize); + DDV_MinMaxUInt(pDX, m_nBorderSize, 1, 1024); + DDX_Check(pDX, IDC_ALIGN_CHK, m_bAlignTop); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CPolygonDialog, CDialog) + //{{AFX_MSG_MAP(CPolygonDialog) + ON_BN_CLICKED(IDC_BORDER_CHK, OnBorderChkClicked) + ON_BN_CLICKED(IDC_INVERSE_CHK, OnInverseChkClickrd) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CPolygonDialog message handlers + +BOOL CPolygonDialog::OnInitDialog() +{ + CDialog::OnInitDialog(); + + EnableBordered(!GetChkBool(IDC_INVERSE_CHK)); + EnableBorderEdit(!GetChkBool(IDC_INVERSE_CHK) && GetChkBool(IDC_BORDER_CHK)); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CPolygonDialog::EnableBordered(BOOL bEnable) +{ + CWnd* dtlChk = GetDlgItem(IDC_BORDER_CHK); + if(dtlChk) + dtlChk->EnableWindow(bEnable); +} + +void CPolygonDialog::EnableBorderEdit(BOOL bEnable) +{ + CWnd* dtlChk = GetDlgItem(IDC_BORDER_EDIT); + if(dtlChk) + dtlChk->EnableWindow(bEnable); +} + +void CPolygonDialog::OnBorderChkClicked() +{ + EnableBorderEdit(!GetChkBool(IDC_INVERSE_CHK) && GetChkBool(IDC_BORDER_CHK)); +} + +void CPolygonDialog::OnInverseChkClickrd() +{ + EnableBordered(!GetChkBool(IDC_INVERSE_CHK)); + EnableBorderEdit(!GetChkBool(IDC_INVERSE_CHK) && GetChkBool(IDC_BORDER_CHK)); +} + +BOOL CPolygonDialog::GetChkBool(int nID) +{ + CButton* btn = (CButton*)GetDlgItem(nID); + if(btn) + return btn->GetCheck(); + return FALSE; +} diff --git a/contrib/bobtoolz/dialogs/StairDialog.cpp b/contrib/bobtoolz/dialogs/StairDialog.cpp index c8e60bc2..4e7feba3 100644 --- a/contrib/bobtoolz/dialogs/StairDialog.cpp +++ b/contrib/bobtoolz/dialogs/StairDialog.cpp @@ -1,105 +1,105 @@ -/* -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 -*/ - -// StairDialog.cpp : implementation file -// - -#include "../StdAfx.h" -#include "StairDialog.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CStairDialog dialog - - -CStairDialog::CStairDialog(CWnd* pParent /*=NULL*/) - : CDialog(CStairDialog::IDD, pParent) -{ - //{{AFX_DATA_INIT(CStairDialog) - m_nStairHeight = 8; - m_StairDir = 0; - m_StairStyle = 0; - m_riserTexture = _T(""); - m_bDetail = TRUE; - //}}AFX_DATA_INIT -} - -void CStairDialog::DoDataExchange(CDataExchange* pDX) -{ - CDialog::DoDataExchange(pDX); - //{{AFX_DATA_MAP(CStairDialog) - DDX_Text(pDX, IDC_EDIT1, m_nStairHeight); - DDV_MinMaxUInt(pDX, m_nStairHeight, 1, 256); - DDX_Radio(pDX, IDC_DIR_N_RADIO, m_StairDir); - DDX_Radio(pDX, IDC_STYLE_ORIG_RADIO, m_StairStyle); - DDX_Text(pDX, IDC_RISER_EDIT, m_riserTexture); - DDV_MaxChars(pDX, m_riserTexture, 256); - DDX_Check(pDX, IDC_DETAIL_CHK, m_bDetail); - //}}AFX_DATA_MAP -} - - -BEGIN_MESSAGE_MAP(CStairDialog, CDialog) - //{{AFX_MSG_MAP(CStairDialog) - ON_BN_CLICKED(IDC_STYLE_BOB_RADIO, OnStyleBobClicked) - ON_BN_CLICKED(IDC_STYLE_ORIG_RADIO, OnStyleOrigClicked) - ON_BN_CLICKED(IDC_STYLE_CORNER_RADIO, OnStyleCornerClicked) - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CStairDialog message handlers - -void CStairDialog::OnStyleBobClicked() -{ - EnableDetail(TRUE); -} - -void CStairDialog::OnStyleOrigClicked() -{ - EnableDetail(FALSE); -} - -void CStairDialog::EnableDetail(BOOL bEnable) -{ - CWnd* dtlChk = GetDlgItem(IDC_DETAIL_CHK); - if(dtlChk) - dtlChk->EnableWindow(bEnable); -} - - -BOOL CStairDialog::OnInitDialog() -{ - CDialog::OnInitDialog(); - - EnableDetail(m_StairStyle == 1); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -void CStairDialog::OnStyleCornerClicked() -{ - EnableDetail(FALSE); -} +/* +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 +*/ + +// StairDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "StairDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CStairDialog dialog + + +CStairDialog::CStairDialog(CWnd* pParent /*=NULL*/) + : CDialog(CStairDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CStairDialog) + m_nStairHeight = 8; + m_StairDir = 0; + m_StairStyle = 0; + m_riserTexture = _T(""); + m_bDetail = TRUE; + //}}AFX_DATA_INIT +} + +void CStairDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CStairDialog) + DDX_Text(pDX, IDC_EDIT1, m_nStairHeight); + DDV_MinMaxUInt(pDX, m_nStairHeight, 1, 256); + DDX_Radio(pDX, IDC_DIR_N_RADIO, m_StairDir); + DDX_Radio(pDX, IDC_STYLE_ORIG_RADIO, m_StairStyle); + DDX_Text(pDX, IDC_RISER_EDIT, m_riserTexture); + DDV_MaxChars(pDX, m_riserTexture, 256); + DDX_Check(pDX, IDC_DETAIL_CHK, m_bDetail); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CStairDialog, CDialog) + //{{AFX_MSG_MAP(CStairDialog) + ON_BN_CLICKED(IDC_STYLE_BOB_RADIO, OnStyleBobClicked) + ON_BN_CLICKED(IDC_STYLE_ORIG_RADIO, OnStyleOrigClicked) + ON_BN_CLICKED(IDC_STYLE_CORNER_RADIO, OnStyleCornerClicked) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CStairDialog message handlers + +void CStairDialog::OnStyleBobClicked() +{ + EnableDetail(TRUE); +} + +void CStairDialog::OnStyleOrigClicked() +{ + EnableDetail(FALSE); +} + +void CStairDialog::EnableDetail(BOOL bEnable) +{ + CWnd* dtlChk = GetDlgItem(IDC_DETAIL_CHK); + if(dtlChk) + dtlChk->EnableWindow(bEnable); +} + + +BOOL CStairDialog::OnInitDialog() +{ + CDialog::OnInitDialog(); + + EnableDetail(m_StairStyle == 1); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CStairDialog::OnStyleCornerClicked() +{ + EnableDetail(FALSE); +} diff --git a/contrib/bobtoolz/dialogs/TextureResetDialog.cpp b/contrib/bobtoolz/dialogs/TextureResetDialog.cpp index 10c57f1b..77ebc766 100644 --- a/contrib/bobtoolz/dialogs/TextureResetDialog.cpp +++ b/contrib/bobtoolz/dialogs/TextureResetDialog.cpp @@ -1,81 +1,81 @@ -/* -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 -*/ - -// TextureResetDialog.cpp : implementation file -// - -#include "../StdAfx.h" -#include "../bobtoolz.h" -#include "TextureResetDialog.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CTextureResetDialog dialog - - -CTextureResetDialog::CTextureResetDialog(CWnd* pParent /*=NULL*/) - : CDialog(CTextureResetDialog::IDD, pParent) -{ - //{{AFX_DATA_INIT(CTextureResetDialog) - m_bAllTextures = FALSE; - m_TextureName = _T(""); - m_nRotation = 0; - m_fScaleHorizontal = 0.5f; - m_fScaleVertical = 0.5f; - m_nShiftHorizontal = 0; - m_nShiftVertical = 0; - m_bOnlyTexture = FALSE; - m_NewTextureName = _T(""); - //}}AFX_DATA_INIT -} - - -void CTextureResetDialog::DoDataExchange(CDataExchange* pDX) -{ - CDialog::DoDataExchange(pDX); - //{{AFX_DATA_MAP(CTextureResetDialog) - DDX_Check(pDX, IDC_ALLTEXTURES_CHECK, m_bAllTextures); - DDX_Text(pDX, IDC_RESET_TEXTURE_EDIT, m_TextureName); - DDV_MaxChars(pDX, m_TextureName, 256); - DDX_Text(pDX, IDC_ROTATION_EDIT, m_nRotation); - DDV_MinMaxInt(pDX, m_nRotation, 0, 360); - DDX_Text(pDX, IDC_SCL_HOR_EDIT, m_fScaleHorizontal); - DDX_Text(pDX, IDC_SCL_VERT_EDIT, m_fScaleVertical); - DDX_Text(pDX, IDC_SHFT_HOR_EDIT, m_nShiftHorizontal); - DDX_Text(pDX, IDC_SHFT_VER_EDIT, m_nShiftVertical); - DDX_Check(pDX, IDC_ONLYTEXTURE_CHECK, m_bOnlyTexture); - DDX_Text(pDX, IDC_RESET_NEW_TEXTURE_EDIT, m_NewTextureName); - DDV_MaxChars(pDX, m_NewTextureName, 256); - //}}AFX_DATA_MAP -} - - -BEGIN_MESSAGE_MAP(CTextureResetDialog, CDialog) - //{{AFX_MSG_MAP(CTextureResetDialog) - // NOTE: the ClassWizard will add message map macros here - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CTextureResetDialog message handlers +/* +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 +*/ + +// TextureResetDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "../bobtoolz.h" +#include "TextureResetDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CTextureResetDialog dialog + + +CTextureResetDialog::CTextureResetDialog(CWnd* pParent /*=NULL*/) + : CDialog(CTextureResetDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CTextureResetDialog) + m_bAllTextures = FALSE; + m_TextureName = _T(""); + m_nRotation = 0; + m_fScaleHorizontal = 0.5f; + m_fScaleVertical = 0.5f; + m_nShiftHorizontal = 0; + m_nShiftVertical = 0; + m_bOnlyTexture = FALSE; + m_NewTextureName = _T(""); + //}}AFX_DATA_INIT +} + + +void CTextureResetDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CTextureResetDialog) + DDX_Check(pDX, IDC_ALLTEXTURES_CHECK, m_bAllTextures); + DDX_Text(pDX, IDC_RESET_TEXTURE_EDIT, m_TextureName); + DDV_MaxChars(pDX, m_TextureName, 256); + DDX_Text(pDX, IDC_ROTATION_EDIT, m_nRotation); + DDV_MinMaxInt(pDX, m_nRotation, 0, 360); + DDX_Text(pDX, IDC_SCL_HOR_EDIT, m_fScaleHorizontal); + DDX_Text(pDX, IDC_SCL_VERT_EDIT, m_fScaleVertical); + DDX_Text(pDX, IDC_SHFT_HOR_EDIT, m_nShiftHorizontal); + DDX_Text(pDX, IDC_SHFT_VER_EDIT, m_nShiftVertical); + DDX_Check(pDX, IDC_ONLYTEXTURE_CHECK, m_bOnlyTexture); + DDX_Text(pDX, IDC_RESET_NEW_TEXTURE_EDIT, m_NewTextureName); + DDV_MaxChars(pDX, m_NewTextureName, 256); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CTextureResetDialog, CDialog) + //{{AFX_MSG_MAP(CTextureResetDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CTextureResetDialog message handlers diff --git a/contrib/bobtoolz/dialogs/brushcheckdialog.cpp b/contrib/bobtoolz/dialogs/brushcheckdialog.cpp index 5082d8a5..06fe6c9b 100644 --- a/contrib/bobtoolz/dialogs/brushcheckdialog.cpp +++ b/contrib/bobtoolz/dialogs/brushcheckdialog.cpp @@ -1,61 +1,61 @@ -/* -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 -*/ - -// BrushCheckDialog.cpp : implementation file -// - -#include "../StdAfx.h" -#include "../bobtoolz.h" -#include "BrushCheckDialog.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CBrushCheckDialog dialog - - -CBrushCheckDialog::CBrushCheckDialog(CWnd* pParent /*=NULL*/) - : CDialog(CBrushCheckDialog::IDD, pParent) -{ - //{{AFX_DATA_INIT(CBrushCheckDialog) - //}}AFX_DATA_INIT -} - - -void CBrushCheckDialog::DoDataExchange(CDataExchange* pDX) -{ - CDialog::DoDataExchange(pDX); - //{{AFX_DATA_MAP(CBrushCheckDialog) - DDX_Control(pDX, IDC_PROGRESS1, m_prog1); - //}}AFX_DATA_MAP -} - - -BEGIN_MESSAGE_MAP(CBrushCheckDialog, CDialog) - //{{AFX_MSG_MAP(CBrushCheckDialog) - // NOTE: the ClassWizard will add message map macros here - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CBrushCheckDialog message handlers +/* +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 +*/ + +// BrushCheckDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "../bobtoolz.h" +#include "BrushCheckDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CBrushCheckDialog dialog + + +CBrushCheckDialog::CBrushCheckDialog(CWnd* pParent /*=NULL*/) + : CDialog(CBrushCheckDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CBrushCheckDialog) + //}}AFX_DATA_INIT +} + + +void CBrushCheckDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CBrushCheckDialog) + DDX_Control(pDX, IDC_PROGRESS1, m_prog1); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CBrushCheckDialog, CDialog) + //{{AFX_MSG_MAP(CBrushCheckDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CBrushCheckDialog message handlers diff --git a/contrib/bobtoolz/dialogs/dialogs-gtk.cpp b/contrib/bobtoolz/dialogs/dialogs-gtk.cpp index f59ff754..a51789c4 100644 --- a/contrib/bobtoolz/dialogs/dialogs-gtk.cpp +++ b/contrib/bobtoolz/dialogs/dialogs-gtk.cpp @@ -1,1894 +1,1894 @@ -/* -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 -*/ - -#include "../StdAfx.h" -#include "dialogs-gtk.h" -#include "../funchandlers.h" -#include "../lists.h" -#include "../misc.h" - -/*-------------------------------- - Callback Functions ----------------------------------*/ - -typedef struct { - GtkWidget *cbTexChange; - GtkWidget *editTexOld, *editTexNew; - - GtkWidget *cbScaleHor, *cbScaleVert; - GtkWidget *editScaleHor, *editScaleVert; - - GtkWidget *cbShiftHor, *cbShiftVert; - GtkWidget *editShiftHor, *editShiftVert; - - GtkWidget *cbRotation; - GtkWidget *editRotation; -}dlg_texReset_t; - -dlg_texReset_t dlgTexReset; - -void Update_TextureReseter(); - -static void dialog_button_callback_texreset_update (GtkWidget *widget, gpointer data) -{ - Update_TextureReseter(); -} - -void Update_TextureReseter() -{ - gboolean check; - - check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbTexChange )); - gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editTexNew), check); - gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editTexOld), check); - - check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbScaleHor )); - gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editScaleHor), check); - - check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbScaleVert )); - gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editScaleVert), check); - - check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbShiftHor )); - gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editShiftHor), check); - - check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbShiftVert )); - gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editShiftVert), check); - - check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbRotation )); - gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editRotation), check); -} - -static void dialog_button_callback (GtkWidget *widget, gpointer data) -{ - GtkWidget *parent; - int *loop, *ret; - - parent = gtk_widget_get_toplevel (widget); - loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); - ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); - - *loop = 0; - *ret = (int)data; -} - -static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) -{ - int *loop; - - gtk_widget_hide (widget); - loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); - *loop = 0; - - return TRUE; -} - -static void dialog_button_callback_settex (GtkWidget *widget, gpointer data) -{ - TwinWidget* tw = (TwinWidget*)data; - - GtkEntry* entry = GTK_ENTRY( tw->one ); - GtkCombo* combo = GTK_COMBO( tw->two ); - - const gchar* tex = gtk_entry_get_text(GTK_ENTRY( combo->entry )); - gtk_entry_set_text( entry, tex); -} - -/*-------------------------------- - Data validation Routines ----------------------------------*/ - -bool ValidateTextFloat(const char* pData, char* error_title, float* value) -{ - if(pData) - { - float testNum = (float)atof(pData); - - if((testNum == 0.0f) && strcmp(pData, "0")) - { - DoMessageBox("Please Enter A Floating Point Number", error_title, MB_OK); - return FALSE; - } - else - { - *value = testNum; - return TRUE; - } - } - - DoMessageBox("Please Enter A Floating Point Number", error_title, MB_OK); - return FALSE; -} - -bool ValidateTextFloatRange(const char* pData, float min, float max, char* error_title, float* value) -{ - char error_buffer[256]; - sprintf(error_buffer, "Please Enter A Floating Point Number Between %.3f and %.3f", min, max); - - if(pData) - { - float testNum = (float)atof(pData); - - if((testNum < min) || (testNum > max)) - { - DoMessageBox(error_buffer, error_title, MB_OK); - return FALSE; - } - else - { - *value = testNum; - return TRUE; - } - } - - DoMessageBox(error_buffer, error_title, MB_OK); - return FALSE; -} - -bool ValidateTextIntRange(const char* pData, int min, int max, char* error_title, int* value) -{ - char error_buffer[256]; - sprintf(error_buffer, "Please Enter An Integer Between %i and %i", min, max); - - if(pData) - { - int testNum = atoi(pData); - - if((testNum < min) || (testNum > max)) - { - DoMessageBox(error_buffer, error_title, MB_OK); - return FALSE; - } - else - { - *value = testNum; - return TRUE; - } - } - - DoMessageBox(error_buffer, error_title, MB_OK); - return FALSE; -} - -bool ValidateTextInt(const char* pData, char* error_title, int* value) -{ - if(pData) - { - int testNum = atoi(pData); - - if((testNum == 0) && strcmp(pData, "0")) - { - DoMessageBox("Please Enter An Integer", error_title, MB_OK); - return FALSE; - } - else - { - *value = testNum; - return TRUE; - } - } - - DoMessageBox("Please Enter An Integer", error_title, MB_OK); - return FALSE; -} - -/*-------------------------------- - Modal Dialog Boxes ----------------------------------*/ - -/* - - Major clean up of variable names etc required, excluding Mars's ones, - which are nicely done :) - -*/ - -int DoMessageBox (const char* lpText, const char* lpCaption, guint32 uType) -{ - GtkWidget *window, *w, *vbox, *hbox; - int mode = (uType & MB_TYPEMASK), ret, loop = 1; - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_signal_connect (GTK_OBJECT (window), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (window), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - gtk_window_set_title (GTK_WINDOW (window), lpCaption); - gtk_container_border_width (GTK_CONTAINER (window), 10); - g_object_set_data (G_OBJECT (window), "loop", &loop); - g_object_set_data (G_OBJECT (window), "ret", &ret); - gtk_widget_realize (window); - - vbox = gtk_vbox_new (FALSE, 10); - gtk_container_add (GTK_CONTAINER (window), vbox); - gtk_widget_show (vbox); - - w = gtk_label_new (lpText); - gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); - gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); - gtk_widget_show (w); - - w = gtk_hseparator_new (); - gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); - gtk_widget_show (w); - - hbox = gtk_hbox_new (FALSE, 10); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); - gtk_widget_show (hbox); - - if (mode == MB_OK) - { - w = gtk_button_new_with_label ("Ok"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); - gtk_widget_grab_default (w); - gtk_widget_show (w); - ret = IDOK; - } - else if (mode == MB_OKCANCEL) - { - w = gtk_button_new_with_label ("Ok"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); - gtk_widget_grab_default (w); - gtk_widget_show (w); - - w = gtk_button_new_with_label ("Cancel"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_show (w); - ret = IDCANCEL; - } - else if (mode == MB_YESNOCANCEL) - { - w = gtk_button_new_with_label ("Yes"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); - GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); - gtk_widget_grab_default (w); - gtk_widget_show (w); - - w = gtk_button_new_with_label ("No"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO)); - gtk_widget_show (w); - - w = gtk_button_new_with_label ("Cancel"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_show (w); - ret = IDCANCEL; - } - else /* if (mode == MB_YESNO) */ - { - w = gtk_button_new_with_label ("Yes"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); - GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); - gtk_widget_grab_default (w); - gtk_widget_show (w); - - w = gtk_button_new_with_label ("No"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO)); - gtk_widget_show (w); - ret = IDNO; - } - - gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); - gtk_widget_show (window); - gtk_grab_add (window); - - while (loop) - gtk_main_iteration (); - - gtk_grab_remove (window); - gtk_widget_destroy (window); - - return ret; -} - -int DoIntersectBox (IntersectRS* rs) -{ - GtkWidget *window, *w, *vbox, *hbox; - GtkWidget *radio1, *radio2; - GtkWidget *check1, *check2; - int ret, loop = 1; - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - - gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - - gtk_window_set_title (GTK_WINDOW (window), "Intersect"); - gtk_container_border_width (GTK_CONTAINER (window), 10); - - g_object_set_data (G_OBJECT (window), "loop", &loop); - g_object_set_data (G_OBJECT (window), "ret", &ret); - - gtk_widget_realize (window); - - - - vbox = gtk_vbox_new (FALSE, 10); - gtk_container_add (GTK_CONTAINER (window), vbox); - gtk_widget_show (vbox); - - // ---- vbox ---- - - radio1 = gtk_radio_button_new_with_label(NULL, "Use Whole Map"); - gtk_box_pack_start (GTK_BOX (vbox), radio1, FALSE, FALSE, 2); - gtk_widget_show (radio1); - - radio2 = gtk_radio_button_new_with_label(((GtkRadioButton*)radio1)->group, "Use Selected Brushes"); - gtk_box_pack_start (GTK_BOX (vbox), radio2, FALSE, FALSE, 2); - gtk_widget_show (radio2); - - w = gtk_hseparator_new (); - gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); - gtk_widget_show (w); - - check1 = gtk_check_button_new_with_label("Include Detail Brushes"); - gtk_box_pack_start (GTK_BOX (vbox), check1, FALSE, FALSE, 0); - gtk_widget_show (check1); - - check2 = gtk_check_button_new_with_label("Select Duplicate Brushes Only"); - gtk_box_pack_start (GTK_BOX (vbox), check2, FALSE, FALSE, 0); - gtk_widget_show (check2); - - hbox = gtk_hbox_new (FALSE, 10); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); - gtk_widget_show (hbox); - - // ---- hbox ---- ok/cancel buttons - - w = gtk_button_new_with_label ("Ok"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - - GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); - gtk_widget_grab_default (w); - gtk_widget_show (w); - - w = gtk_button_new_with_label ("Cancel"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_show (w); - ret = IDCANCEL; - - // ---- /hbox ---- - - // ---- /vbox ---- - - gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); - gtk_widget_show (window); - gtk_grab_add (window); - - while (loop) - gtk_main_iteration (); - - if(gtk_toggle_button_get_active((GtkToggleButton*)radio1)) - rs->nBrushOptions = BRUSH_OPT_WHOLE_MAP; - else if(gtk_toggle_button_get_active((GtkToggleButton*)radio2)) - rs->nBrushOptions = BRUSH_OPT_SELECTED; - - rs->bUseDetail = gtk_toggle_button_get_active((GtkToggleButton*)check1) ? true : false; - rs->bDuplicateOnly = gtk_toggle_button_get_active((GtkToggleButton*)check2) ? true : false; - - gtk_grab_remove (window); - gtk_widget_destroy (window); - - return ret; -} - -int DoPolygonBox (PolygonRS* rs) -{ - GtkWidget *window, *w, *vbox, *hbox, *vbox2, *hbox2; - - GtkWidget *check1, *check2, *check3; - GtkWidget *text1, *text2; - - int ret, loop = 1; - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - - gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - - gtk_window_set_title (GTK_WINDOW (window), "Polygon Builder"); - gtk_container_border_width (GTK_CONTAINER (window), 10); - - g_object_set_data (G_OBJECT (window), "loop", &loop); - g_object_set_data (G_OBJECT (window), "ret", &ret); - - gtk_widget_realize (window); - - - - vbox = gtk_vbox_new (FALSE, 10); - gtk_container_add (GTK_CONTAINER (window), vbox); - gtk_widget_show (vbox); - - // ---- vbox ---- - - hbox = gtk_hbox_new (FALSE, 10); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); - gtk_widget_show (hbox); - - // ---- hbox ---- - - - vbox2 = gtk_vbox_new (FALSE, 10); - gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 2); - gtk_widget_show (vbox2); - - // ---- vbox2 ---- - - hbox2 = gtk_hbox_new (FALSE, 10); - gtk_box_pack_start (GTK_BOX (vbox2), hbox2, FALSE, FALSE, 2); - gtk_widget_show (hbox2); - - // ---- hbox2 ---- - - text1 = gtk_entry_new_with_max_length(256); - gtk_entry_set_text((GtkEntry*)text1, "3"); - gtk_box_pack_start (GTK_BOX (hbox2), text1, FALSE, FALSE, 2); - gtk_widget_show (text1); - - w = gtk_label_new ("Number Of Sides"); - gtk_box_pack_start (GTK_BOX (hbox2), w, FALSE, FALSE, 2); - gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); - gtk_widget_show (w); - - // ---- /hbox2 ---- - - hbox2 = gtk_hbox_new (FALSE, 10); - gtk_box_pack_start (GTK_BOX (vbox2), hbox2, FALSE, FALSE, 2); - gtk_widget_show (hbox2); - - // ---- hbox2 ---- - - text2 = gtk_entry_new_with_max_length(256); - gtk_entry_set_text((GtkEntry*)text2, "8"); - gtk_box_pack_start (GTK_BOX (hbox2), text2, FALSE, FALSE, 2); - gtk_widget_show (text2); - - w = gtk_label_new ("Border Width"); - gtk_box_pack_start (GTK_BOX (hbox2), w, FALSE, FALSE, 2); - gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); - gtk_widget_show (w); - - // ---- /hbox2 ---- - - // ---- /vbox2 ---- - - - - vbox2 = gtk_vbox_new (FALSE, 10); - gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 2); - gtk_widget_show (vbox2); - - // ---- vbox2 ---- - - check1 = gtk_check_button_new_with_label("Use Border"); - gtk_box_pack_start (GTK_BOX (vbox2), check1, FALSE, FALSE, 0); - gtk_widget_show (check1); - - - check2 = gtk_check_button_new_with_label("Inverse Polygon"); - gtk_box_pack_start (GTK_BOX (vbox2), check2, FALSE, FALSE, 0); - gtk_widget_show (check2); - - - check3 = gtk_check_button_new_with_label("Align Top Edge"); - gtk_box_pack_start (GTK_BOX (vbox2), check3, FALSE, FALSE, 0); - gtk_widget_show (check3); - - // ---- /vbox2 ---- - - // ---- /hbox ---- - - hbox = gtk_hbox_new (FALSE, 10); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); - gtk_widget_show (hbox); - - // ---- hbox ---- - - w = gtk_button_new_with_label ("Ok"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - - GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); - gtk_widget_grab_default (w); - gtk_widget_show (w); - - w = gtk_button_new_with_label ("Cancel"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_show (w); - ret = IDCANCEL; - - // ---- /hbox ---- - - // ---- /vbox ---- - - gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); - gtk_widget_show (window); - gtk_grab_add (window); - - bool dialogError = TRUE; - while (dialogError) - { - loop = 1; - while (loop) - gtk_main_iteration (); - - dialogError = FALSE; - - if(ret == IDOK) - { - rs->bUseBorder = gtk_toggle_button_get_active((GtkToggleButton*)check1) ? true : false; - rs->bInverse = gtk_toggle_button_get_active((GtkToggleButton*)check2) ? true : false; - rs->bAlignTop = gtk_toggle_button_get_active((GtkToggleButton*)check3) ? true : false; - - if(!ValidateTextIntRange(gtk_entry_get_text((GtkEntry*)text1), 3, 32, "Number Of Sides", &rs->nSides)) - dialogError = TRUE; - - if(rs->bUseBorder) - { - if(!ValidateTextIntRange(gtk_entry_get_text((GtkEntry*)text2), 8, 256, "Border Width", &rs->nBorderWidth)) - dialogError = TRUE; - } - } - } - - gtk_grab_remove (window); - gtk_widget_destroy (window); - - return ret; -} - -// mars -// for stair builder stuck as close as i could to the MFC version -// obviously feel free to change it at will :) -int DoBuildStairsBox(BuildStairsRS* rs) -{ - // i made widgets for just about everything ... i think that's what i need to do dunno tho - GtkWidget *window, *w, *vbox, *hbox; - GtkWidget *textStairHeight, *textRiserTex, *textMainTex; - GtkWidget *radioNorth, *radioSouth, *radioEast, *radioWest; // i'm guessing we can't just abuse 'w' for these if we're getting a value - GtkWidget *radioOldStyle, *radioBobStyle, *radioCornerStyle; - GtkWidget *checkUseDetail; - GSList *radioDirection, *radioStyle; - int ret, loop; - - loop = 1; - - char *text = "Please set a value in the boxes below and press 'OK' to build the stairs"; - - window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); - - gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - - gtk_window_set_title( GTK_WINDOW( window ), "Stair Builder" ); - - gtk_container_border_width( GTK_CONTAINER( window ), 10 ); - - g_object_set_data (G_OBJECT (window), "loop", &loop); - g_object_set_data (G_OBJECT (window), "ret", &ret); - - gtk_widget_realize (window); - - // new vbox - vbox = gtk_vbox_new( FALSE, 10 ); - gtk_container_add( GTK_CONTAINER( window ), vbox ); - gtk_widget_show( vbox ); - - hbox = gtk_hbox_new( FALSE, 10 ); - gtk_container_add( GTK_CONTAINER( vbox ), hbox ); - gtk_widget_show( hbox ); - - // dunno if you want this text or not ... - w = gtk_label_new( text ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); // not entirely sure on all the parameters / what they do ... - gtk_widget_show( w ); - - w = gtk_hseparator_new(); - gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - - // ------------------------- // indenting == good way of keeping track of lines :) - - // new hbox - hbox = gtk_hbox_new( FALSE, 10 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - textStairHeight = gtk_entry_new_with_max_length( 256 ); - gtk_box_pack_start( GTK_BOX( hbox ), textStairHeight, FALSE, FALSE, 1 ); - gtk_widget_show( textStairHeight ); - - w = gtk_label_new( "Stair Height" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 1 ); - gtk_widget_show( w ); - - // ------------------------- // - - hbox = gtk_hbox_new( FALSE, 10 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - w = gtk_label_new( "Direction:" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 5 ); - gtk_widget_show( w ); - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 10 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - // radio buttons confuse me ... - // but this _looks_ right - - // djbob: actually it looks very nice :), slightly better than the way i did it - // edit: actually it doesn't work :P, you must pass the last radio item each time, ugh - - radioNorth = gtk_radio_button_new_with_label( NULL, "North" ); - gtk_box_pack_start( GTK_BOX( hbox ), radioNorth, FALSE, FALSE, 3 ); - gtk_widget_show( radioNorth ); - - radioDirection = gtk_radio_button_group( GTK_RADIO_BUTTON( radioNorth ) ); - - radioSouth = gtk_radio_button_new_with_label( radioDirection, "South" ); - gtk_box_pack_start( GTK_BOX( hbox ), radioSouth, FALSE, FALSE, 2 ); - gtk_widget_show( radioSouth ); - - radioDirection = gtk_radio_button_group( GTK_RADIO_BUTTON( radioSouth ) ); - - radioEast = gtk_radio_button_new_with_label( radioDirection, "East" ); - gtk_box_pack_start( GTK_BOX( hbox ), radioEast, FALSE, FALSE, 1 ); - gtk_widget_show( radioEast ); - - radioDirection = gtk_radio_button_group( GTK_RADIO_BUTTON( radioEast ) ); - - radioWest = gtk_radio_button_new_with_label( radioDirection, "West" ); - gtk_box_pack_start( GTK_BOX( hbox ), radioWest, FALSE, FALSE, 0 ); - gtk_widget_show( radioWest ); - - // --------------------------- // - - hbox = gtk_hbox_new( FALSE, 10 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - w = gtk_label_new( "Style:" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 5 ); - gtk_widget_show( w ); - - // --------------------------- // - - hbox = gtk_hbox_new( FALSE, 10 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - radioOldStyle = gtk_radio_button_new_with_label( NULL, "Original" ); - gtk_box_pack_start( GTK_BOX( hbox ), radioOldStyle, FALSE, FALSE, 0 ); - gtk_widget_show( radioOldStyle ); - - radioStyle = gtk_radio_button_group( GTK_RADIO_BUTTON( radioOldStyle ) ); - - radioBobStyle = gtk_radio_button_new_with_label( radioStyle, "Bob's Style" ); - gtk_box_pack_start( GTK_BOX( hbox ), radioBobStyle, FALSE, FALSE, 0 ); - gtk_widget_show( radioBobStyle ); - - radioStyle = gtk_radio_button_group( GTK_RADIO_BUTTON( radioBobStyle ) ); - - radioCornerStyle = gtk_radio_button_new_with_label( radioStyle, "Corner Style" ); - gtk_box_pack_start( GTK_BOX( hbox ), radioCornerStyle, FALSE, FALSE, 0 ); - gtk_widget_show( radioCornerStyle ); - - // err, the q3r has an if or something so you need bob style checked before this - // is "ungreyed out" but you'll need to do that, as i suck :) - - // djbob: er.... yeah um, im not at all sure how i'm gonna sort this - // djbob: think we need some button callback functions or smuffin - // FIXME: actually get around to doing what i suggested!!!! - - checkUseDetail = gtk_check_button_new_with_label( "Use Detail Brushes" ); - gtk_box_pack_start( GTK_BOX( hbox ), checkUseDetail, FALSE, FALSE, 0 ); - gtk_widget_show( checkUseDetail ); - - // --------------------------- // - - hbox = gtk_hbox_new( FALSE, 10 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - textMainTex = gtk_entry_new_with_max_length( 512 ); - gtk_entry_set_text(GTK_ENTRY(textMainTex), rs->mainTexture); - gtk_box_pack_start( GTK_BOX( hbox ), textMainTex, FALSE, FALSE, 0 ); - gtk_widget_show( textMainTex ); - - w = gtk_label_new( "Main Texture" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 1 ); - gtk_widget_show( w ); - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 10 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - textRiserTex = gtk_entry_new_with_max_length( 512 ); - gtk_box_pack_start( GTK_BOX( hbox ), textRiserTex, FALSE, FALSE, 0 ); - gtk_widget_show( textRiserTex ); - - w = gtk_label_new( "Riser Texture" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 1 ); - gtk_widget_show( w ); - - // -------------------------- // - w = gtk_hseparator_new(); - gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - - hbox = gtk_hbox_new( FALSE, 10 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - w = gtk_button_new_with_label( "OK" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDOK ) ); - GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); - gtk_widget_grab_default( w ); - gtk_widget_show( w ); - - w = gtk_button_new_with_label( "Cancel" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDCANCEL ) ); - gtk_widget_show( w ); - - ret = IDCANCEL; - -// +djbob: need our "little" modal loop mars :P - gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); - gtk_widget_show (window); - gtk_grab_add (window); - - bool dialogError = TRUE; - while (dialogError) - { - loop = 1; - while (loop) - gtk_main_iteration (); - - dialogError = FALSE; - - if(ret == IDOK) - { - rs->bUseDetail = gtk_toggle_button_get_active((GtkToggleButton*)checkUseDetail) ? true : false; - - strcpy(rs->riserTexture, gtk_entry_get_text((GtkEntry*)textRiserTex)); - strcpy(rs->mainTexture, gtk_entry_get_text((GtkEntry*)textMainTex)); - - if(gtk_toggle_button_get_active((GtkToggleButton*)radioNorth)) - rs->direction = MOVE_NORTH; - else if(gtk_toggle_button_get_active((GtkToggleButton*)radioSouth)) - rs->direction = MOVE_SOUTH; - else if(gtk_toggle_button_get_active((GtkToggleButton*)radioEast)) - rs->direction = MOVE_EAST; - else if(gtk_toggle_button_get_active((GtkToggleButton*)radioWest)) - rs->direction = MOVE_WEST; - - if(!ValidateTextInt(gtk_entry_get_text((GtkEntry*)textStairHeight), "Stair Height", &rs->stairHeight)) - dialogError = TRUE; - - if(gtk_toggle_button_get_active((GtkToggleButton*)radioOldStyle)) - rs->style = STYLE_ORIGINAL; - else if(gtk_toggle_button_get_active((GtkToggleButton*)radioBobStyle)) - rs->style = STYLE_BOB; - else if(gtk_toggle_button_get_active((GtkToggleButton*)radioCornerStyle)) - rs->style = STYLE_CORNER; - } - } - - gtk_grab_remove (window); - gtk_widget_destroy (window); - - return ret; -// -djbob - - // there we go, all done ... on my end at least, not bad for a night's work -} - -int DoDoorsBox(DoorRS* rs) -{ - GtkWidget *window, *hbox, *vbox, *w; - GtkWidget *textFrontBackTex, *textTrimTex; - GtkWidget *checkScaleMainH, *checkScaleMainV, *checkScaleTrimH, *checkScaleTrimV; - GtkWidget *comboMain, *comboTrim; - GtkWidget *buttonSetMain, *buttonSetTrim; - GtkWidget *radioNS, *radioEW; - GSList *radioOrientation; - TwinWidget tw1, tw2; - int ret, loop; - - loop = 1; - - window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); - - gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - - gtk_window_set_title( GTK_WINDOW( window ), "Door Builder" ); - - gtk_container_border_width( GTK_CONTAINER( window ), 10 ); - - g_object_set_data( G_OBJECT( window ), "loop", &loop ); - g_object_set_data( G_OBJECT( window ), "ret", &ret ); - - gtk_widget_realize (window); - - char buffer[256]; - GList *listMainTextures = NULL; - GList *listTrimTextures = NULL; - LoadGList(GetFilename(buffer, "plugins/bt/door-tex.txt"), &listMainTextures); - LoadGList(GetFilename(buffer, "plugins/bt/door-tex-trim.txt"), &listTrimTextures); - - vbox = gtk_vbox_new( FALSE, 10 ); - gtk_container_add( GTK_CONTAINER( window ), vbox ); - gtk_widget_show( vbox ); - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 10 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - textFrontBackTex = gtk_entry_new_with_max_length( 512 ); - gtk_entry_set_text( GTK_ENTRY( textFrontBackTex ), rs->mainTexture); - gtk_box_pack_start( GTK_BOX( hbox ), textFrontBackTex, FALSE, FALSE, 0 ); - gtk_widget_show( textFrontBackTex ); - - w = gtk_label_new( "Door Front/Back Texture" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - - // ------------------------ // - - hbox = gtk_hbox_new( FALSE, 10 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - textTrimTex = gtk_entry_new_with_max_length( 512 ); - gtk_box_pack_start( GTK_BOX( hbox ), textTrimTex, FALSE, FALSE, 0 ); - gtk_widget_show( textTrimTex ); - - w = gtk_label_new( "Door Trim Texture" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - - // ----------------------- // - - hbox = gtk_hbox_new( FALSE, 10 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - // sp: horizontally ???? - // djbob: yes mars, u can spell :] - checkScaleMainH = gtk_check_button_new_with_label( "Scale Main Texture Horizontally" ); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( checkScaleMainH ), TRUE); - gtk_box_pack_start( GTK_BOX( hbox ), checkScaleMainH, FALSE, FALSE, 0 ); - gtk_widget_show( checkScaleMainH ); - - checkScaleTrimH = gtk_check_button_new_with_label( "Scale Trim Texture Horizontally" ); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( checkScaleTrimH ), TRUE); - gtk_box_pack_start( GTK_BOX( hbox ), checkScaleTrimH, FALSE, FALSE, 0 ); - gtk_widget_show( checkScaleTrimH ); - - // ---------------------- // - - hbox = gtk_hbox_new( FALSE, 10 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - checkScaleMainV = gtk_check_button_new_with_label( "Scale Main Texture Vertically" ); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( checkScaleMainV ), TRUE); - gtk_box_pack_start( GTK_BOX( hbox ), checkScaleMainV, FALSE, FALSE, 0 ); - gtk_widget_show( checkScaleMainV ); - - checkScaleTrimV = gtk_check_button_new_with_label( "Scale Trim Texture Vertically" ); - gtk_box_pack_start( GTK_BOX( hbox ), checkScaleTrimV, FALSE, FALSE, 0 ); - gtk_widget_show( checkScaleTrimV ); - - // --------------------- // - - hbox = gtk_hbox_new( FALSE, 10 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - // djbob: lists added - - comboMain = gtk_combo_new(); - gtk_box_pack_start( GTK_BOX( hbox ), comboMain, FALSE, FALSE, 0 ); - gtk_combo_set_popdown_strings( GTK_COMBO( comboMain ), listMainTextures ); - gtk_combo_set_use_arrows( GTK_COMBO( comboMain ), 1 ); - gtk_widget_show( comboMain ); - - tw1.one = textFrontBackTex; - tw1.two = comboMain; - - buttonSetMain = gtk_button_new_with_label( "Set As Main Texture" ); - gtk_signal_connect( GTK_OBJECT( buttonSetMain ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback_settex ), &tw1 ); - gtk_box_pack_start( GTK_BOX( hbox ), buttonSetMain, FALSE, FALSE, 0 ); - gtk_widget_show( buttonSetMain ); - - // ------------------- // - - hbox = gtk_hbox_new( FALSE, 10 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - comboTrim = gtk_combo_new(); - gtk_box_pack_start( GTK_BOX( hbox ), comboTrim, FALSE, FALSE, 0 ); - gtk_combo_set_popdown_strings( GTK_COMBO( comboTrim ), listTrimTextures ); - gtk_combo_set_use_arrows( GTK_COMBO( comboMain ), 1 ); - gtk_widget_show( comboTrim ); - - tw2.one = textTrimTex; - tw2.two = comboTrim; - - buttonSetTrim = gtk_button_new_with_label( "Set As Trim Texture" ); - gtk_signal_connect( GTK_OBJECT( buttonSetTrim ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback_settex ), &tw2 ); - gtk_box_pack_start( GTK_BOX( hbox ), buttonSetTrim, FALSE, FALSE, 0 ); - gtk_widget_show( buttonSetTrim ); - - // ------------------ // - - hbox = gtk_hbox_new( FALSE, 10 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - w = gtk_label_new( "Orientation" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - - // argh more radio buttons! - radioNS = gtk_radio_button_new_with_label( NULL, "North - South" ); - gtk_box_pack_start( GTK_BOX( hbox ), radioNS, FALSE, FALSE, 0 ); - gtk_widget_show( radioNS ); - - radioOrientation = gtk_radio_button_group( GTK_RADIO_BUTTON( radioNS ) ); - - radioEW = gtk_radio_button_new_with_label( radioOrientation, "East - West" ); - gtk_box_pack_start( GTK_BOX( hbox ), radioEW, FALSE, FALSE, 0 ); - gtk_widget_show( radioEW ); - - // ----------------- // - - w = gtk_hseparator_new(); - gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - - // ----------------- // - - hbox = gtk_hbox_new( FALSE, 10 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - w = gtk_button_new_with_label( "OK" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDOK ) ); - GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); - gtk_widget_grab_default( w ); - gtk_widget_show( w ); - - w = gtk_button_new_with_label( "Cancel" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDCANCEL ) ); - gtk_widget_show( w ); - ret = IDCANCEL; - - // ----------------- // - -//+djbob - gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); - gtk_widget_show (window); - gtk_grab_add (window); - - while (loop) - gtk_main_iteration (); - - strcpy(rs->mainTexture, gtk_entry_get_text( GTK_ENTRY( textFrontBackTex ) )); - strcpy(rs->trimTexture, gtk_entry_get_text( GTK_ENTRY( textTrimTex ) )); - - rs->bScaleMainH = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkScaleMainH)) ? true : false; - rs->bScaleMainV = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkScaleMainV)) ? true : false; - rs->bScaleTrimH = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkScaleTrimH)) ? true : false; - rs->bScaleTrimV = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkScaleTrimV)) ? true : false; - - if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioNS))) - rs->nOrientation = DIRECTION_NS; - else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioEW))) - rs->nOrientation = DIRECTION_EW; - - gtk_grab_remove (window); - gtk_widget_destroy (window); - - return ret; -//-djbob -} - -int DoPathPlotterBox(PathPlotterRS* rs) -{ - GtkWidget *window, *w, *vbox, *hbox; - - GtkWidget *text1, *text2, *text3; - GtkWidget *check1, *check2; - - int ret, loop = 1; - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - - gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - - gtk_window_set_title (GTK_WINDOW (window), "Texture Reset"); - gtk_container_border_width (GTK_CONTAINER (window), 10); - - g_object_set_data (G_OBJECT (window), "loop", &loop); - g_object_set_data (G_OBJECT (window), "ret", &ret); - - gtk_widget_realize (window); - - - - vbox = gtk_vbox_new (FALSE, 10); - gtk_container_add (GTK_CONTAINER (window), vbox); - gtk_widget_show (vbox); - - // ---- vbox ---- - - hbox = gtk_hbox_new (FALSE, 10); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); - gtk_widget_show (hbox); - - // ---- hbox ---- - - text1 = gtk_entry_new_with_max_length(256); - gtk_entry_set_text((GtkEntry*)text1, "25"); - gtk_box_pack_start (GTK_BOX (hbox), text1, FALSE, FALSE, 2); - gtk_widget_show (text1); - - w = gtk_label_new ("Number Of Points"); - gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 2); - gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); - gtk_widget_show (w); - - // ---- /hbox ---- - - hbox = gtk_hbox_new (FALSE, 10); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); - gtk_widget_show (hbox); - - // ---- hbox ---- - - text2 = gtk_entry_new_with_max_length(256); - gtk_entry_set_text((GtkEntry*)text2, "3"); - gtk_box_pack_start (GTK_BOX (hbox), text2, FALSE, FALSE, 2); - gtk_widget_show (text2); - - w = gtk_label_new ("Multipler"); - gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 2); - gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); - gtk_widget_show (w); - - // ---- /hbox ---- - - w = gtk_label_new ("Path Distance = dist(start -> apex) * multiplier"); - gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 0); - gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); - gtk_widget_show (w); - - hbox = gtk_hbox_new (FALSE, 10); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); - gtk_widget_show (hbox); - - // ---- hbox ---- - - text3 = gtk_entry_new_with_max_length(256); - gtk_entry_set_text((GtkEntry*)text3, "-800"); - gtk_box_pack_start (GTK_BOX (hbox), text3, FALSE, FALSE, 2); - gtk_widget_show (text3); - - w = gtk_label_new ("Gravity"); - gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 2); - gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); - gtk_widget_show (w); - - // ---- /hbox ---- - - w = gtk_hseparator_new(); - gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - - check1 = gtk_check_button_new_with_label( "No Dynamic Update" ); - gtk_box_pack_start( GTK_BOX( vbox ), check1, FALSE, FALSE, 0 ); - gtk_widget_show( check1 ); - - check2 = gtk_check_button_new_with_label( "Show Bounding Lines" ); - gtk_box_pack_start( GTK_BOX( vbox ), check2, FALSE, FALSE, 0 ); - gtk_widget_show( check2 ); - - // ---- /vbox ---- - - - // ----------------- // - - w = gtk_hseparator_new(); - gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - - // ----------------- // - - hbox = gtk_hbox_new( FALSE, 10 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - w = gtk_button_new_with_label( "Enable" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDYES ) ); - gtk_widget_show( w ); - - GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); - gtk_widget_grab_default( w ); - - w = gtk_button_new_with_label( "Disable" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDNO ) ); - gtk_widget_show( w ); - - w = gtk_button_new_with_label( "Cancel" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDCANCEL ) ); - gtk_widget_show( w ); - - ret = IDCANCEL; - - // ----------------- // - - gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); - gtk_widget_show (window); - gtk_grab_add (window); - - bool dialogError = TRUE; - while (dialogError) - { - loop = 1; - while (loop) - gtk_main_iteration (); - - dialogError = FALSE; - - if(ret == IDYES) - { - if(!ValidateTextIntRange(gtk_entry_get_text(GTK_ENTRY(text1)), 1, 200, "Number Of Points", &rs->nPoints)) - dialogError = TRUE; - - if(!ValidateTextFloatRange(gtk_entry_get_text(GTK_ENTRY(text2)), 1.0f, 10.0f, "Multiplier", &rs->fMultiplier)) - dialogError = TRUE; - - if(!ValidateTextFloatRange(gtk_entry_get_text(GTK_ENTRY(text3)), -10000.0f, -1.0f, "Gravity", &rs->fGravity)) - dialogError = TRUE; - - rs->bNoUpdate = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check1)) ? true : false; - rs->bShowExtra = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check2)) ? true : false; - } - } - - gtk_grab_remove (window); - gtk_widget_destroy (window); - - return ret; -} - -int DoCTFColourChangeBox () -{ - GtkWidget *window, *w, *vbox, *hbox; - int ret, loop = 1; - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - - gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - - gtk_window_set_title (GTK_WINDOW (window), "CTF Colour Changer"); - gtk_container_border_width (GTK_CONTAINER (window), 10); - - g_object_set_data (G_OBJECT (window), "loop", &loop); - g_object_set_data (G_OBJECT (window), "ret", &ret); - - gtk_widget_realize (window); - - - - vbox = gtk_vbox_new (FALSE, 10); - gtk_container_add (GTK_CONTAINER (window), vbox); - gtk_widget_show (vbox); - - // ---- vbox ---- - - hbox = gtk_hbox_new( FALSE, 10 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, TRUE, TRUE, 0 ); - gtk_widget_show( hbox ); - - // ---- hbox ---- ok/cancel buttons - - w = gtk_button_new_with_label ("Red->Blue"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - - GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); - gtk_widget_grab_default (w); - gtk_widget_show (w); - - w = gtk_button_new_with_label ("Blue->Red"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); - gtk_widget_show (w); - - w = gtk_button_new_with_label ("Cancel"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_show (w); - ret = IDCANCEL; - - // ---- /hbox ---- - - // ---- /vbox ---- - - gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); - gtk_widget_show (window); - gtk_grab_add (window); - - while (loop) - gtk_main_iteration (); - - gtk_grab_remove (window); - gtk_widget_destroy (window); - - return ret; -} - -int DoResetTextureBox (ResetTextureRS* rs) -{ - Str texSelected; - - GtkWidget *window, *w, *vbox, *hbox, *frame, *table; - - int ret, loop = 1; - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - - gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - - gtk_window_set_title (GTK_WINDOW (window), "Texture Reset"); - gtk_container_border_width (GTK_CONTAINER (window), 10); - - g_object_set_data (G_OBJECT (window), "loop", &loop); - g_object_set_data (G_OBJECT (window), "ret", &ret); - - gtk_widget_realize (window); - - vbox = gtk_vbox_new (FALSE, 10); - gtk_container_add (GTK_CONTAINER (window), vbox); - gtk_widget_show (vbox); - - // ---- vbox ---- - - hbox = gtk_hbox_new (FALSE, 10); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); - gtk_widget_show (hbox); - - // ---- hbox ---- - - texSelected = "Currently Selected Face: "; - if(g_SelectedFaceTable.m_pfnGetSelectedFaceCount() == 1) { - texSelected += GetCurrentTexture(); - } - - w = gtk_label_new (texSelected); - gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 2); - gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); - gtk_widget_show (w); - - // ---- /hbox ---- - - frame = gtk_frame_new ("Reset Texture Names"); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); - - table = gtk_table_new (2, 3, TRUE); - gtk_widget_show (table); - gtk_container_add (GTK_CONTAINER (frame), table); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - gtk_container_set_border_width (GTK_CONTAINER (table), 5); - - // ---- frame ---- - - dlgTexReset.cbTexChange = gtk_check_button_new_with_label("Enabled"); - gtk_signal_connect (GTK_OBJECT (dlgTexReset.cbTexChange), "toggled", GTK_SIGNAL_FUNC (dialog_button_callback_texreset_update), NULL); - gtk_widget_show (dlgTexReset.cbTexChange); - gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbTexChange, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - w = gtk_label_new ("Old Name: "); - gtk_table_attach (GTK_TABLE (table), w, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (w); - - dlgTexReset.editTexOld = gtk_entry_new_with_max_length(256); - gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editTexOld), rs->textureName); - gtk_table_attach (GTK_TABLE (table), dlgTexReset.editTexOld, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (dlgTexReset.editTexOld); - - w = gtk_label_new ("New Name: "); - gtk_table_attach (GTK_TABLE (table), w, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (w); - - dlgTexReset.editTexNew = gtk_entry_new_with_max_length(256); - gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editTexNew), rs->textureName); - gtk_table_attach (GTK_TABLE (table), dlgTexReset.editTexNew, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (dlgTexReset.editTexNew); - - // ---- /frame ---- - - frame = gtk_frame_new ("Reset Scales"); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); - - table = gtk_table_new (2, 3, TRUE); - gtk_widget_show (table); - gtk_container_add (GTK_CONTAINER (frame), table); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - gtk_container_set_border_width (GTK_CONTAINER (table), 5); - - // ---- frame ---- - - dlgTexReset.cbScaleHor = gtk_check_button_new_with_label("Enabled"); - gtk_signal_connect (GTK_OBJECT (dlgTexReset.cbScaleHor), "toggled", GTK_SIGNAL_FUNC (dialog_button_callback_texreset_update), NULL); - gtk_widget_show (dlgTexReset.cbScaleHor); - gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbScaleHor, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - w = gtk_label_new ("New Horizontal Scale: "); - gtk_table_attach (GTK_TABLE (table), w, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (w); - - dlgTexReset.editScaleHor = gtk_entry_new_with_max_length(256); - gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editScaleHor), "0.5"); - gtk_table_attach (GTK_TABLE (table), dlgTexReset.editScaleHor, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (dlgTexReset.editScaleHor); - - - dlgTexReset.cbScaleVert = gtk_check_button_new_with_label("Enabled"); - gtk_signal_connect (GTK_OBJECT (dlgTexReset.cbScaleVert), "toggled", GTK_SIGNAL_FUNC (dialog_button_callback_texreset_update), NULL); - gtk_widget_show (dlgTexReset.cbScaleVert); - gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbScaleVert, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - w = gtk_label_new ("New Vertical Scale: "); - gtk_table_attach (GTK_TABLE (table), w, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (w); - - dlgTexReset.editScaleVert = gtk_entry_new_with_max_length(256); - gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editScaleVert), "0.5"); - gtk_table_attach (GTK_TABLE (table), dlgTexReset.editScaleVert, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (dlgTexReset.editScaleVert); - - // ---- /frame ---- - - frame = gtk_frame_new ("Reset Shift"); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); - - table = gtk_table_new (2, 3, TRUE); - gtk_widget_show (table); - gtk_container_add (GTK_CONTAINER (frame), table); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - gtk_container_set_border_width (GTK_CONTAINER (table), 5); - - // ---- frame ---- - - dlgTexReset.cbShiftHor = gtk_check_button_new_with_label("Enabled"); - gtk_signal_connect (GTK_OBJECT (dlgTexReset.cbShiftHor), "toggled", GTK_SIGNAL_FUNC (dialog_button_callback_texreset_update), NULL); - gtk_widget_show (dlgTexReset.cbShiftHor); - gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbShiftHor, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - w = gtk_label_new ("New Horizontal Shift: "); - gtk_table_attach (GTK_TABLE (table), w, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (w); - - dlgTexReset.editShiftHor = gtk_entry_new_with_max_length(256); - gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editShiftHor), "0"); - gtk_table_attach (GTK_TABLE (table), dlgTexReset.editShiftHor, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (dlgTexReset.editShiftHor); - - - dlgTexReset.cbShiftVert = gtk_check_button_new_with_label("Enabled"); - gtk_signal_connect (GTK_OBJECT (dlgTexReset.cbShiftVert), "toggled", GTK_SIGNAL_FUNC (dialog_button_callback_texreset_update), NULL); - gtk_widget_show (dlgTexReset.cbShiftVert); - gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbShiftVert, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - w = gtk_label_new ("New Vertical Shift: "); - gtk_table_attach (GTK_TABLE (table), w, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (w); - - dlgTexReset.editShiftVert = gtk_entry_new_with_max_length(256); - gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editShiftVert), "0"); - gtk_table_attach (GTK_TABLE (table), dlgTexReset.editShiftVert, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (dlgTexReset.editShiftVert); - - // ---- /frame ---- - - frame = gtk_frame_new ("Reset Rotation"); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); - - table = gtk_table_new (1, 3, TRUE); - gtk_widget_show (table); - gtk_container_add (GTK_CONTAINER (frame), table); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - gtk_container_set_border_width (GTK_CONTAINER (table), 5); - - // ---- frame ---- - - dlgTexReset.cbRotation = gtk_check_button_new_with_label("Enabled"); - gtk_widget_show (dlgTexReset.cbRotation); - gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbRotation, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - w = gtk_label_new ("New Rotation Value: "); - gtk_table_attach (GTK_TABLE (table), w, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (w); - - dlgTexReset.editRotation = gtk_entry_new_with_max_length(256); - gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editRotation), "0"); - gtk_table_attach (GTK_TABLE (table), dlgTexReset.editRotation, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (dlgTexReset.editRotation); - - // ---- /frame ---- - - hbox = gtk_hbox_new (FALSE, 10); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); - gtk_widget_show (hbox); - - // ---- hbox ---- - - w = gtk_button_new_with_label ("Use Selected Brushes"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - - GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); - gtk_widget_grab_default (w); - gtk_widget_show (w); - - w = gtk_button_new_with_label ("Use All Brushes"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); - gtk_widget_show (w); - - w = gtk_button_new_with_label ("Cancel"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_show (w); - ret = IDCANCEL; - - // ---- /hbox ---- - - // ---- /vbox ---- - - gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); - gtk_widget_show (window); - gtk_grab_add (window); - - Update_TextureReseter(); - - bool dialogError = TRUE; - while (dialogError) - { - loop = 1; - while (loop) - gtk_main_iteration (); - - dialogError = FALSE; - - if(ret != IDCANCEL) - { - rs->bResetRotation = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbRotation )); - if(rs->bResetRotation) - if(!ValidateTextInt(gtk_entry_get_text(GTK_ENTRY(dlgTexReset.editRotation)), "Rotation", &rs->rotation)) - dialogError = TRUE; - - rs->bResetScale[0] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbScaleHor )); - if(rs->bResetScale[0]) - if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(dlgTexReset.editScaleHor)), "Horizontal Scale", &rs->fScale[0])) - dialogError = TRUE; - - rs->bResetScale[1] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbScaleVert )); - if(rs->bResetScale[1]) - if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(dlgTexReset.editScaleVert)), "Vertical Scale", &rs->fScale[1])) - dialogError = TRUE; - - rs->bResetShift[0] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbShiftHor )); - if(rs->bResetShift[0]) - if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(dlgTexReset.editShiftHor)), "Horizontal Shift", &rs->fShift[0])) - dialogError = TRUE; - - rs->bResetShift[1] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbShiftVert )); - if(rs->bResetShift[1]) - if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(dlgTexReset.editShiftVert)), "Vertical Shift", &rs->fShift[1])) - dialogError = TRUE; - - rs->bResetTextureName = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbTexChange )); - if(rs->bResetTextureName) - { - strcpy(rs->textureName, gtk_entry_get_text(GTK_ENTRY( dlgTexReset.editTexOld ))); - strcpy(rs->newTextureName, gtk_entry_get_text(GTK_ENTRY( dlgTexReset.editTexNew ))); - } - } - } - - gtk_grab_remove (window); - gtk_widget_destroy (window); - - return ret; -} - -int DoTrainThingBox (TrainThingRS* rs) -{ - Str texSelected; - - GtkWidget *window, *w, *vbox, *hbox, *frame, *table; - - GtkWidget *radiusX, *radiusY; - GtkWidget *angleStart, *angleEnd; - GtkWidget *heightStart, *heightEnd; - GtkWidget *numPoints; - - int ret, loop = 1; - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - - gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - - gtk_window_set_title (GTK_WINDOW (window), "Train Thing"); - gtk_container_border_width (GTK_CONTAINER (window), 10); - - gtk_object_set_data (GTK_OBJECT (window), "loop", &loop); - gtk_object_set_data (GTK_OBJECT (window), "ret", &ret); - - gtk_widget_realize (window); - - vbox = gtk_vbox_new (FALSE, 10); - gtk_container_add (GTK_CONTAINER (window), vbox); - gtk_widget_show (vbox); - - // ---- vbox ---- - - hbox = gtk_hbox_new (FALSE, 10); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); - gtk_widget_show (hbox); - - // ---- /hbox ---- - - frame = gtk_frame_new ("Radii"); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); - - table = gtk_table_new (2, 3, TRUE); - gtk_widget_show (table); - gtk_container_add (GTK_CONTAINER (frame), table); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - gtk_container_set_border_width (GTK_CONTAINER (table), 5); - - // ---- frame ---- - - w = gtk_label_new ("X: "); - gtk_table_attach (GTK_TABLE (table), w, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (w); - - radiusX = gtk_entry_new_with_max_length(256); - gtk_entry_set_text(GTK_ENTRY(radiusX), "100"); - gtk_table_attach (GTK_TABLE (table), radiusX, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (radiusX); - - - - w = gtk_label_new ("Y: "); - gtk_table_attach (GTK_TABLE (table), w, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (w); - - radiusY = gtk_entry_new_with_max_length(256); - gtk_entry_set_text(GTK_ENTRY(radiusY), "100"); - gtk_table_attach (GTK_TABLE (table), radiusY, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (radiusY); - - - - frame = gtk_frame_new ("Angles"); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); - - table = gtk_table_new (2, 3, TRUE); - gtk_widget_show (table); - gtk_container_add (GTK_CONTAINER (frame), table); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - gtk_container_set_border_width (GTK_CONTAINER (table), 5); - - // ---- frame ---- - - w = gtk_label_new ("Start: "); - gtk_table_attach (GTK_TABLE (table), w, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (w); - - angleStart = gtk_entry_new_with_max_length(256); - gtk_entry_set_text(GTK_ENTRY(angleStart), "0"); - gtk_table_attach (GTK_TABLE (table), angleStart, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (angleStart); - - - - w = gtk_label_new ("End: "); - gtk_table_attach (GTK_TABLE (table), w, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (w); - - angleEnd = gtk_entry_new_with_max_length(256); - gtk_entry_set_text(GTK_ENTRY(angleEnd), "90"); - gtk_table_attach (GTK_TABLE (table), angleEnd, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (angleEnd); - - - frame = gtk_frame_new ("Height"); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); - - table = gtk_table_new (2, 3, TRUE); - gtk_widget_show (table); - gtk_container_add (GTK_CONTAINER (frame), table); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - gtk_container_set_border_width (GTK_CONTAINER (table), 5); - - // ---- frame ---- - - w = gtk_label_new ("Start: "); - gtk_table_attach (GTK_TABLE (table), w, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (w); - - heightStart = gtk_entry_new_with_max_length(256); - gtk_entry_set_text(GTK_ENTRY(heightStart), "0"); - gtk_table_attach (GTK_TABLE (table), heightStart, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (heightStart); - - - - w = gtk_label_new ("End: "); - gtk_table_attach (GTK_TABLE (table), w, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (w); - - heightEnd = gtk_entry_new_with_max_length(256); - gtk_entry_set_text(GTK_ENTRY(heightEnd), "0"); - gtk_table_attach (GTK_TABLE (table), heightEnd, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (heightEnd); - - - - frame = gtk_frame_new ("Points"); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); - - table = gtk_table_new (2, 3, TRUE); - gtk_widget_show (table); - gtk_container_add (GTK_CONTAINER (frame), table); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - gtk_container_set_border_width (GTK_CONTAINER (table), 5); - - // ---- frame ---- - - w = gtk_label_new ("Number: "); - gtk_table_attach (GTK_TABLE (table), w, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (w); - - numPoints = gtk_entry_new_with_max_length(256); - gtk_entry_set_text(GTK_ENTRY(numPoints), "0"); - gtk_table_attach (GTK_TABLE (table), numPoints, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_show (numPoints); - - - hbox = gtk_hbox_new (FALSE, 10); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); - gtk_widget_show (hbox); - - // ---- hbox ---- - - w = gtk_button_new_with_label ("Ok"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - - GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); - gtk_widget_grab_default (w); - gtk_widget_show (w); - - w = gtk_button_new_with_label ("Cancel"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_show (w); - ret = IDCANCEL; - - // ---- /hbox ---- - - - - gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); - gtk_widget_show (window); - gtk_grab_add (window); - - bool dialogError = TRUE; - while (dialogError) - { - loop = 1; - while (loop) - gtk_main_iteration (); - - dialogError = FALSE; - - if(ret != IDCANCEL) - { - if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(radiusX)), "Radius (X)", &rs->fRadiusX)) - dialogError = TRUE; - - if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(radiusY)), "Radius (Y)", &rs->fRadiusY)) - dialogError = TRUE; - - if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(angleStart)), "Angle (Start)", &rs->fStartAngle)) - dialogError = TRUE; - - if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(angleEnd)), "Angle (End)", &rs->fEndAngle)) - dialogError = TRUE; - - if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(heightStart)), "Height (Start)", &rs->fStartHeight)) - dialogError = TRUE; - - if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(heightEnd)), "Height (End)", &rs->fEndHeight)) - dialogError = TRUE; - - if(!ValidateTextInt(gtk_entry_get_text(GTK_ENTRY(numPoints)), "Num Points", &rs->iNumPoints)) - dialogError = TRUE; - } - } - - gtk_grab_remove (window); - gtk_widget_destroy (window); - - return ret; -} +/* +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 +*/ + +#include "../StdAfx.h" +#include "dialogs-gtk.h" +#include "../funchandlers.h" +#include "../lists.h" +#include "../misc.h" + +/*-------------------------------- + Callback Functions +---------------------------------*/ + +typedef struct { + GtkWidget *cbTexChange; + GtkWidget *editTexOld, *editTexNew; + + GtkWidget *cbScaleHor, *cbScaleVert; + GtkWidget *editScaleHor, *editScaleVert; + + GtkWidget *cbShiftHor, *cbShiftVert; + GtkWidget *editShiftHor, *editShiftVert; + + GtkWidget *cbRotation; + GtkWidget *editRotation; +}dlg_texReset_t; + +dlg_texReset_t dlgTexReset; + +void Update_TextureReseter(); + +static void dialog_button_callback_texreset_update (GtkWidget *widget, gpointer data) +{ + Update_TextureReseter(); +} + +void Update_TextureReseter() +{ + gboolean check; + + check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbTexChange )); + gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editTexNew), check); + gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editTexOld), check); + + check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbScaleHor )); + gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editScaleHor), check); + + check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbScaleVert )); + gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editScaleVert), check); + + check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbShiftHor )); + gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editShiftHor), check); + + check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbShiftVert )); + gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editShiftVert), check); + + check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbRotation )); + gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editRotation), check); +} + +static void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} + +static void dialog_button_callback_settex (GtkWidget *widget, gpointer data) +{ + TwinWidget* tw = (TwinWidget*)data; + + GtkEntry* entry = GTK_ENTRY( tw->one ); + GtkCombo* combo = GTK_COMBO( tw->two ); + + const gchar* tex = gtk_entry_get_text(GTK_ENTRY( combo->entry )); + gtk_entry_set_text( entry, tex); +} + +/*-------------------------------- + Data validation Routines +---------------------------------*/ + +bool ValidateTextFloat(const char* pData, char* error_title, float* value) +{ + if(pData) + { + float testNum = (float)atof(pData); + + if((testNum == 0.0f) && strcmp(pData, "0")) + { + DoMessageBox("Please Enter A Floating Point Number", error_title, MB_OK); + return FALSE; + } + else + { + *value = testNum; + return TRUE; + } + } + + DoMessageBox("Please Enter A Floating Point Number", error_title, MB_OK); + return FALSE; +} + +bool ValidateTextFloatRange(const char* pData, float min, float max, char* error_title, float* value) +{ + char error_buffer[256]; + sprintf(error_buffer, "Please Enter A Floating Point Number Between %.3f and %.3f", min, max); + + if(pData) + { + float testNum = (float)atof(pData); + + if((testNum < min) || (testNum > max)) + { + DoMessageBox(error_buffer, error_title, MB_OK); + return FALSE; + } + else + { + *value = testNum; + return TRUE; + } + } + + DoMessageBox(error_buffer, error_title, MB_OK); + return FALSE; +} + +bool ValidateTextIntRange(const char* pData, int min, int max, char* error_title, int* value) +{ + char error_buffer[256]; + sprintf(error_buffer, "Please Enter An Integer Between %i and %i", min, max); + + if(pData) + { + int testNum = atoi(pData); + + if((testNum < min) || (testNum > max)) + { + DoMessageBox(error_buffer, error_title, MB_OK); + return FALSE; + } + else + { + *value = testNum; + return TRUE; + } + } + + DoMessageBox(error_buffer, error_title, MB_OK); + return FALSE; +} + +bool ValidateTextInt(const char* pData, char* error_title, int* value) +{ + if(pData) + { + int testNum = atoi(pData); + + if((testNum == 0) && strcmp(pData, "0")) + { + DoMessageBox("Please Enter An Integer", error_title, MB_OK); + return FALSE; + } + else + { + *value = testNum; + return TRUE; + } + } + + DoMessageBox("Please Enter An Integer", error_title, MB_OK); + return FALSE; +} + +/*-------------------------------- + Modal Dialog Boxes +---------------------------------*/ + +/* + + Major clean up of variable names etc required, excluding Mars's ones, + which are nicely done :) + +*/ + +int DoMessageBox (const char* lpText, const char* lpCaption, guint32 uType) +{ + GtkWidget *window, *w, *vbox, *hbox; + int mode = (uType & MB_TYPEMASK), ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_window_set_title (GTK_WINDOW (window), lpCaption); + gtk_container_border_width (GTK_CONTAINER (window), 10); + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + gtk_widget_realize (window); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + w = gtk_label_new (lpText); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + if (mode == MB_OK) + { + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + ret = IDOK; + } + else if (mode == MB_OKCANCEL) + { + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + } + else if (mode == MB_YESNOCANCEL) + { + w = gtk_button_new_with_label ("Yes"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("No"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO)); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + } + else /* if (mode == MB_YESNO) */ + { + w = gtk_button_new_with_label ("Yes"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("No"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO)); + gtk_widget_show (w); + ret = IDNO; + } + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} + +int DoIntersectBox (IntersectRS* rs) +{ + GtkWidget *window, *w, *vbox, *hbox; + GtkWidget *radio1, *radio2; + GtkWidget *check1, *check2; + int ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title (GTK_WINDOW (window), "Intersect"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + // ---- vbox ---- + + radio1 = gtk_radio_button_new_with_label(NULL, "Use Whole Map"); + gtk_box_pack_start (GTK_BOX (vbox), radio1, FALSE, FALSE, 2); + gtk_widget_show (radio1); + + radio2 = gtk_radio_button_new_with_label(((GtkRadioButton*)radio1)->group, "Use Selected Brushes"); + gtk_box_pack_start (GTK_BOX (vbox), radio2, FALSE, FALSE, 2); + gtk_widget_show (radio2); + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + check1 = gtk_check_button_new_with_label("Include Detail Brushes"); + gtk_box_pack_start (GTK_BOX (vbox), check1, FALSE, FALSE, 0); + gtk_widget_show (check1); + + check2 = gtk_check_button_new_with_label("Select Duplicate Brushes Only"); + gtk_box_pack_start (GTK_BOX (vbox), check2, FALSE, FALSE, 0); + gtk_widget_show (check2); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- ok/cancel buttons + + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // ---- /hbox ---- + + // ---- /vbox ---- + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + while (loop) + gtk_main_iteration (); + + if(gtk_toggle_button_get_active((GtkToggleButton*)radio1)) + rs->nBrushOptions = BRUSH_OPT_WHOLE_MAP; + else if(gtk_toggle_button_get_active((GtkToggleButton*)radio2)) + rs->nBrushOptions = BRUSH_OPT_SELECTED; + + rs->bUseDetail = gtk_toggle_button_get_active((GtkToggleButton*)check1) ? true : false; + rs->bDuplicateOnly = gtk_toggle_button_get_active((GtkToggleButton*)check2) ? true : false; + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} + +int DoPolygonBox (PolygonRS* rs) +{ + GtkWidget *window, *w, *vbox, *hbox, *vbox2, *hbox2; + + GtkWidget *check1, *check2, *check3; + GtkWidget *text1, *text2; + + int ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title (GTK_WINDOW (window), "Polygon Builder"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + // ---- vbox ---- + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + + vbox2 = gtk_vbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 2); + gtk_widget_show (vbox2); + + // ---- vbox2 ---- + + hbox2 = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox2), hbox2, FALSE, FALSE, 2); + gtk_widget_show (hbox2); + + // ---- hbox2 ---- + + text1 = gtk_entry_new_with_max_length(256); + gtk_entry_set_text((GtkEntry*)text1, "3"); + gtk_box_pack_start (GTK_BOX (hbox2), text1, FALSE, FALSE, 2); + gtk_widget_show (text1); + + w = gtk_label_new ("Number Of Sides"); + gtk_box_pack_start (GTK_BOX (hbox2), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + // ---- /hbox2 ---- + + hbox2 = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox2), hbox2, FALSE, FALSE, 2); + gtk_widget_show (hbox2); + + // ---- hbox2 ---- + + text2 = gtk_entry_new_with_max_length(256); + gtk_entry_set_text((GtkEntry*)text2, "8"); + gtk_box_pack_start (GTK_BOX (hbox2), text2, FALSE, FALSE, 2); + gtk_widget_show (text2); + + w = gtk_label_new ("Border Width"); + gtk_box_pack_start (GTK_BOX (hbox2), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + // ---- /hbox2 ---- + + // ---- /vbox2 ---- + + + + vbox2 = gtk_vbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 2); + gtk_widget_show (vbox2); + + // ---- vbox2 ---- + + check1 = gtk_check_button_new_with_label("Use Border"); + gtk_box_pack_start (GTK_BOX (vbox2), check1, FALSE, FALSE, 0); + gtk_widget_show (check1); + + + check2 = gtk_check_button_new_with_label("Inverse Polygon"); + gtk_box_pack_start (GTK_BOX (vbox2), check2, FALSE, FALSE, 0); + gtk_widget_show (check2); + + + check3 = gtk_check_button_new_with_label("Align Top Edge"); + gtk_box_pack_start (GTK_BOX (vbox2), check3, FALSE, FALSE, 0); + gtk_widget_show (check3); + + // ---- /vbox2 ---- + + // ---- /hbox ---- + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // ---- /hbox ---- + + // ---- /vbox ---- + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) + { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if(ret == IDOK) + { + rs->bUseBorder = gtk_toggle_button_get_active((GtkToggleButton*)check1) ? true : false; + rs->bInverse = gtk_toggle_button_get_active((GtkToggleButton*)check2) ? true : false; + rs->bAlignTop = gtk_toggle_button_get_active((GtkToggleButton*)check3) ? true : false; + + if(!ValidateTextIntRange(gtk_entry_get_text((GtkEntry*)text1), 3, 32, "Number Of Sides", &rs->nSides)) + dialogError = TRUE; + + if(rs->bUseBorder) + { + if(!ValidateTextIntRange(gtk_entry_get_text((GtkEntry*)text2), 8, 256, "Border Width", &rs->nBorderWidth)) + dialogError = TRUE; + } + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} + +// mars +// for stair builder stuck as close as i could to the MFC version +// obviously feel free to change it at will :) +int DoBuildStairsBox(BuildStairsRS* rs) +{ + // i made widgets for just about everything ... i think that's what i need to do dunno tho + GtkWidget *window, *w, *vbox, *hbox; + GtkWidget *textStairHeight, *textRiserTex, *textMainTex; + GtkWidget *radioNorth, *radioSouth, *radioEast, *radioWest; // i'm guessing we can't just abuse 'w' for these if we're getting a value + GtkWidget *radioOldStyle, *radioBobStyle, *radioCornerStyle; + GtkWidget *checkUseDetail; + GSList *radioDirection, *radioStyle; + int ret, loop; + + loop = 1; + + char *text = "Please set a value in the boxes below and press 'OK' to build the stairs"; + + window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title( GTK_WINDOW( window ), "Stair Builder" ); + + gtk_container_border_width( GTK_CONTAINER( window ), 10 ); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + // new vbox + vbox = gtk_vbox_new( FALSE, 10 ); + gtk_container_add( GTK_CONTAINER( window ), vbox ); + gtk_widget_show( vbox ); + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_container_add( GTK_CONTAINER( vbox ), hbox ); + gtk_widget_show( hbox ); + + // dunno if you want this text or not ... + w = gtk_label_new( text ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); // not entirely sure on all the parameters / what they do ... + gtk_widget_show( w ); + + w = gtk_hseparator_new(); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + // ------------------------- // indenting == good way of keeping track of lines :) + + // new hbox + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + textStairHeight = gtk_entry_new_with_max_length( 256 ); + gtk_box_pack_start( GTK_BOX( hbox ), textStairHeight, FALSE, FALSE, 1 ); + gtk_widget_show( textStairHeight ); + + w = gtk_label_new( "Stair Height" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 1 ); + gtk_widget_show( w ); + + // ------------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Direction:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 5 ); + gtk_widget_show( w ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + // radio buttons confuse me ... + // but this _looks_ right + + // djbob: actually it looks very nice :), slightly better than the way i did it + // edit: actually it doesn't work :P, you must pass the last radio item each time, ugh + + radioNorth = gtk_radio_button_new_with_label( NULL, "North" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioNorth, FALSE, FALSE, 3 ); + gtk_widget_show( radioNorth ); + + radioDirection = gtk_radio_button_group( GTK_RADIO_BUTTON( radioNorth ) ); + + radioSouth = gtk_radio_button_new_with_label( radioDirection, "South" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioSouth, FALSE, FALSE, 2 ); + gtk_widget_show( radioSouth ); + + radioDirection = gtk_radio_button_group( GTK_RADIO_BUTTON( radioSouth ) ); + + radioEast = gtk_radio_button_new_with_label( radioDirection, "East" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioEast, FALSE, FALSE, 1 ); + gtk_widget_show( radioEast ); + + radioDirection = gtk_radio_button_group( GTK_RADIO_BUTTON( radioEast ) ); + + radioWest = gtk_radio_button_new_with_label( radioDirection, "West" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioWest, FALSE, FALSE, 0 ); + gtk_widget_show( radioWest ); + + // --------------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Style:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 5 ); + gtk_widget_show( w ); + + // --------------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + radioOldStyle = gtk_radio_button_new_with_label( NULL, "Original" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioOldStyle, FALSE, FALSE, 0 ); + gtk_widget_show( radioOldStyle ); + + radioStyle = gtk_radio_button_group( GTK_RADIO_BUTTON( radioOldStyle ) ); + + radioBobStyle = gtk_radio_button_new_with_label( radioStyle, "Bob's Style" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioBobStyle, FALSE, FALSE, 0 ); + gtk_widget_show( radioBobStyle ); + + radioStyle = gtk_radio_button_group( GTK_RADIO_BUTTON( radioBobStyle ) ); + + radioCornerStyle = gtk_radio_button_new_with_label( radioStyle, "Corner Style" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioCornerStyle, FALSE, FALSE, 0 ); + gtk_widget_show( radioCornerStyle ); + + // err, the q3r has an if or something so you need bob style checked before this + // is "ungreyed out" but you'll need to do that, as i suck :) + + // djbob: er.... yeah um, im not at all sure how i'm gonna sort this + // djbob: think we need some button callback functions or smuffin + // FIXME: actually get around to doing what i suggested!!!! + + checkUseDetail = gtk_check_button_new_with_label( "Use Detail Brushes" ); + gtk_box_pack_start( GTK_BOX( hbox ), checkUseDetail, FALSE, FALSE, 0 ); + gtk_widget_show( checkUseDetail ); + + // --------------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + textMainTex = gtk_entry_new_with_max_length( 512 ); + gtk_entry_set_text(GTK_ENTRY(textMainTex), rs->mainTexture); + gtk_box_pack_start( GTK_BOX( hbox ), textMainTex, FALSE, FALSE, 0 ); + gtk_widget_show( textMainTex ); + + w = gtk_label_new( "Main Texture" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 1 ); + gtk_widget_show( w ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + textRiserTex = gtk_entry_new_with_max_length( 512 ); + gtk_box_pack_start( GTK_BOX( hbox ), textRiserTex, FALSE, FALSE, 0 ); + gtk_widget_show( textRiserTex ); + + w = gtk_label_new( "Riser Texture" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 1 ); + gtk_widget_show( w ); + + // -------------------------- // + w = gtk_hseparator_new(); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label( "OK" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDOK ) ); + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Cancel" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDCANCEL ) ); + gtk_widget_show( w ); + + ret = IDCANCEL; + +// +djbob: need our "little" modal loop mars :P + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) + { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if(ret == IDOK) + { + rs->bUseDetail = gtk_toggle_button_get_active((GtkToggleButton*)checkUseDetail) ? true : false; + + strcpy(rs->riserTexture, gtk_entry_get_text((GtkEntry*)textRiserTex)); + strcpy(rs->mainTexture, gtk_entry_get_text((GtkEntry*)textMainTex)); + + if(gtk_toggle_button_get_active((GtkToggleButton*)radioNorth)) + rs->direction = MOVE_NORTH; + else if(gtk_toggle_button_get_active((GtkToggleButton*)radioSouth)) + rs->direction = MOVE_SOUTH; + else if(gtk_toggle_button_get_active((GtkToggleButton*)radioEast)) + rs->direction = MOVE_EAST; + else if(gtk_toggle_button_get_active((GtkToggleButton*)radioWest)) + rs->direction = MOVE_WEST; + + if(!ValidateTextInt(gtk_entry_get_text((GtkEntry*)textStairHeight), "Stair Height", &rs->stairHeight)) + dialogError = TRUE; + + if(gtk_toggle_button_get_active((GtkToggleButton*)radioOldStyle)) + rs->style = STYLE_ORIGINAL; + else if(gtk_toggle_button_get_active((GtkToggleButton*)radioBobStyle)) + rs->style = STYLE_BOB; + else if(gtk_toggle_button_get_active((GtkToggleButton*)radioCornerStyle)) + rs->style = STYLE_CORNER; + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +// -djbob + + // there we go, all done ... on my end at least, not bad for a night's work +} + +int DoDoorsBox(DoorRS* rs) +{ + GtkWidget *window, *hbox, *vbox, *w; + GtkWidget *textFrontBackTex, *textTrimTex; + GtkWidget *checkScaleMainH, *checkScaleMainV, *checkScaleTrimH, *checkScaleTrimV; + GtkWidget *comboMain, *comboTrim; + GtkWidget *buttonSetMain, *buttonSetTrim; + GtkWidget *radioNS, *radioEW; + GSList *radioOrientation; + TwinWidget tw1, tw2; + int ret, loop; + + loop = 1; + + window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title( GTK_WINDOW( window ), "Door Builder" ); + + gtk_container_border_width( GTK_CONTAINER( window ), 10 ); + + g_object_set_data( G_OBJECT( window ), "loop", &loop ); + g_object_set_data( G_OBJECT( window ), "ret", &ret ); + + gtk_widget_realize (window); + + char buffer[256]; + GList *listMainTextures = NULL; + GList *listTrimTextures = NULL; + LoadGList(GetFilename(buffer, "plugins/bt/door-tex.txt"), &listMainTextures); + LoadGList(GetFilename(buffer, "plugins/bt/door-tex-trim.txt"), &listTrimTextures); + + vbox = gtk_vbox_new( FALSE, 10 ); + gtk_container_add( GTK_CONTAINER( window ), vbox ); + gtk_widget_show( vbox ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + textFrontBackTex = gtk_entry_new_with_max_length( 512 ); + gtk_entry_set_text( GTK_ENTRY( textFrontBackTex ), rs->mainTexture); + gtk_box_pack_start( GTK_BOX( hbox ), textFrontBackTex, FALSE, FALSE, 0 ); + gtk_widget_show( textFrontBackTex ); + + w = gtk_label_new( "Door Front/Back Texture" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + // ------------------------ // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + textTrimTex = gtk_entry_new_with_max_length( 512 ); + gtk_box_pack_start( GTK_BOX( hbox ), textTrimTex, FALSE, FALSE, 0 ); + gtk_widget_show( textTrimTex ); + + w = gtk_label_new( "Door Trim Texture" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + // ----------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + // sp: horizontally ???? + // djbob: yes mars, u can spell :] + checkScaleMainH = gtk_check_button_new_with_label( "Scale Main Texture Horizontally" ); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( checkScaleMainH ), TRUE); + gtk_box_pack_start( GTK_BOX( hbox ), checkScaleMainH, FALSE, FALSE, 0 ); + gtk_widget_show( checkScaleMainH ); + + checkScaleTrimH = gtk_check_button_new_with_label( "Scale Trim Texture Horizontally" ); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( checkScaleTrimH ), TRUE); + gtk_box_pack_start( GTK_BOX( hbox ), checkScaleTrimH, FALSE, FALSE, 0 ); + gtk_widget_show( checkScaleTrimH ); + + // ---------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + checkScaleMainV = gtk_check_button_new_with_label( "Scale Main Texture Vertically" ); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( checkScaleMainV ), TRUE); + gtk_box_pack_start( GTK_BOX( hbox ), checkScaleMainV, FALSE, FALSE, 0 ); + gtk_widget_show( checkScaleMainV ); + + checkScaleTrimV = gtk_check_button_new_with_label( "Scale Trim Texture Vertically" ); + gtk_box_pack_start( GTK_BOX( hbox ), checkScaleTrimV, FALSE, FALSE, 0 ); + gtk_widget_show( checkScaleTrimV ); + + // --------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + // djbob: lists added + + comboMain = gtk_combo_new(); + gtk_box_pack_start( GTK_BOX( hbox ), comboMain, FALSE, FALSE, 0 ); + gtk_combo_set_popdown_strings( GTK_COMBO( comboMain ), listMainTextures ); + gtk_combo_set_use_arrows( GTK_COMBO( comboMain ), 1 ); + gtk_widget_show( comboMain ); + + tw1.one = textFrontBackTex; + tw1.two = comboMain; + + buttonSetMain = gtk_button_new_with_label( "Set As Main Texture" ); + gtk_signal_connect( GTK_OBJECT( buttonSetMain ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback_settex ), &tw1 ); + gtk_box_pack_start( GTK_BOX( hbox ), buttonSetMain, FALSE, FALSE, 0 ); + gtk_widget_show( buttonSetMain ); + + // ------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + comboTrim = gtk_combo_new(); + gtk_box_pack_start( GTK_BOX( hbox ), comboTrim, FALSE, FALSE, 0 ); + gtk_combo_set_popdown_strings( GTK_COMBO( comboTrim ), listTrimTextures ); + gtk_combo_set_use_arrows( GTK_COMBO( comboMain ), 1 ); + gtk_widget_show( comboTrim ); + + tw2.one = textTrimTex; + tw2.two = comboTrim; + + buttonSetTrim = gtk_button_new_with_label( "Set As Trim Texture" ); + gtk_signal_connect( GTK_OBJECT( buttonSetTrim ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback_settex ), &tw2 ); + gtk_box_pack_start( GTK_BOX( hbox ), buttonSetTrim, FALSE, FALSE, 0 ); + gtk_widget_show( buttonSetTrim ); + + // ------------------ // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Orientation" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + // argh more radio buttons! + radioNS = gtk_radio_button_new_with_label( NULL, "North - South" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioNS, FALSE, FALSE, 0 ); + gtk_widget_show( radioNS ); + + radioOrientation = gtk_radio_button_group( GTK_RADIO_BUTTON( radioNS ) ); + + radioEW = gtk_radio_button_new_with_label( radioOrientation, "East - West" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioEW, FALSE, FALSE, 0 ); + gtk_widget_show( radioEW ); + + // ----------------- // + + w = gtk_hseparator_new(); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + // ----------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label( "OK" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDOK ) ); + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Cancel" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDCANCEL ) ); + gtk_widget_show( w ); + ret = IDCANCEL; + + // ----------------- // + +//+djbob + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + while (loop) + gtk_main_iteration (); + + strcpy(rs->mainTexture, gtk_entry_get_text( GTK_ENTRY( textFrontBackTex ) )); + strcpy(rs->trimTexture, gtk_entry_get_text( GTK_ENTRY( textTrimTex ) )); + + rs->bScaleMainH = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkScaleMainH)) ? true : false; + rs->bScaleMainV = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkScaleMainV)) ? true : false; + rs->bScaleTrimH = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkScaleTrimH)) ? true : false; + rs->bScaleTrimV = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkScaleTrimV)) ? true : false; + + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioNS))) + rs->nOrientation = DIRECTION_NS; + else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioEW))) + rs->nOrientation = DIRECTION_EW; + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +//-djbob +} + +int DoPathPlotterBox(PathPlotterRS* rs) +{ + GtkWidget *window, *w, *vbox, *hbox; + + GtkWidget *text1, *text2, *text3; + GtkWidget *check1, *check2; + + int ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title (GTK_WINDOW (window), "Texture Reset"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + // ---- vbox ---- + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + text1 = gtk_entry_new_with_max_length(256); + gtk_entry_set_text((GtkEntry*)text1, "25"); + gtk_box_pack_start (GTK_BOX (hbox), text1, FALSE, FALSE, 2); + gtk_widget_show (text1); + + w = gtk_label_new ("Number Of Points"); + gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + // ---- /hbox ---- + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + text2 = gtk_entry_new_with_max_length(256); + gtk_entry_set_text((GtkEntry*)text2, "3"); + gtk_box_pack_start (GTK_BOX (hbox), text2, FALSE, FALSE, 2); + gtk_widget_show (text2); + + w = gtk_label_new ("Multipler"); + gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + // ---- /hbox ---- + + w = gtk_label_new ("Path Distance = dist(start -> apex) * multiplier"); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + text3 = gtk_entry_new_with_max_length(256); + gtk_entry_set_text((GtkEntry*)text3, "-800"); + gtk_box_pack_start (GTK_BOX (hbox), text3, FALSE, FALSE, 2); + gtk_widget_show (text3); + + w = gtk_label_new ("Gravity"); + gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + // ---- /hbox ---- + + w = gtk_hseparator_new(); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + check1 = gtk_check_button_new_with_label( "No Dynamic Update" ); + gtk_box_pack_start( GTK_BOX( vbox ), check1, FALSE, FALSE, 0 ); + gtk_widget_show( check1 ); + + check2 = gtk_check_button_new_with_label( "Show Bounding Lines" ); + gtk_box_pack_start( GTK_BOX( vbox ), check2, FALSE, FALSE, 0 ); + gtk_widget_show( check2 ); + + // ---- /vbox ---- + + + // ----------------- // + + w = gtk_hseparator_new(); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + // ----------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label( "Enable" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDYES ) ); + gtk_widget_show( w ); + + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + + w = gtk_button_new_with_label( "Disable" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDNO ) ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Cancel" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDCANCEL ) ); + gtk_widget_show( w ); + + ret = IDCANCEL; + + // ----------------- // + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) + { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if(ret == IDYES) + { + if(!ValidateTextIntRange(gtk_entry_get_text(GTK_ENTRY(text1)), 1, 200, "Number Of Points", &rs->nPoints)) + dialogError = TRUE; + + if(!ValidateTextFloatRange(gtk_entry_get_text(GTK_ENTRY(text2)), 1.0f, 10.0f, "Multiplier", &rs->fMultiplier)) + dialogError = TRUE; + + if(!ValidateTextFloatRange(gtk_entry_get_text(GTK_ENTRY(text3)), -10000.0f, -1.0f, "Gravity", &rs->fGravity)) + dialogError = TRUE; + + rs->bNoUpdate = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check1)) ? true : false; + rs->bShowExtra = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check2)) ? true : false; + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} + +int DoCTFColourChangeBox () +{ + GtkWidget *window, *w, *vbox, *hbox; + int ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title (GTK_WINDOW (window), "CTF Colour Changer"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + // ---- vbox ---- + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, TRUE, TRUE, 0 ); + gtk_widget_show( hbox ); + + // ---- hbox ---- ok/cancel buttons + + w = gtk_button_new_with_label ("Red->Blue"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Blue->Red"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // ---- /hbox ---- + + // ---- /vbox ---- + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} + +int DoResetTextureBox (ResetTextureRS* rs) +{ + Str texSelected; + + GtkWidget *window, *w, *vbox, *hbox, *frame, *table; + + int ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title (GTK_WINDOW (window), "Texture Reset"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + // ---- vbox ---- + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + texSelected = "Currently Selected Face: "; + if(g_SelectedFaceTable.m_pfnGetSelectedFaceCount() == 1) { + texSelected += GetCurrentTexture(); + } + + w = gtk_label_new (texSelected); + gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + // ---- /hbox ---- + + frame = gtk_frame_new ("Reset Texture Names"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (2, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + dlgTexReset.cbTexChange = gtk_check_button_new_with_label("Enabled"); + gtk_signal_connect (GTK_OBJECT (dlgTexReset.cbTexChange), "toggled", GTK_SIGNAL_FUNC (dialog_button_callback_texreset_update), NULL); + gtk_widget_show (dlgTexReset.cbTexChange); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbTexChange, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + w = gtk_label_new ("Old Name: "); + gtk_table_attach (GTK_TABLE (table), w, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + dlgTexReset.editTexOld = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editTexOld), rs->textureName); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.editTexOld, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (dlgTexReset.editTexOld); + + w = gtk_label_new ("New Name: "); + gtk_table_attach (GTK_TABLE (table), w, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + dlgTexReset.editTexNew = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editTexNew), rs->textureName); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.editTexNew, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (dlgTexReset.editTexNew); + + // ---- /frame ---- + + frame = gtk_frame_new ("Reset Scales"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (2, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + dlgTexReset.cbScaleHor = gtk_check_button_new_with_label("Enabled"); + gtk_signal_connect (GTK_OBJECT (dlgTexReset.cbScaleHor), "toggled", GTK_SIGNAL_FUNC (dialog_button_callback_texreset_update), NULL); + gtk_widget_show (dlgTexReset.cbScaleHor); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbScaleHor, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + w = gtk_label_new ("New Horizontal Scale: "); + gtk_table_attach (GTK_TABLE (table), w, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + dlgTexReset.editScaleHor = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editScaleHor), "0.5"); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.editScaleHor, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (dlgTexReset.editScaleHor); + + + dlgTexReset.cbScaleVert = gtk_check_button_new_with_label("Enabled"); + gtk_signal_connect (GTK_OBJECT (dlgTexReset.cbScaleVert), "toggled", GTK_SIGNAL_FUNC (dialog_button_callback_texreset_update), NULL); + gtk_widget_show (dlgTexReset.cbScaleVert); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbScaleVert, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + w = gtk_label_new ("New Vertical Scale: "); + gtk_table_attach (GTK_TABLE (table), w, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + dlgTexReset.editScaleVert = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editScaleVert), "0.5"); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.editScaleVert, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (dlgTexReset.editScaleVert); + + // ---- /frame ---- + + frame = gtk_frame_new ("Reset Shift"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (2, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + dlgTexReset.cbShiftHor = gtk_check_button_new_with_label("Enabled"); + gtk_signal_connect (GTK_OBJECT (dlgTexReset.cbShiftHor), "toggled", GTK_SIGNAL_FUNC (dialog_button_callback_texreset_update), NULL); + gtk_widget_show (dlgTexReset.cbShiftHor); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbShiftHor, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + w = gtk_label_new ("New Horizontal Shift: "); + gtk_table_attach (GTK_TABLE (table), w, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + dlgTexReset.editShiftHor = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editShiftHor), "0"); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.editShiftHor, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (dlgTexReset.editShiftHor); + + + dlgTexReset.cbShiftVert = gtk_check_button_new_with_label("Enabled"); + gtk_signal_connect (GTK_OBJECT (dlgTexReset.cbShiftVert), "toggled", GTK_SIGNAL_FUNC (dialog_button_callback_texreset_update), NULL); + gtk_widget_show (dlgTexReset.cbShiftVert); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbShiftVert, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + w = gtk_label_new ("New Vertical Shift: "); + gtk_table_attach (GTK_TABLE (table), w, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + dlgTexReset.editShiftVert = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editShiftVert), "0"); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.editShiftVert, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (dlgTexReset.editShiftVert); + + // ---- /frame ---- + + frame = gtk_frame_new ("Reset Rotation"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (1, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + dlgTexReset.cbRotation = gtk_check_button_new_with_label("Enabled"); + gtk_widget_show (dlgTexReset.cbRotation); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbRotation, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + w = gtk_label_new ("New Rotation Value: "); + gtk_table_attach (GTK_TABLE (table), w, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + dlgTexReset.editRotation = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editRotation), "0"); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.editRotation, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (dlgTexReset.editRotation); + + // ---- /frame ---- + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + w = gtk_button_new_with_label ("Use Selected Brushes"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Use All Brushes"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // ---- /hbox ---- + + // ---- /vbox ---- + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + Update_TextureReseter(); + + bool dialogError = TRUE; + while (dialogError) + { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if(ret != IDCANCEL) + { + rs->bResetRotation = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbRotation )); + if(rs->bResetRotation) + if(!ValidateTextInt(gtk_entry_get_text(GTK_ENTRY(dlgTexReset.editRotation)), "Rotation", &rs->rotation)) + dialogError = TRUE; + + rs->bResetScale[0] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbScaleHor )); + if(rs->bResetScale[0]) + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(dlgTexReset.editScaleHor)), "Horizontal Scale", &rs->fScale[0])) + dialogError = TRUE; + + rs->bResetScale[1] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbScaleVert )); + if(rs->bResetScale[1]) + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(dlgTexReset.editScaleVert)), "Vertical Scale", &rs->fScale[1])) + dialogError = TRUE; + + rs->bResetShift[0] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbShiftHor )); + if(rs->bResetShift[0]) + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(dlgTexReset.editShiftHor)), "Horizontal Shift", &rs->fShift[0])) + dialogError = TRUE; + + rs->bResetShift[1] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbShiftVert )); + if(rs->bResetShift[1]) + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(dlgTexReset.editShiftVert)), "Vertical Shift", &rs->fShift[1])) + dialogError = TRUE; + + rs->bResetTextureName = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbTexChange )); + if(rs->bResetTextureName) + { + strcpy(rs->textureName, gtk_entry_get_text(GTK_ENTRY( dlgTexReset.editTexOld ))); + strcpy(rs->newTextureName, gtk_entry_get_text(GTK_ENTRY( dlgTexReset.editTexNew ))); + } + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} + +int DoTrainThingBox (TrainThingRS* rs) +{ + Str texSelected; + + GtkWidget *window, *w, *vbox, *hbox, *frame, *table; + + GtkWidget *radiusX, *radiusY; + GtkWidget *angleStart, *angleEnd; + GtkWidget *heightStart, *heightEnd; + GtkWidget *numPoints; + + int ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title (GTK_WINDOW (window), "Train Thing"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + gtk_object_set_data (GTK_OBJECT (window), "loop", &loop); + gtk_object_set_data (GTK_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + // ---- vbox ---- + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- /hbox ---- + + frame = gtk_frame_new ("Radii"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (2, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + w = gtk_label_new ("X: "); + gtk_table_attach (GTK_TABLE (table), w, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + radiusX = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(radiusX), "100"); + gtk_table_attach (GTK_TABLE (table), radiusX, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (radiusX); + + + + w = gtk_label_new ("Y: "); + gtk_table_attach (GTK_TABLE (table), w, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + radiusY = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(radiusY), "100"); + gtk_table_attach (GTK_TABLE (table), radiusY, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (radiusY); + + + + frame = gtk_frame_new ("Angles"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (2, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + w = gtk_label_new ("Start: "); + gtk_table_attach (GTK_TABLE (table), w, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + angleStart = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(angleStart), "0"); + gtk_table_attach (GTK_TABLE (table), angleStart, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (angleStart); + + + + w = gtk_label_new ("End: "); + gtk_table_attach (GTK_TABLE (table), w, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + angleEnd = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(angleEnd), "90"); + gtk_table_attach (GTK_TABLE (table), angleEnd, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (angleEnd); + + + frame = gtk_frame_new ("Height"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (2, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + w = gtk_label_new ("Start: "); + gtk_table_attach (GTK_TABLE (table), w, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + heightStart = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(heightStart), "0"); + gtk_table_attach (GTK_TABLE (table), heightStart, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (heightStart); + + + + w = gtk_label_new ("End: "); + gtk_table_attach (GTK_TABLE (table), w, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + heightEnd = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(heightEnd), "0"); + gtk_table_attach (GTK_TABLE (table), heightEnd, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (heightEnd); + + + + frame = gtk_frame_new ("Points"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (2, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + w = gtk_label_new ("Number: "); + gtk_table_attach (GTK_TABLE (table), w, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + numPoints = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(numPoints), "0"); + gtk_table_attach (GTK_TABLE (table), numPoints, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (numPoints); + + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // ---- /hbox ---- + + + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) + { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if(ret != IDCANCEL) + { + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(radiusX)), "Radius (X)", &rs->fRadiusX)) + dialogError = TRUE; + + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(radiusY)), "Radius (Y)", &rs->fRadiusY)) + dialogError = TRUE; + + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(angleStart)), "Angle (Start)", &rs->fStartAngle)) + dialogError = TRUE; + + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(angleEnd)), "Angle (End)", &rs->fEndAngle)) + dialogError = TRUE; + + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(heightStart)), "Height (Start)", &rs->fStartHeight)) + dialogError = TRUE; + + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(heightEnd)), "Height (End)", &rs->fEndHeight)) + dialogError = TRUE; + + if(!ValidateTextInt(gtk_entry_get_text(GTK_ENTRY(numPoints)), "Num Points", &rs->iNumPoints)) + dialogError = TRUE; + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} diff --git a/contrib/bobtoolz/dialogs/pathplotterdialog.cpp b/contrib/bobtoolz/dialogs/pathplotterdialog.cpp index 2a77f984..ae638529 100644 --- a/contrib/bobtoolz/dialogs/pathplotterdialog.cpp +++ b/contrib/bobtoolz/dialogs/pathplotterdialog.cpp @@ -1,85 +1,85 @@ -/* -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 -*/ - -// PathPlotterDialog.cpp : implementation file -// - -#include "../StdAfx.h" -#include "../bobtoolz.h" -#include "PathPlotterDialog.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CPathPlotterDialog dialog - - -CPathPlotterDialog::CPathPlotterDialog(CWnd* pParent /*=NULL*/) - : CDialog(CPathPlotterDialog::IDD, pParent) -{ - //{{AFX_DATA_INIT(CPathPlotterDialog) - m_fGravity = -800.0f; - m_fMultiplier = 3.0f; - m_bNoUpdate = FALSE; - m_nPoints = 25; - m_bShowExtra = FALSE; - //}}AFX_DATA_INIT -} - - -void CPathPlotterDialog::DoDataExchange(CDataExchange* pDX) -{ - CDialog::DoDataExchange(pDX); - //{{AFX_DATA_MAP(CPathPlotterDialog) - DDX_Text(pDX, IDC_GRAVITY_EDIT, m_fGravity); - DDV_MinMaxFloat(pDX, m_fGravity, -10000.f, -1.f); - DDX_Text(pDX, IDC_MULTIPLIER_EDIT, m_fMultiplier); - DDV_MinMaxFloat(pDX, m_fMultiplier, 1.f, 10.f); - DDX_Check(pDX, IDC_NOUPDATE_CHECK, m_bNoUpdate); - DDX_Text(pDX, IDC_POINTCOUNT_EDIT, m_nPoints); - DDV_MinMaxInt(pDX, m_nPoints, 1, 1000); - DDX_Check(pDX, IDC_SHOWEXTRA_CHECK, m_bShowExtra); - //}}AFX_DATA_MAP -} - - -BEGIN_MESSAGE_MAP(CPathPlotterDialog, CDialog) - //{{AFX_MSG_MAP(CPathPlotterDialog) - ON_BN_CLICKED(IDYES, OnYes) - ON_BN_CLICKED(IDNO, OnNo) - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CPathPlotterDialog message handlers - -void CPathPlotterDialog::OnYes() -{ - if(UpdateData()) - EndModalLoop(IDYES); -} - -void CPathPlotterDialog::OnNo() -{ - EndModalLoop(IDNO); -} +/* +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 +*/ + +// PathPlotterDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "../bobtoolz.h" +#include "PathPlotterDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CPathPlotterDialog dialog + + +CPathPlotterDialog::CPathPlotterDialog(CWnd* pParent /*=NULL*/) + : CDialog(CPathPlotterDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CPathPlotterDialog) + m_fGravity = -800.0f; + m_fMultiplier = 3.0f; + m_bNoUpdate = FALSE; + m_nPoints = 25; + m_bShowExtra = FALSE; + //}}AFX_DATA_INIT +} + + +void CPathPlotterDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CPathPlotterDialog) + DDX_Text(pDX, IDC_GRAVITY_EDIT, m_fGravity); + DDV_MinMaxFloat(pDX, m_fGravity, -10000.f, -1.f); + DDX_Text(pDX, IDC_MULTIPLIER_EDIT, m_fMultiplier); + DDV_MinMaxFloat(pDX, m_fMultiplier, 1.f, 10.f); + DDX_Check(pDX, IDC_NOUPDATE_CHECK, m_bNoUpdate); + DDX_Text(pDX, IDC_POINTCOUNT_EDIT, m_nPoints); + DDV_MinMaxInt(pDX, m_nPoints, 1, 1000); + DDX_Check(pDX, IDC_SHOWEXTRA_CHECK, m_bShowExtra); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CPathPlotterDialog, CDialog) + //{{AFX_MSG_MAP(CPathPlotterDialog) + ON_BN_CLICKED(IDYES, OnYes) + ON_BN_CLICKED(IDNO, OnNo) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CPathPlotterDialog message handlers + +void CPathPlotterDialog::OnYes() +{ + if(UpdateData()) + EndModalLoop(IDYES); +} + +void CPathPlotterDialog::OnNo() +{ + EndModalLoop(IDNO); +} diff --git a/contrib/bobtoolz/funchandlers-GTK.cpp b/contrib/bobtoolz/funchandlers-GTK.cpp index 57d06b18..6f7ad443 100644 --- a/contrib/bobtoolz/funchandlers-GTK.cpp +++ b/contrib/bobtoolz/funchandlers-GTK.cpp @@ -1,800 +1,800 @@ -/* -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 -*/ - -#include "StdAfx.h" - -#ifdef _WIN32 -#pragma warning(disable : 4786) -#endif - -#include "dialogs/dialogs-gtk.h" - -#include "DEntity.h" -#include "DShape.h" -#include "DPatch.h" - -#include "misc.h" -#include "shapes.h" -#include "lists.h" -#include "funchandlers.h" -#include "visfind.h" - -// for autocaulk -list exclusionList; // whole brush exclusion -list exclusionList_Face; // single face exclusion - -bool el1Loaded = FALSE; -bool el2Loaded = FALSE; -bool clrLst1Loaded = FALSE; -bool clrLst2Loaded = FALSE; - -DBobView* g_PathView = NULL; -DVisDrawer* g_VisView = NULL; -DTrainDrawer* g_TrainView = NULL; -DTreePlanter* g_TreePlanter = NULL; -// ------------- - -//========================// -// Helper Functions // -//========================// - -void LoadLists() -{ - char buffer[256]; - - if(!el1Loaded) - el1Loaded = LoadExclusionList(GetFilename(buffer, "bt/bt-el1.txt"), &exclusionList); - if(!el2Loaded) - el2Loaded = LoadExclusionList(GetFilename(buffer, "bt/bt-el2.txt"), &exclusionList_Face); -} - - -//========================// -// Main Functions // -//========================// - -void DoIntersect() -{ - IntersectRS rs; - - if(DoIntersectBox(&rs) == IDCANCEL) - return; - - if(rs.nBrushOptions == BRUSH_OPT_SELECTED) - { - if( g_FuncTable.m_pfnSelectedBrushCount() < 2 ) - { - DoMessageBox("Invalid number of brushes selected, choose at least 2", "Error", MB_OK); - return; - } - } - - DEntity world; - - switch(rs.nBrushOptions) - { - case BRUSH_OPT_SELECTED: - { - world.LoadSelectedBrushes(); - break; - } - case BRUSH_OPT_WHOLE_MAP: - { - world.LoadFromEntity(0, FALSE); - break; - } - } - - world.RemoveNonCheckBrushes(&exclusionList, rs.bUseDetail); - - bool* pbSelectList; - if(rs.bDuplicateOnly) - pbSelectList = world.BuildDuplicateList(); - else - pbSelectList = world.BuildIntersectList(); - - world.SelectBrushes(pbSelectList); - - delete[] pbSelectList; -} - -void DoPolygonsTB() -{ - vec3_t vMin, vMax; - - // figure out vMin and vMax - g_FuncTable.m_pfnGetDispatchParams( vMin, vMax, NULL ); - - DoPolygons( vMin, vMax ); -} - -void DoPolygons(vec3_t vMin, vec3_t vMax) -{ - // ensure we have something selected - if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) - { - DoMessageBox("Invalid number of brushes selected, choose 1 only", "Error", MB_OK); - return; - } - - // tell Radiant we want to access the selected brushes - g_FuncTable.m_pfnAllocateSelectedBrushHandles(); - - // get handle to size definition brush - brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); - // cant release until we delete the brush, if we do... - - PolygonRS rs; - - // ask user for type, size, etc.... - if(DoPolygonBox(&rs) == IDOK) - { - g_FuncTable.m_pfnDeleteBrushHandle(brush); - - DShape poly; - - if(rs.bInverse) - poly.BuildInversePrism(vMin, vMax, rs.nSides, rs.bAlignTop); - else - { - if(rs.bUseBorder) - poly.BuildBorderedPrism(vMin, vMax, rs.nSides, rs.nBorderWidth, rs.bAlignTop); - else - poly.BuildRegularPrism(vMin, vMax, rs.nSides, rs.bAlignTop); - - } - - poly.Commit(); - } - - - g_FuncTable.m_pfnReleaseSelectedBrushHandles(); -} - -void DoFixBrushes() -{ - DMap world; - world.LoadAll(); - - int count = world.FixBrushes(TRUE); - - Sys_Printf("%i invalid/duplicate planes removed\n", count); -} - -void DoResetTextures() -{ - static ResetTextureRS rs; - - const char* texName; - if(g_SelectedFaceTable.m_pfnGetSelectedFaceCount() != 1) - { - texName = NULL; - } - else - { - texName = GetCurrentTexture(); - strcpy(rs.textureName, GetCurrentTexture()); - } - - int ret; - if((ret = DoResetTextureBox(&rs)) == IDCANCEL) - return; - - if(rs.bResetTextureName) - texName = rs.textureName; - - if(ret == IDOK) - { - DEntity world; - world.LoadSelectedBrushes(); - world.ResetTextures(texName, rs.fScale, rs.fShift, rs.rotation, rs.newTextureName, - rs.bResetTextureName, rs.bResetScale, rs.bResetShift, rs.bResetRotation, TRUE); - } - else - { - DMap world; - world.LoadAll(TRUE); - world.ResetTextures(texName, rs.fScale, rs.fShift, rs.rotation, rs.newTextureName, - rs.bResetTextureName, rs.bResetScale, rs.bResetShift, rs.bResetRotation); - } -} - -void DoBuildStairs(vec3_t vMin, vec3_t vMax) -{ - BuildStairsRS rs; - - strcpy(rs.mainTexture, GetCurrentTexture()); - - // ensure we have something selected - if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) - { - DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK); - return; - } - - // tell Radiant we want to access the selected brushes - g_FuncTable.m_pfnAllocateSelectedBrushHandles(); - - // get handle to size definition brush - brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); - // cant release until we delete the brush, if we do... - - - // ask user for type, size, etc.... - if(DoBuildStairsBox(&rs) == IDOK) - { - // calc brush size - vec3_t size; - VectorSubtract(vMax, vMin, size); - - if(((int)size[2] % rs.stairHeight) != 0) - { - // stairs must fit evenly into brush - DoMessageBox("Invalid stair height\nHeight of block must be divisable by stair height", "Error", MB_OK); - } - else - { - - // Remove Size Brush - g_FuncTable.m_pfnDeleteBrushHandle(brush); - - - // Get Step Count - int numSteps = (int)size[2] / rs.stairHeight; - - if(rs.style == STYLE_CORNER) - { - BuildCornerStairs(vMin, vMax, numSteps, rs.mainTexture, rs.riserTexture); - } - else - { - - // Get Step Dimensions - float stairHeight = (float)rs.stairHeight; - float stairWidth; - if((rs.direction == MOVE_EAST) || (rs.direction == MOVE_WEST)) - stairWidth = (size[0])/numSteps; - else - stairWidth = (size[1])/numSteps; - - - // Build Base For Stair (bob's style) - if(rs.style == STYLE_BOB) - Build_Wedge(rs.direction, vMin, vMax, TRUE); - - - // Set First Step Starting Position - vMax[2] = vMin[2] + stairHeight; - SetInitialStairPos(rs.direction, vMin, vMax, stairWidth); - - - // Build The Steps - for(int i = 0; i < numSteps; i++) - { - if(rs.style == STYLE_BOB) - Build_StairStep_Wedge(rs.direction, vMin, vMax, rs.mainTexture, rs.riserTexture, rs.bUseDetail); - else if(rs.style == STYLE_ORIGINAL) - Build_StairStep(vMin, vMax, rs.mainTexture, rs.riserTexture, rs.direction); - - // get step into next position - MoveBlock(rs.direction, vMin, vMax, stairWidth); - vMax[2] += stairHeight; - if(rs.style == STYLE_BOB) - vMin[2] += stairHeight; // wedge bottom must be raised - } - } - } - } - - g_FuncTable.m_pfnReleaseSelectedBrushHandles(); -} - -void DoBuildDoors(vec3_t vMin, vec3_t vMax) -{ - // ensure we have something selected - if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) - { - DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK); - return; - } - - // tell Radiant we want to access the selected brushes - g_FuncTable.m_pfnAllocateSelectedBrushHandles(); - - // get handle to size definition brush - brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); - // cant release until we delete the brush, if we do... - - DoorRS rs; - strcpy(rs.mainTexture, GetCurrentTexture()); - - if(DoDoorsBox(&rs) == IDOK) - { - g_FuncTable.m_pfnDeleteBrushHandle(brush); - - BuildDoorsX2(vMin, vMax, - rs.bScaleMainH, rs.bScaleMainV, - rs.bScaleTrimH, rs.bScaleTrimV, - rs.mainTexture, rs.trimTexture, - rs.nOrientation); // shapes.cpp - } - - g_FuncTable.m_pfnReleaseSelectedBrushHandles(); -} - -void DoPathPlotter() -{ - PathPlotterRS rs; - int ret = DoPathPlotterBox(&rs); - if(ret == IDCANCEL) - return; - if(ret == IDNO) - { - if(g_PathView) - delete g_PathView; - return; - } - - if( g_FuncTable.m_pfnSelectedBrushCount() != 1) - { - DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK); - return; - } - - // tell Radiant we want to access the selected brushes - g_FuncTable.m_pfnAllocateSelectedBrushHandles(); - - brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); - // should be our trigger brush - - DEntity world; - world.LoadEPairList(*g_EntityTable.m_pfnGetEntityKeyValList(brush->owner)); - - DEPair* trigger_ep = world.FindEPairByKey("targetname"); - - if(trigger_ep) - { - if(!strcmp(world.m_Classname, "trigger_push")) - { - DEPair* target_ep = world.FindEPairByKey("target"); - if(target_ep) - { - entity_s* entTarget = FindEntityFromTargetname(target_ep->value, NULL); - if(entTarget) - { - if(g_PathView) - delete g_PathView; - g_PathView = new DBobView; - - g_PathView->Begin(trigger_ep->value, target_ep->value, rs.fMultiplier, rs.nPoints, rs.fGravity, rs.bNoUpdate, rs.bShowExtra); - } - else - DoMessageBox("trigger_push target could not be found.", "Error", MB_OK); - } - else - DoMessageBox("trigger_push has no target.", "Error", MB_OK); - } - else - DoMessageBox("You must select a 'trigger_push' entity.", "Error", MB_OK); - } - else - DoMessageBox("Entity must have a targetname", "Error", MB_OK); - - g_FuncTable.m_pfnReleaseSelectedBrushHandles(); -} - -void DoPitBuilder(vec3_t vMin, vec3_t vMax) -{ - // ensure we have something selected - if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) - { - DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK); - return; - } - - // tell Radiant we want to access the selected brushes - g_FuncTable.m_pfnAllocateSelectedBrushHandles(); - - // get handle to size definition brush - brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); - // cant release until we delete the brush, if we do... - - DShape pit; - - if(pit.BuildPit(vMin, vMax)) - { - pit.Commit(); - - g_FuncTable.m_pfnDeleteBrushHandle(brush); - } - else - DoMessageBox("Failed To Make Pit\nTry Making The Brush Bigger", "Error", MB_OK); - - g_FuncTable.m_pfnReleaseSelectedBrushHandles(); -} - -void DoMergePatches() -{ - patch_merge_t merge_info; - DPatch mrgPatches[2]; - int i; - - // ensure we have something selected - if ( g_FuncTable.m_pfnSelectedBrushCount() != 2 ) - { - DoMessageBox("Invalid number of objects selected, chose 2 only", "Error", MB_OK); - return; - } - - - g_FuncTable.m_pfnAllocateSelectedBrushHandles(); - - for (i = 0; i < 2; i++) - { - brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i); - - if (!brush->pPatch) - { - g_FuncTable.m_pfnReleaseSelectedBrushHandles(); - DoMessageBox("You must select ONLY patches", "Error", MB_OK); - return; - } - - mrgPatches[i].LoadFromBrush_t(brush); - } - - /* mrgPatches[0].Transpose(); - mrgPatches[0].RemoveFromRadiant(); - mrgPatches[0].BuildInRadiant();*/ - - merge_info = mrgPatches[0].IsMergable(&mrgPatches[1]); - - if (merge_info.mergable) - { - Sys_Printf("%i %i", merge_info.pos1, merge_info.pos2); - - Sys_Printf("Patches Mergable\n"); - DPatch* newPatch = mrgPatches[0].MergePatches(merge_info, &mrgPatches[0], &mrgPatches[1]); - - /* mrgPatches[0].RemoveFromRadiant(); - mrgPatches[0].BuildInRadiant(); - - mrgPatches[1].RemoveFromRadiant(); - mrgPatches[1].BuildInRadiant(); - - - delete newPatch;*/ - - if (!newPatch) - { - } else - { - mrgPatches[0].RemoveFromRadiant(); - mrgPatches[1].RemoveFromRadiant(); - - newPatch->BuildInRadiant(); - delete newPatch; - } - } - - g_FuncTable.m_pfnReleaseSelectedBrushHandles(); -} - -void DoSplitPatch() { - DPatch patch; - - // ensure we have something selected - if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) { - DoMessageBox("Invalid number of objects selected, select 1 patch only", "Error", MB_OK); - return; - } - - g_FuncTable.m_pfnAllocateSelectedBrushHandles(); - - brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); - - if( !brush->pPatch ) { - g_FuncTable.m_pfnReleaseSelectedBrushHandles(); - DoMessageBox("You must select ONLY patches", "Error", MB_OK); - return; - } - - patch.LoadFromBrush_t(brush); - - list patchList = patch.Split( true, true ); - for(list::iterator patches = patchList.begin(); patches != patchList.end(); patches++) { - (*patches).BuildInRadiant(); - } - - patch.RemoveFromRadiant(); - - g_FuncTable.m_pfnReleaseSelectedBrushHandles(); -} - -void DoVisAnalyse() -{ - char filename[1024]; - - if( g_FuncTable.m_pfnSelectedBrushCount() == 0 ) - { - if(g_VisView) - { - delete g_VisView; - return; - } - } - - if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) - { - DoMessageBox("Invalid number of objects selected, select 1 only", "Error", MB_OK); - return; - } - - g_FuncTable.m_pfnAllocateSelectedBrushHandles(); - - brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); - - DBrush orgBrush; - orgBrush.LoadFromBrush_t(brush, false); - - g_FuncTable.m_pfnReleaseSelectedBrushHandles(); - - orgBrush.BuildBounds(); - vec3_t origin; - origin[0] = (orgBrush.bbox_max[0] + orgBrush.bbox_min[0])/2.f; - origin[1] = (orgBrush.bbox_max[1] + orgBrush.bbox_min[1])/2.f; - origin[2] = (orgBrush.bbox_max[2] + orgBrush.bbox_min[2])/2.f; - - - char* rad_filename = g_FuncTable.m_pfnGetMapName(); - if(!rad_filename) - { - DoMessageBox("An Error Occurred While Trying\n To Get The Map Filename", "Error", MB_OK); - return; - } - - strcpy(filename, rad_filename); - - char* ext = strrchr(filename, '.')+1; - strcpy(ext, "bsp");// rename the extension - - list *pointList = BuildTrace(filename, origin); - - if(!g_VisView) - { - g_VisView = new DVisDrawer; - g_VisView->Register(); - } - - g_VisView->SetList(pointList); -} - -void DoTrainPathPlot() { - if(g_TrainView) { - delete g_TrainView; - g_TrainView = NULL; - } - - g_TrainView = new DTrainDrawer(); -} - -void DoCaulkSelection( void ) { - DEntity world; - - float fScale[2] = { 0.5f, 0.5f }; - float fShift[2] = { 0.0f, 0.0f }; - - int bResetScale[2] = { false, false }; - int bResetShift[2] = { false, false }; - - world.LoadSelectedBrushes(); - world.LoadSelectedPatches(); - world.ResetTextures( NULL, fScale, fShift, 0, "textures/common/caulk", true, bResetScale, bResetShift, false, true ); -} - -void DoTreePlanter( void ) { - if(g_TreePlanter) { - delete g_TreePlanter; - g_TreePlanter = NULL; - return; - } - - g_TreePlanter = new DTreePlanter(); -} - -void DoDropEnts( void ) { - if(g_TreePlanter) { - g_TreePlanter->DropEntsToGround(); - } -} - -void DoMakeChain( void ) { - DTreePlanter pl; - pl.MakeChain(); -} - -typedef DPoint* pntTripple[3]; - -bool bFacesNoTop[6] = {true, true, true, true, true, false}; - -void DoFlipTerrain( void ) { - vec3_t vUp = { 0.f, 0.f, 1.f }; - int i; - - // ensure we have something selected - if( g_FuncTable.m_pfnSelectedBrushCount() != 2 ) { - DoMessageBox("Invalid number of objects selected, chose 2 only", "Error", MB_OK); - return; - } - - g_FuncTable.m_pfnAllocateSelectedBrushHandles(); - - brush_t* brushes[2]; - for( i = 0; i < 2; i++ ) { - brushes[i] = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i); - } - - DBrush Brushes[2]; - DPlane* Planes[2]; - pntTripple Points[2]; - for( i = 0; i < 2; i++ ) { - Brushes[i].LoadFromBrush_t( brushes[i], false ); - if(!(Planes[i] = Brushes[i].FindPlaneWithClosestNormal( vUp )) || Brushes[i].FindPointsForPlane( Planes[i], Points[i], 3 ) != 3) { - g_FuncTable.m_pfnReleaseSelectedBrushHandles(); - DoMessageBox("Error", "Error", MB_OK); - return; - } - } - - vec3_t mins1, mins2, maxs1, maxs2; - Brushes[0].GetBounds( mins1, maxs1 ); - Brushes[1].GetBounds( mins2, maxs2 ); - - entity_t* ents[2]; - for( i = 0; i < 2; i++ ) { - ents[i] = brushes[i]->owner; - Brushes[i].RemoveFromRadiant(); - } - - g_FuncTable.m_pfnReleaseSelectedBrushHandles(); - - - - - int dontmatch[2] = { -1, -1 }; - bool found = false; - for( i = 0; i < 3; i++ ) { - for( int j = 0; j < 3 && !found; j++ ) { - if(VectorCompare( (Points[0])[i]->_pnt, (Points[1])[j]->_pnt )) { - found = true; - break; - } - } - if(!found) { - dontmatch[0] = i; - break; - } - found = false; - } - if(dontmatch[0] == -1) { - DoMessageBox("Error", "Error", MB_OK); - return; - } - - for( i = 0; i < 3; i++ ) { - for( int j = 0; j < 3 && !found; j++ ) { - if(VectorCompare( (Points[1])[i]->_pnt, (Points[0])[j]->_pnt )) { - found = true; - break; - } - } - if(!found) { - dontmatch[1] = i; - break; - } - found = false; - } - if(dontmatch[1] == -1) { - DoMessageBox("Error", "Error", MB_OK); - return; - } - - vec3_t plnpnts1[3]; - vec3_t plnpnts2[3]; - vec3_t plnpntsshr[3]; - - VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpnts1[0] ); - for( i = 0; i < 3; i++ ) { - if( dontmatch[0] != i ) { - VectorCopy( (Points[0])[i]->_pnt, plnpnts1[1] ); - break; - } - } - VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpnts1[2] ); - - VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpnts2[0] ); - for( i = 0; i < 3; i++ ) { - if( dontmatch[1] != i && !VectorCompare( (Points[1])[i]->_pnt, plnpnts1[1] )) { - VectorCopy( (Points[1])[i]->_pnt, plnpnts2[1] ); - break; - } - } - VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpnts2[2] ); - - VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpntsshr[0] ); - VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpntsshr[1] ); - if( (Points[1])[dontmatch[1]]->_pnt[2] < (Points[0])[dontmatch[0]]->_pnt[2] ) { - VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpntsshr[2] ); - } else { - VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpntsshr[2] ); - } - plnpntsshr[2][2] -= 16; - - for( i = 0; i < 3; i++ ) { - if( mins2[i] < mins1[i] ) { - mins1[i] = mins2[i]; - } - if( maxs2[i] > maxs1[i] ) { - maxs1[i] = maxs2[i]; - } - } - - DBrush* newBrushes[2]; - newBrushes[0] = DShape::GetBoundingCube_Ext( mins1, maxs1, "textures/common/caulk", bFacesAll, true); - newBrushes[1] = DShape::GetBoundingCube_Ext( mins1, maxs1, "textures/common/caulk", bFacesAll, true); - - vec3_t normal; - MakeNormal( plnpnts1[0], plnpnts1[1], plnpnts1[2], normal ); - if( normal[2] >= 0 ) { - newBrushes[0]->AddFace( plnpnts1[0], plnpnts1[1], plnpnts1[2], "textures/common/terrain", true ); - } else { - newBrushes[0]->AddFace( plnpnts1[2], plnpnts1[1], plnpnts1[0], "textures/common/terrain", true ); - } - - MakeNormal( plnpnts2[0], plnpnts2[1], plnpnts2[2], normal ); - if( normal[2] >= 0 ) { - newBrushes[1]->AddFace( plnpnts2[0], plnpnts2[1], plnpnts2[2], "textures/common/terrain", true ); - } else { - newBrushes[1]->AddFace( plnpnts2[2], plnpnts2[1], plnpnts2[0], "textures/common/terrain", true ); - } - - vec3_t vec; - MakeNormal( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], normal ); - - VectorSubtract( plnpnts1[2], plnpnts1[1], vec ); - if( DotProduct( vec, normal ) >= 0 ) { - newBrushes[0]->AddFace( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], "textures/common/caulk", true ); - } else { - newBrushes[0]->AddFace( plnpntsshr[2], plnpntsshr[1], plnpntsshr[0], "textures/common/caulk", true ); - } - - VectorSubtract( plnpnts2[2], plnpnts2[1], vec ); - if( DotProduct( vec, normal ) >= 0 ) { - newBrushes[1]->AddFace( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], "textures/common/caulk", true ); - } else { - newBrushes[1]->AddFace( plnpntsshr[2], plnpntsshr[1], plnpntsshr[0], "textures/common/caulk", true ); - } - - for( i = 0; i < 2; i++ ) { - newBrushes[i]->RemoveRedundantPlanes(); - newBrushes[i]->BuildInRadiant( false, NULL, ents[i] ); - delete newBrushes[i]; - } - -} +/* +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 +*/ + +#include "StdAfx.h" + +#ifdef _WIN32 +#pragma warning(disable : 4786) +#endif + +#include "dialogs/dialogs-gtk.h" + +#include "DEntity.h" +#include "DShape.h" +#include "DPatch.h" + +#include "misc.h" +#include "shapes.h" +#include "lists.h" +#include "funchandlers.h" +#include "visfind.h" + +// for autocaulk +list exclusionList; // whole brush exclusion +list exclusionList_Face; // single face exclusion + +bool el1Loaded = FALSE; +bool el2Loaded = FALSE; +bool clrLst1Loaded = FALSE; +bool clrLst2Loaded = FALSE; + +DBobView* g_PathView = NULL; +DVisDrawer* g_VisView = NULL; +DTrainDrawer* g_TrainView = NULL; +DTreePlanter* g_TreePlanter = NULL; +// ------------- + +//========================// +// Helper Functions // +//========================// + +void LoadLists() +{ + char buffer[256]; + + if(!el1Loaded) + el1Loaded = LoadExclusionList(GetFilename(buffer, "bt/bt-el1.txt"), &exclusionList); + if(!el2Loaded) + el2Loaded = LoadExclusionList(GetFilename(buffer, "bt/bt-el2.txt"), &exclusionList_Face); +} + + +//========================// +// Main Functions // +//========================// + +void DoIntersect() +{ + IntersectRS rs; + + if(DoIntersectBox(&rs) == IDCANCEL) + return; + + if(rs.nBrushOptions == BRUSH_OPT_SELECTED) + { + if( g_FuncTable.m_pfnSelectedBrushCount() < 2 ) + { + DoMessageBox("Invalid number of brushes selected, choose at least 2", "Error", MB_OK); + return; + } + } + + DEntity world; + + switch(rs.nBrushOptions) + { + case BRUSH_OPT_SELECTED: + { + world.LoadSelectedBrushes(); + break; + } + case BRUSH_OPT_WHOLE_MAP: + { + world.LoadFromEntity(0, FALSE); + break; + } + } + + world.RemoveNonCheckBrushes(&exclusionList, rs.bUseDetail); + + bool* pbSelectList; + if(rs.bDuplicateOnly) + pbSelectList = world.BuildDuplicateList(); + else + pbSelectList = world.BuildIntersectList(); + + world.SelectBrushes(pbSelectList); + + delete[] pbSelectList; +} + +void DoPolygonsTB() +{ + vec3_t vMin, vMax; + + // figure out vMin and vMax + g_FuncTable.m_pfnGetDispatchParams( vMin, vMax, NULL ); + + DoPolygons( vMin, vMax ); +} + +void DoPolygons(vec3_t vMin, vec3_t vMax) +{ + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + DoMessageBox("Invalid number of brushes selected, choose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + PolygonRS rs; + + // ask user for type, size, etc.... + if(DoPolygonBox(&rs) == IDOK) + { + g_FuncTable.m_pfnDeleteBrushHandle(brush); + + DShape poly; + + if(rs.bInverse) + poly.BuildInversePrism(vMin, vMax, rs.nSides, rs.bAlignTop); + else + { + if(rs.bUseBorder) + poly.BuildBorderedPrism(vMin, vMax, rs.nSides, rs.nBorderWidth, rs.bAlignTop); + else + poly.BuildRegularPrism(vMin, vMax, rs.nSides, rs.bAlignTop); + + } + + poly.Commit(); + } + + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoFixBrushes() +{ + DMap world; + world.LoadAll(); + + int count = world.FixBrushes(TRUE); + + Sys_Printf("%i invalid/duplicate planes removed\n", count); +} + +void DoResetTextures() +{ + static ResetTextureRS rs; + + const char* texName; + if(g_SelectedFaceTable.m_pfnGetSelectedFaceCount() != 1) + { + texName = NULL; + } + else + { + texName = GetCurrentTexture(); + strcpy(rs.textureName, GetCurrentTexture()); + } + + int ret; + if((ret = DoResetTextureBox(&rs)) == IDCANCEL) + return; + + if(rs.bResetTextureName) + texName = rs.textureName; + + if(ret == IDOK) + { + DEntity world; + world.LoadSelectedBrushes(); + world.ResetTextures(texName, rs.fScale, rs.fShift, rs.rotation, rs.newTextureName, + rs.bResetTextureName, rs.bResetScale, rs.bResetShift, rs.bResetRotation, TRUE); + } + else + { + DMap world; + world.LoadAll(TRUE); + world.ResetTextures(texName, rs.fScale, rs.fShift, rs.rotation, rs.newTextureName, + rs.bResetTextureName, rs.bResetScale, rs.bResetShift, rs.bResetRotation); + } +} + +void DoBuildStairs(vec3_t vMin, vec3_t vMax) +{ + BuildStairsRS rs; + + strcpy(rs.mainTexture, GetCurrentTexture()); + + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + + // ask user for type, size, etc.... + if(DoBuildStairsBox(&rs) == IDOK) + { + // calc brush size + vec3_t size; + VectorSubtract(vMax, vMin, size); + + if(((int)size[2] % rs.stairHeight) != 0) + { + // stairs must fit evenly into brush + DoMessageBox("Invalid stair height\nHeight of block must be divisable by stair height", "Error", MB_OK); + } + else + { + + // Remove Size Brush + g_FuncTable.m_pfnDeleteBrushHandle(brush); + + + // Get Step Count + int numSteps = (int)size[2] / rs.stairHeight; + + if(rs.style == STYLE_CORNER) + { + BuildCornerStairs(vMin, vMax, numSteps, rs.mainTexture, rs.riserTexture); + } + else + { + + // Get Step Dimensions + float stairHeight = (float)rs.stairHeight; + float stairWidth; + if((rs.direction == MOVE_EAST) || (rs.direction == MOVE_WEST)) + stairWidth = (size[0])/numSteps; + else + stairWidth = (size[1])/numSteps; + + + // Build Base For Stair (bob's style) + if(rs.style == STYLE_BOB) + Build_Wedge(rs.direction, vMin, vMax, TRUE); + + + // Set First Step Starting Position + vMax[2] = vMin[2] + stairHeight; + SetInitialStairPos(rs.direction, vMin, vMax, stairWidth); + + + // Build The Steps + for(int i = 0; i < numSteps; i++) + { + if(rs.style == STYLE_BOB) + Build_StairStep_Wedge(rs.direction, vMin, vMax, rs.mainTexture, rs.riserTexture, rs.bUseDetail); + else if(rs.style == STYLE_ORIGINAL) + Build_StairStep(vMin, vMax, rs.mainTexture, rs.riserTexture, rs.direction); + + // get step into next position + MoveBlock(rs.direction, vMin, vMax, stairWidth); + vMax[2] += stairHeight; + if(rs.style == STYLE_BOB) + vMin[2] += stairHeight; // wedge bottom must be raised + } + } + } + } + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoBuildDoors(vec3_t vMin, vec3_t vMax) +{ + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + DoorRS rs; + strcpy(rs.mainTexture, GetCurrentTexture()); + + if(DoDoorsBox(&rs) == IDOK) + { + g_FuncTable.m_pfnDeleteBrushHandle(brush); + + BuildDoorsX2(vMin, vMax, + rs.bScaleMainH, rs.bScaleMainV, + rs.bScaleTrimH, rs.bScaleTrimV, + rs.mainTexture, rs.trimTexture, + rs.nOrientation); // shapes.cpp + } + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoPathPlotter() +{ + PathPlotterRS rs; + int ret = DoPathPlotterBox(&rs); + if(ret == IDCANCEL) + return; + if(ret == IDNO) + { + if(g_PathView) + delete g_PathView; + return; + } + + if( g_FuncTable.m_pfnSelectedBrushCount() != 1) + { + DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // should be our trigger brush + + DEntity world; + world.LoadEPairList(*g_EntityTable.m_pfnGetEntityKeyValList(brush->owner)); + + DEPair* trigger_ep = world.FindEPairByKey("targetname"); + + if(trigger_ep) + { + if(!strcmp(world.m_Classname, "trigger_push")) + { + DEPair* target_ep = world.FindEPairByKey("target"); + if(target_ep) + { + entity_s* entTarget = FindEntityFromTargetname(target_ep->value, NULL); + if(entTarget) + { + if(g_PathView) + delete g_PathView; + g_PathView = new DBobView; + + g_PathView->Begin(trigger_ep->value, target_ep->value, rs.fMultiplier, rs.nPoints, rs.fGravity, rs.bNoUpdate, rs.bShowExtra); + } + else + DoMessageBox("trigger_push target could not be found.", "Error", MB_OK); + } + else + DoMessageBox("trigger_push has no target.", "Error", MB_OK); + } + else + DoMessageBox("You must select a 'trigger_push' entity.", "Error", MB_OK); + } + else + DoMessageBox("Entity must have a targetname", "Error", MB_OK); + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoPitBuilder(vec3_t vMin, vec3_t vMax) +{ + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + DShape pit; + + if(pit.BuildPit(vMin, vMax)) + { + pit.Commit(); + + g_FuncTable.m_pfnDeleteBrushHandle(brush); + } + else + DoMessageBox("Failed To Make Pit\nTry Making The Brush Bigger", "Error", MB_OK); + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoMergePatches() +{ + patch_merge_t merge_info; + DPatch mrgPatches[2]; + int i; + + // ensure we have something selected + if ( g_FuncTable.m_pfnSelectedBrushCount() != 2 ) + { + DoMessageBox("Invalid number of objects selected, chose 2 only", "Error", MB_OK); + return; + } + + + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + for (i = 0; i < 2; i++) + { + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i); + + if (!brush->pPatch) + { + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); + DoMessageBox("You must select ONLY patches", "Error", MB_OK); + return; + } + + mrgPatches[i].LoadFromBrush_t(brush); + } + + /* mrgPatches[0].Transpose(); + mrgPatches[0].RemoveFromRadiant(); + mrgPatches[0].BuildInRadiant();*/ + + merge_info = mrgPatches[0].IsMergable(&mrgPatches[1]); + + if (merge_info.mergable) + { + Sys_Printf("%i %i", merge_info.pos1, merge_info.pos2); + + Sys_Printf("Patches Mergable\n"); + DPatch* newPatch = mrgPatches[0].MergePatches(merge_info, &mrgPatches[0], &mrgPatches[1]); + + /* mrgPatches[0].RemoveFromRadiant(); + mrgPatches[0].BuildInRadiant(); + + mrgPatches[1].RemoveFromRadiant(); + mrgPatches[1].BuildInRadiant(); + + + delete newPatch;*/ + + if (!newPatch) + { + } else + { + mrgPatches[0].RemoveFromRadiant(); + mrgPatches[1].RemoveFromRadiant(); + + newPatch->BuildInRadiant(); + delete newPatch; + } + } + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoSplitPatch() { + DPatch patch; + + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) { + DoMessageBox("Invalid number of objects selected, select 1 patch only", "Error", MB_OK); + return; + } + + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + + if( !brush->pPatch ) { + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); + DoMessageBox("You must select ONLY patches", "Error", MB_OK); + return; + } + + patch.LoadFromBrush_t(brush); + + list patchList = patch.Split( true, true ); + for(list::iterator patches = patchList.begin(); patches != patchList.end(); patches++) { + (*patches).BuildInRadiant(); + } + + patch.RemoveFromRadiant(); + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoVisAnalyse() +{ + char filename[1024]; + + if( g_FuncTable.m_pfnSelectedBrushCount() == 0 ) + { + if(g_VisView) + { + delete g_VisView; + return; + } + } + + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + DoMessageBox("Invalid number of objects selected, select 1 only", "Error", MB_OK); + return; + } + + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + + DBrush orgBrush; + orgBrush.LoadFromBrush_t(brush, false); + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); + + orgBrush.BuildBounds(); + vec3_t origin; + origin[0] = (orgBrush.bbox_max[0] + orgBrush.bbox_min[0])/2.f; + origin[1] = (orgBrush.bbox_max[1] + orgBrush.bbox_min[1])/2.f; + origin[2] = (orgBrush.bbox_max[2] + orgBrush.bbox_min[2])/2.f; + + + char* rad_filename = g_FuncTable.m_pfnGetMapName(); + if(!rad_filename) + { + DoMessageBox("An Error Occurred While Trying\n To Get The Map Filename", "Error", MB_OK); + return; + } + + strcpy(filename, rad_filename); + + char* ext = strrchr(filename, '.')+1; + strcpy(ext, "bsp");// rename the extension + + list *pointList = BuildTrace(filename, origin); + + if(!g_VisView) + { + g_VisView = new DVisDrawer; + g_VisView->Register(); + } + + g_VisView->SetList(pointList); +} + +void DoTrainPathPlot() { + if(g_TrainView) { + delete g_TrainView; + g_TrainView = NULL; + } + + g_TrainView = new DTrainDrawer(); +} + +void DoCaulkSelection( void ) { + DEntity world; + + float fScale[2] = { 0.5f, 0.5f }; + float fShift[2] = { 0.0f, 0.0f }; + + int bResetScale[2] = { false, false }; + int bResetShift[2] = { false, false }; + + world.LoadSelectedBrushes(); + world.LoadSelectedPatches(); + world.ResetTextures( NULL, fScale, fShift, 0, "textures/common/caulk", true, bResetScale, bResetShift, false, true ); +} + +void DoTreePlanter( void ) { + if(g_TreePlanter) { + delete g_TreePlanter; + g_TreePlanter = NULL; + return; + } + + g_TreePlanter = new DTreePlanter(); +} + +void DoDropEnts( void ) { + if(g_TreePlanter) { + g_TreePlanter->DropEntsToGround(); + } +} + +void DoMakeChain( void ) { + DTreePlanter pl; + pl.MakeChain(); +} + +typedef DPoint* pntTripple[3]; + +bool bFacesNoTop[6] = {true, true, true, true, true, false}; + +void DoFlipTerrain( void ) { + vec3_t vUp = { 0.f, 0.f, 1.f }; + int i; + + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 2 ) { + DoMessageBox("Invalid number of objects selected, chose 2 only", "Error", MB_OK); + return; + } + + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + brush_t* brushes[2]; + for( i = 0; i < 2; i++ ) { + brushes[i] = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i); + } + + DBrush Brushes[2]; + DPlane* Planes[2]; + pntTripple Points[2]; + for( i = 0; i < 2; i++ ) { + Brushes[i].LoadFromBrush_t( brushes[i], false ); + if(!(Planes[i] = Brushes[i].FindPlaneWithClosestNormal( vUp )) || Brushes[i].FindPointsForPlane( Planes[i], Points[i], 3 ) != 3) { + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); + DoMessageBox("Error", "Error", MB_OK); + return; + } + } + + vec3_t mins1, mins2, maxs1, maxs2; + Brushes[0].GetBounds( mins1, maxs1 ); + Brushes[1].GetBounds( mins2, maxs2 ); + + entity_t* ents[2]; + for( i = 0; i < 2; i++ ) { + ents[i] = brushes[i]->owner; + Brushes[i].RemoveFromRadiant(); + } + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); + + + + + int dontmatch[2] = { -1, -1 }; + bool found = false; + for( i = 0; i < 3; i++ ) { + for( int j = 0; j < 3 && !found; j++ ) { + if(VectorCompare( (Points[0])[i]->_pnt, (Points[1])[j]->_pnt )) { + found = true; + break; + } + } + if(!found) { + dontmatch[0] = i; + break; + } + found = false; + } + if(dontmatch[0] == -1) { + DoMessageBox("Error", "Error", MB_OK); + return; + } + + for( i = 0; i < 3; i++ ) { + for( int j = 0; j < 3 && !found; j++ ) { + if(VectorCompare( (Points[1])[i]->_pnt, (Points[0])[j]->_pnt )) { + found = true; + break; + } + } + if(!found) { + dontmatch[1] = i; + break; + } + found = false; + } + if(dontmatch[1] == -1) { + DoMessageBox("Error", "Error", MB_OK); + return; + } + + vec3_t plnpnts1[3]; + vec3_t plnpnts2[3]; + vec3_t plnpntsshr[3]; + + VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpnts1[0] ); + for( i = 0; i < 3; i++ ) { + if( dontmatch[0] != i ) { + VectorCopy( (Points[0])[i]->_pnt, plnpnts1[1] ); + break; + } + } + VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpnts1[2] ); + + VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpnts2[0] ); + for( i = 0; i < 3; i++ ) { + if( dontmatch[1] != i && !VectorCompare( (Points[1])[i]->_pnt, plnpnts1[1] )) { + VectorCopy( (Points[1])[i]->_pnt, plnpnts2[1] ); + break; + } + } + VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpnts2[2] ); + + VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpntsshr[0] ); + VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpntsshr[1] ); + if( (Points[1])[dontmatch[1]]->_pnt[2] < (Points[0])[dontmatch[0]]->_pnt[2] ) { + VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpntsshr[2] ); + } else { + VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpntsshr[2] ); + } + plnpntsshr[2][2] -= 16; + + for( i = 0; i < 3; i++ ) { + if( mins2[i] < mins1[i] ) { + mins1[i] = mins2[i]; + } + if( maxs2[i] > maxs1[i] ) { + maxs1[i] = maxs2[i]; + } + } + + DBrush* newBrushes[2]; + newBrushes[0] = DShape::GetBoundingCube_Ext( mins1, maxs1, "textures/common/caulk", bFacesAll, true); + newBrushes[1] = DShape::GetBoundingCube_Ext( mins1, maxs1, "textures/common/caulk", bFacesAll, true); + + vec3_t normal; + MakeNormal( plnpnts1[0], plnpnts1[1], plnpnts1[2], normal ); + if( normal[2] >= 0 ) { + newBrushes[0]->AddFace( plnpnts1[0], plnpnts1[1], plnpnts1[2], "textures/common/terrain", true ); + } else { + newBrushes[0]->AddFace( plnpnts1[2], plnpnts1[1], plnpnts1[0], "textures/common/terrain", true ); + } + + MakeNormal( plnpnts2[0], plnpnts2[1], plnpnts2[2], normal ); + if( normal[2] >= 0 ) { + newBrushes[1]->AddFace( plnpnts2[0], plnpnts2[1], plnpnts2[2], "textures/common/terrain", true ); + } else { + newBrushes[1]->AddFace( plnpnts2[2], plnpnts2[1], plnpnts2[0], "textures/common/terrain", true ); + } + + vec3_t vec; + MakeNormal( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], normal ); + + VectorSubtract( plnpnts1[2], plnpnts1[1], vec ); + if( DotProduct( vec, normal ) >= 0 ) { + newBrushes[0]->AddFace( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], "textures/common/caulk", true ); + } else { + newBrushes[0]->AddFace( plnpntsshr[2], plnpntsshr[1], plnpntsshr[0], "textures/common/caulk", true ); + } + + VectorSubtract( plnpnts2[2], plnpnts2[1], vec ); + if( DotProduct( vec, normal ) >= 0 ) { + newBrushes[1]->AddFace( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], "textures/common/caulk", true ); + } else { + newBrushes[1]->AddFace( plnpntsshr[2], plnpntsshr[1], plnpntsshr[0], "textures/common/caulk", true ); + } + + for( i = 0; i < 2; i++ ) { + newBrushes[i]->RemoveRedundantPlanes(); + newBrushes[i]->BuildInRadiant( false, NULL, ents[i] ); + delete newBrushes[i]; + } + +} diff --git a/contrib/bobtoolz/funchandlers-ctf-GTK.cpp b/contrib/bobtoolz/funchandlers-ctf-GTK.cpp index e13b6400..b01fc7cb 100644 --- a/contrib/bobtoolz/funchandlers-ctf-GTK.cpp +++ b/contrib/bobtoolz/funchandlers-ctf-GTK.cpp @@ -1,214 +1,214 @@ -/* -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 -*/ - -#include "StdAfx.h" - -#include "dialogs/dialogs-gtk.h" - -#include "DEntity.h" -#include "DMap.h" - -#include "misc.h" -#include "lists.h" -#include "funchandlers.h" - -// for ctf texture changer -list clrList_Blue; -list clrList_Red; - -BOOL clrLst1Loaded = FALSE; -BOOL clrLst2Loaded = FALSE; - -// ------------- - -//========================// -// Helper Functions // -//========================// - -void LoadLists() -{ - char buffer[256]; - - if(!clrLst1Loaded) - { - clrLst1Loaded = LoadExclusionList(GetFilename(buffer, "plugins/bt/ctf-blue.txt"), &clrList_Blue); - LoadExclusionList(GetFilename(buffer, "plugins/bt/blue.txt"), &clrList_Blue); - } - if(!clrLst2Loaded) - { - clrLst2Loaded = LoadExclusionList(GetFilename(buffer, "plugins/bt/ctf-red.txt"), &clrList_Red); - LoadExclusionList(GetFilename(buffer, "plugins/bt/red.txt"), &clrList_Red); - } -} - - -//========================// -// Main Functions // -//========================// - -void DoCTFColourChanger() -{ - if(!clrLst1Loaded || !clrLst2Loaded) - { - DoMessageBox("CTF texture lists not found, this function will terminate.", "Error", MB_OK); - return; - } - - int ret = DoCTFColourChangeBox(); - if(ret == IDCANCEL) - return; - - int cnt = Min(clrList_Blue.size(), clrList_Red.size()); - - list::const_iterator Texture_change; - list::const_iterator Texture_new; - - float fDummy[2]; - - int eCnt = g_FuncTable.m_pfnGetEntityCount(); - - DMap world; - world.LoadAll(TRUE); - - if(ret == IDYES) - { - Texture_change = clrList_Blue.begin(); - Texture_new = clrList_Red.begin(); - } - else - { - Texture_change = clrList_Red.begin(); - Texture_new = clrList_Blue.begin(); - } - - for(int i = 0; i < cnt; i++) - { - world.ResetTextures((*Texture_change).c_str(), fDummy, fDummy, 0, (*Texture_new).c_str(), TRUE); - - Texture_change++; - Texture_new++; - } -} - -void DoSwapLights() -{ -/* DMap world; - world.LoadAll(); - - for(list::const_iterator loopEnt = world.entityList.begin(); loopEnt != world.entityList.end(); loopEnt++) - { - DEntity* e = (*loopEnt); - DEPair* epLightColour = e->FindEPairByKey("_color"); - if(epLightColour) - { - float r, g, b; - sscanf(epLightColour->value, "%f %f %f", &r, &g, &b); - sprintf(epLightColour->value, "%f %f %f", b, g, r); - DMap::RebuildEntity(e); - } - }*/ - - int cnt = g_FuncTable.m_pfnGetEntityCount(); - - for(int i = 0; i < cnt; i++) - { - void* ent = g_FuncTable.m_pfnGetEntityHandle(i); - - for(epair_t* epList = *g_FuncTable.m_pfnGetEntityKeyValList(ent); epList; epList= epList->next) - { - if(!stricmp("_color", epList->key)) - { - float r, g, b; - sscanf(epList->value, "%f %f %f", &r, &g, &b); - sprintf(epList->value, "%f %f %f", b, g, r); - } - } - } -} - -void DoChangeAngles() -{ - int cnt = g_FuncTable.m_pfnGetEntityCount(); - - for(int i = 0; i < cnt; i++) - { - void* ent = g_FuncTable.m_pfnGetEntityHandle(i); - - for(epair_t* epList = *g_FuncTable.m_pfnGetEntityKeyValList(ent); epList; epList= epList->next) - { - if(!stricmp("angle", epList->key)) - { - float angle; - sscanf(epList->value, "%f", &angle); - angle += 180; - while(angle > 360) - angle -= 360; - - sprintf(epList->value, "%f", angle); - } - } - } -} - -void DoSwapSpawns() -{ - int cnt = g_FuncTable.m_pfnGetEntityCount(); - - for(int i = 0; i < cnt; i++) - { - void* ent = g_FuncTable.m_pfnGetEntityHandle(i); - - for(epair_t* epList = *g_FuncTable.m_pfnGetEntityKeyValList(ent); epList; epList= epList->next) - { - if(!stricmp("classname", epList->key)) - { - if(!strcmp(epList->value, "team_CTF_redplayer")) - sprintf(epList->value, "team_CTF_blueplayer"); - else if(!strcmp(epList->value, "team_CTF_blueplayer")) - sprintf(epList->value, "team_CTF_redplayer"); - - if(!strcmp(epList->value, "team_CTF_redspawn")) - sprintf(epList->value, "team_CTF_bluespawn"); - else if(!strcmp(epList->value, "team_CTF_bluespawn")) - sprintf(epList->value, "team_CTF_redspawn"); - - if(!strcmp(epList->value, "team_CTF_redflag")) - sprintf(epList->value, "team_CTF_blueflag"); - else if(!strcmp(epList->value, "team_CTF_blueflag")) - sprintf(epList->value, "team_CTF_redflag") - ; - if(!strcmp(epList->value, "team_redobelisk")) - sprintf(epList->value, "team_blueobelisk"); - else if(!strcmp(epList->value, "team_blueobelisk")) - sprintf(epList->value, "team_redobelisk"); - } - } - } -} - -/*void test() -{ - DMap world; - world.LoadAll(); - - for(list::const_iterator ents = world.entityList.begin(); ents != world.entityList.end(); ents++) - { - (*ents)->RemoveFromRadiant(); - } -}*/ +/* +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 +*/ + +#include "StdAfx.h" + +#include "dialogs/dialogs-gtk.h" + +#include "DEntity.h" +#include "DMap.h" + +#include "misc.h" +#include "lists.h" +#include "funchandlers.h" + +// for ctf texture changer +list clrList_Blue; +list clrList_Red; + +BOOL clrLst1Loaded = FALSE; +BOOL clrLst2Loaded = FALSE; + +// ------------- + +//========================// +// Helper Functions // +//========================// + +void LoadLists() +{ + char buffer[256]; + + if(!clrLst1Loaded) + { + clrLst1Loaded = LoadExclusionList(GetFilename(buffer, "plugins/bt/ctf-blue.txt"), &clrList_Blue); + LoadExclusionList(GetFilename(buffer, "plugins/bt/blue.txt"), &clrList_Blue); + } + if(!clrLst2Loaded) + { + clrLst2Loaded = LoadExclusionList(GetFilename(buffer, "plugins/bt/ctf-red.txt"), &clrList_Red); + LoadExclusionList(GetFilename(buffer, "plugins/bt/red.txt"), &clrList_Red); + } +} + + +//========================// +// Main Functions // +//========================// + +void DoCTFColourChanger() +{ + if(!clrLst1Loaded || !clrLst2Loaded) + { + DoMessageBox("CTF texture lists not found, this function will terminate.", "Error", MB_OK); + return; + } + + int ret = DoCTFColourChangeBox(); + if(ret == IDCANCEL) + return; + + int cnt = Min(clrList_Blue.size(), clrList_Red.size()); + + list::const_iterator Texture_change; + list::const_iterator Texture_new; + + float fDummy[2]; + + int eCnt = g_FuncTable.m_pfnGetEntityCount(); + + DMap world; + world.LoadAll(TRUE); + + if(ret == IDYES) + { + Texture_change = clrList_Blue.begin(); + Texture_new = clrList_Red.begin(); + } + else + { + Texture_change = clrList_Red.begin(); + Texture_new = clrList_Blue.begin(); + } + + for(int i = 0; i < cnt; i++) + { + world.ResetTextures((*Texture_change).c_str(), fDummy, fDummy, 0, (*Texture_new).c_str(), TRUE); + + Texture_change++; + Texture_new++; + } +} + +void DoSwapLights() +{ +/* DMap world; + world.LoadAll(); + + for(list::const_iterator loopEnt = world.entityList.begin(); loopEnt != world.entityList.end(); loopEnt++) + { + DEntity* e = (*loopEnt); + DEPair* epLightColour = e->FindEPairByKey("_color"); + if(epLightColour) + { + float r, g, b; + sscanf(epLightColour->value, "%f %f %f", &r, &g, &b); + sprintf(epLightColour->value, "%f %f %f", b, g, r); + DMap::RebuildEntity(e); + } + }*/ + + int cnt = g_FuncTable.m_pfnGetEntityCount(); + + for(int i = 0; i < cnt; i++) + { + void* ent = g_FuncTable.m_pfnGetEntityHandle(i); + + for(epair_t* epList = *g_FuncTable.m_pfnGetEntityKeyValList(ent); epList; epList= epList->next) + { + if(!stricmp("_color", epList->key)) + { + float r, g, b; + sscanf(epList->value, "%f %f %f", &r, &g, &b); + sprintf(epList->value, "%f %f %f", b, g, r); + } + } + } +} + +void DoChangeAngles() +{ + int cnt = g_FuncTable.m_pfnGetEntityCount(); + + for(int i = 0; i < cnt; i++) + { + void* ent = g_FuncTable.m_pfnGetEntityHandle(i); + + for(epair_t* epList = *g_FuncTable.m_pfnGetEntityKeyValList(ent); epList; epList= epList->next) + { + if(!stricmp("angle", epList->key)) + { + float angle; + sscanf(epList->value, "%f", &angle); + angle += 180; + while(angle > 360) + angle -= 360; + + sprintf(epList->value, "%f", angle); + } + } + } +} + +void DoSwapSpawns() +{ + int cnt = g_FuncTable.m_pfnGetEntityCount(); + + for(int i = 0; i < cnt; i++) + { + void* ent = g_FuncTable.m_pfnGetEntityHandle(i); + + for(epair_t* epList = *g_FuncTable.m_pfnGetEntityKeyValList(ent); epList; epList= epList->next) + { + if(!stricmp("classname", epList->key)) + { + if(!strcmp(epList->value, "team_CTF_redplayer")) + sprintf(epList->value, "team_CTF_blueplayer"); + else if(!strcmp(epList->value, "team_CTF_blueplayer")) + sprintf(epList->value, "team_CTF_redplayer"); + + if(!strcmp(epList->value, "team_CTF_redspawn")) + sprintf(epList->value, "team_CTF_bluespawn"); + else if(!strcmp(epList->value, "team_CTF_bluespawn")) + sprintf(epList->value, "team_CTF_redspawn"); + + if(!strcmp(epList->value, "team_CTF_redflag")) + sprintf(epList->value, "team_CTF_blueflag"); + else if(!strcmp(epList->value, "team_CTF_blueflag")) + sprintf(epList->value, "team_CTF_redflag") + ; + if(!strcmp(epList->value, "team_redobelisk")) + sprintf(epList->value, "team_blueobelisk"); + else if(!strcmp(epList->value, "team_blueobelisk")) + sprintf(epList->value, "team_redobelisk"); + } + } + } +} + +/*void test() +{ + DMap world; + world.LoadAll(); + + for(list::const_iterator ents = world.entityList.begin(); ents != world.entityList.end(); ents++) + { + (*ents)->RemoveFromRadiant(); + } +}*/ diff --git a/contrib/bobtoolz/funchandlers.cpp b/contrib/bobtoolz/funchandlers.cpp index 3dcd819a..c83d2ae0 100644 --- a/contrib/bobtoolz/funchandlers.cpp +++ b/contrib/bobtoolz/funchandlers.cpp @@ -1,503 +1,503 @@ -/* -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 -*/ - -#include "StdAfx.h" - -#include "funchandlers.h" - -#include "IntersectDialog.h" -#include "PolygonDialog.h" -#include "StairDialog.h" -#include "DoorDialog.h" -#include "IntersectInfoDialog.h" -#include "BrushCheckDialog.h" -#include "AutoCaulkDialog.h" -#include "AutoCaulkStartDialog.h" -#include "TextureResetDialog.h" -#include "pathplotterdialog.h" - -#include "DEntity.h" -#include "shapes.h" -#include "lists.h" -#include "misc.h" -#include "DShape.h" - -// for autocaulk -list exclusionList; // whole brush exclusion -list exclusionList_Face; // single face exclusion - -BOOL el1Loaded; -BOOL el2Loaded; - -DBobView* g_PathView = NULL; -// ------------- - -/************************ - Global Variables -************************/ - -CPolygonDialog polygonDlg; -CIntersectDialog intrDlg; -CStairDialog stairDlg; -CDoorDialog doorDlg; -CAutoCaulkStartDialog autocaulkDlg; -CTextureResetDialog texRstDlg; -CPathPlotterDialog ppDlg; - -/************************ - --Main Functions-- -************************/ - -void LoadLists() -{ - char buffer[256]; - - if(!el1Loaded) - el1Loaded = LoadExclusionList(GetFilename(buffer, "bt\\bt-el1.txt"), &exclusionList); - if(!el2Loaded) - el2Loaded = LoadExclusionList(GetFilename(buffer, "bt\\bt-el2.txt"), &exclusionList); -} - -void PolygonBuilder(vec3_t vMin, vec3_t vMax) -{ - // ensure we have something selected - if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) - { - MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK); - return; - } - - // tell Radiant we want to access the selected brushes - g_FuncTable.m_pfnAllocateSelectedBrushHandles(); - - // get handle to size definition brush - brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); - // cant release until we delete the brush, if we do... - - // ask user for type, size, etc.... - if(polygonDlg.DoModal() == IDOK) - { - DShape poly; - - g_FuncTable.m_pfnDeleteBrushHandle(brush); - - if(polygonDlg.m_bInverse) - poly.BuildInversePrism(vMin, vMax, polygonDlg.m_nSideCount, polygonDlg.m_bAlignTop); - else - { - if(polygonDlg.m_bBorder) - poly.BuildBorderedPrism(vMin, vMax, polygonDlg.m_nSideCount, polygonDlg.m_nBorderSize, polygonDlg.m_bAlignTop); - else - poly.BuildRegularPrism(vMin, vMax, polygonDlg.m_nSideCount, polygonDlg.m_bAlignTop); - } - - poly.Commit(); - } - - - g_FuncTable.m_pfnReleaseSelectedBrushHandles(); -} - - -void IntersectionFinder() -{ - if(intrDlg.DoModal() == IDCANCEL) - return; - - if(intrDlg.m_nBrushOptions == BRUSH_OPT_SELECTED) - { - // ensure we have enough brushes selected - if( g_FuncTable.m_pfnSelectedBrushCount() < 2 ) - { - MessageBox(NULL, "Invalid number of brushes selected, choose at least 2", "Error", MB_OK); - return; - } - } - - CIntersectInfoDialog* intrInfoDlg = new CIntersectInfoDialog(); - intrInfoDlg->Create(IDD_INTERSECT_INFO_DIALOG); - - DEntity world; - - switch(intrDlg.m_nBrushOptions) - { - case BRUSH_OPT_SELECTED: - { - world.LoadSelectedBrushes(&intrInfoDlg->m_prog1); - break; - } - case BRUSH_OPT_WHOLE_MAP: - { - world.LoadFromEntity(0, &intrInfoDlg->m_prog1); - break; - } - } - - world.RemoveNonCheckBrushes(&exclusionList, intrDlg.m_bUseDetail); - BOOL* pbSelectList; - if(intrDlg.m_bDuplicateOnly) - pbSelectList = world.BuildDuplicateList(); - else - pbSelectList = world.BuildIntersectList(); - - world.SelectBrushes(pbSelectList); - - intrInfoDlg->DestroyWindow(); - delete[] pbSelectList; -} - -void StairBuilder(vec3_t vMin, vec3_t vMax) -{ - // ensure we have something selected - if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) - { - MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK); - return; - } - - // tell Radiant we want to access the selected brushes - g_FuncTable.m_pfnAllocateSelectedBrushHandles(); - - // get handle to size definition brush - brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); - // cant release until we delete the brush, if we do... - - - // ask user for type, size, etc.... - if(stairDlg.DoModal() == IDOK) - { - - // calc brush size - vec3_t size; - _VectorSubtract(vMax, vMin, size); - - - if(((int)size[2] % stairDlg.m_nStairHeight) != 0) - { - // stairs must fit evenly into brush - MessageBox(NULL, "Invalid stair height\nHeight of block must be divisable by stair height", "Error", MB_OK); - } - else - { - - // Remove Size Brush - g_FuncTable.m_pfnDeleteBrushHandle(brush); - - - // Get Step Count, Direction of Stairs, Stair Style - int numSteps = (int)size[2] / stairDlg.m_nStairHeight; - int direction = stairDlg.m_StairDir; - int style = stairDlg.m_StairStyle; - - if(stairDlg.m_StairStyle == STYLE_CORNER) - { - BuildCornerStairs(vMin, vMax, numSteps, "textures/common/caulk", (LPCTSTR)stairDlg.m_riserTexture); - } - else - { - // Get Step Dimensions - float stairHeight = (float)stairDlg.m_nStairHeight; - float stairWidth; - if((direction == MOVE_EAST) || (direction == MOVE_WEST)) - stairWidth = (size[0])/numSteps; - else - stairWidth = (size[1])/numSteps; - - - // Build Base For Stair (bob's style) - if(style == STYLE_BOB) - Build_Wedge(direction, vMin, vMax, TRUE); - - - // Set First Step Starting Position - vMax[2] = vMin[2] + stairHeight; - SetInitialStairPos(direction, vMin, vMax, stairWidth); - - - // Build The Steps - for(int i = 0; i < numSteps; i++) - { - if(style == STYLE_BOB) - Build_StairStep_Wedge(direction, vMin, vMax, "textures/common/caulk", (LPCTSTR)stairDlg.m_riserTexture, stairDlg.m_bDetail); - else if(style == STYLE_ORIGINAL) - Build_StairStep(vMin, vMax, "textures/common/caulk", (LPCTSTR)stairDlg.m_riserTexture, direction); - - // get step into next position - MoveBlock(direction, vMin, vMax, stairWidth); - vMax[2] += stairHeight; - if(style == STYLE_BOB) - vMin[2] += stairHeight; // wedge bottom must be raised - } - } - } - } - - g_FuncTable.m_pfnReleaseSelectedBrushHandles(); -} - -void DoorBuilder(vec3_t vMin, vec3_t vMax) -{ - // ensure we have something selected - if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) - { - MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK); - return; - } - - // tell Radiant we want to access the selected brushes - g_FuncTable.m_pfnAllocateSelectedBrushHandles(); - - // get handle to size definition brush - brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); - // cant release until we delete the brush, if we do... - - - - strcpy(doorDlg.m_fbTextureName.GetBuffer(256), g_FuncTable.m_pfnGetCurrentTexture()); - - if(doorDlg.DoModal() == IDOK) - { - g_FuncTable.m_pfnDeleteBrushHandle(brush); - - BuildDoorsX2(vMin, vMax, - doorDlg.m_bSclMainHor, doorDlg.m_bSclMainVert, - doorDlg.m_bSclTrimHor, doorDlg.m_bSclTrimVert, - (LPCTSTR)doorDlg.m_fbTextureName, - (LPCTSTR)doorDlg.m_trimTextureName, - doorDlg.m_doorDirection); - } - - g_FuncTable.m_pfnReleaseSelectedBrushHandles(); -} - -void FixBrushes() -{ - DEntity world; - - CIntersectInfoDialog* intrInfoDlg = new CIntersectInfoDialog(); - intrInfoDlg->Create(IDD_INTERSECT_INFO_DIALOG); - - world.LoadFromEntity(0, &intrInfoDlg->m_prog1); - - intrInfoDlg->DestroyWindow(); - - CBrushCheckDialog* chkDlg = new CBrushCheckDialog(); - chkDlg->Create(IDD_BRUSHCHECKER_DIALOG); - - int count = world.FixBrushes(TRUE, &chkDlg->m_prog1); - - chkDlg->DestroyWindow(); - - Sys_Printf("%i invalid/duplicate planes removed\n", count); -} - -void AutoCaulk() -{ - if(!el1Loaded) - autocaulkDlg.m_Warning1 = "WARNING: Brush exclusion list not found\n, ALL BRUSHES WILL BE USED"; - - if(autocaulkDlg.DoModal() == IDCANCEL) - return; - - if(autocaulkDlg.m_nMode == MODE_AC_BUILD_MINI_PRT) - { - BuildMiniPrt(&exclusionList); - return; - } - - CAutoCaulkDialog* acDlg = new CAutoCaulkDialog; - acDlg->Create(IDD_AUTOCAULK_DIALOG); - - char filename[1204]; - - if(autocaulkDlg.m_nMode == MODE_AC_NORMAL) - { - char* rad_filename = g_BSPTable.m_pfnGetMapName(); - if(!rad_filename) - { - MessageBox(NULL, "An Error Occurred While Trying To Get The Map Filename", "Error", MB_OK); - acDlg->DestroyWindow(); - return; - } - - strcpy(filename, rad_filename); - - char* ext = strrchr(filename, '.')+1; - strcpy(ext, "prt");// rename the extension - } - else - { - IEpair* pEp = g_EpairTable.m_pfnIEpairForProjectKeys(); - char *pn = pEp->ValueForKey("mapspath"); - pEp->DecRef(); - - strcpy( filename, pn ); - strcat( filename, "/ac_prt.prt" ); - } - - DEntity portals; - if(!portals.LoadFromPrt(filename, &acDlg->m_prog1)) - { - MessageBox(NULL, "Failed To Load Portal File", "Error", MB_OK); - acDlg->DestroyWindow(); - return; - } - // load portal file - - CIntersectInfoDialog* intrInfoDlg = new CIntersectInfoDialog(); - intrInfoDlg->Create(IDD_INTERSECT_INFO_DIALOG); - - DEntity world; - - world.LoadFromEntity(0, &intrInfoDlg->m_prog1); - intrInfoDlg->DestroyWindow(); - - if(autocaulkDlg.m_nMode == MODE_AC_NORMAL) - world.RemoveNonCheckBrushes(&exclusionList, FALSE); - else - world.RemoveNonCheckBrushes(&exclusionList, TRUE); - - world.ResetChecks(&exclusionList_Face); - - int caulkedCount = 0; - int killCnt = world.AutoCaulk(&portals, autocaulkDlg.m_bAllowDestruction, &caulkedCount, &acDlg->m_prog2); - - if(autocaulkDlg.m_bAllowDestruction) - Sys_Printf("%i unrequired brush(es) killed\n", killCnt); - Sys_Printf("%i face(s) caulked\n", caulkedCount); - - acDlg->DestroyWindow(); -} - -void ResetTextures() -{ - texRstDlg.m_TextureName = GetCurrentTexture(); - texRstDlg.m_NewTextureName = GetCurrentTexture(); - - if(texRstDlg.DoModal() == IDCANCEL) - return; - - float fScale[2]; - float fShift[2]; - fScale[1] = texRstDlg.m_fScaleVertical; - fScale[0] = texRstDlg.m_fScaleHorizontal; - - fShift[1] = (float)texRstDlg.m_nShiftVertical; - fShift[0] = (float)texRstDlg.m_nShiftHorizontal; - - DEntity world; - world.LoadFromEntity(0, NULL); - - if(texRstDlg.m_bAllTextures) - world.ResetTextures(NULL, fScale, fShift, texRstDlg.m_nRotation, texRstDlg.m_NewTextureName, texRstDlg.m_bOnlyTexture); - else - world.ResetTextures(texRstDlg.m_TextureName, fScale, fShift, texRstDlg.m_nRotation, texRstDlg.m_NewTextureName, texRstDlg.m_bOnlyTexture); -} - -void PathPlotter() -{ - int ret = ppDlg.DoModal(); - if(ret == IDCANCEL) - return; - if(ret == IDNO) - { - if(g_PathView) - delete g_PathView; - - return; - } - - if( g_FuncTable.m_pfnSelectedBrushCount() != 1) - { - MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK); - return; - } - - // tell Radiant we want to access the selected brushes - g_FuncTable.m_pfnAllocateSelectedBrushHandles(); - - // get handle to size definition brush - brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); - // cant release until we delete the brush, if we do... - - DEntity world; - world.LoadEPairList(*g_FuncTable.m_pfnGetEntityKeyValList(brush->owner)); - - DEPair* trigger_ep = world.FindEPairByKey("targetname"); - - if(trigger_ep) - { - if(!strcmp(world.m_Classname, "trigger_push")) - { - DEPair* target_ep = world.FindEPairByKey("target"); - if(target_ep) - { - entity_s* entTarget = FindEntityFromTargetname(target_ep->value); - if(entTarget) - { - if(g_PathView) - delete g_PathView; - g_PathView = new DBobView; - - g_PathView->Begin(trigger_ep->value, target_ep->value, ppDlg.m_fMultiplier, ppDlg.m_nPoints, ppDlg.m_fGravity, ppDlg.m_bNoUpdate, ppDlg.m_bShowExtra); - } - else - MessageBox(NULL, "trigger_push target could not be found.", "Error", MB_OK); - } - else - MessageBox(NULL, "trigger_push has no target.", "Error", MB_OK); - } - else - MessageBox(NULL, "You must select a 'trigger_push' entity.", "Error", MB_OK); - } - else - MessageBox(NULL, "Entity must have a targetname", "Error", MB_OK); - - g_FuncTable.m_pfnReleaseSelectedBrushHandles(); -} - -void PitBuilder(vec3_t vMin, vec3_t vMax) -{ - // ensure we have something selected - if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) - { - MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK); - return; - } - - // tell Radiant we want to access the selected brushes - g_FuncTable.m_pfnAllocateSelectedBrushHandles(); - - // get handle to size definition brush - brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); - // cant release until we delete the brush, if we do... - - DShape pit; - - if(pit.BuildPit(vMin, vMax)) - { - pit.Commit(); - - g_FuncTable.m_pfnDeleteBrushHandle(brush); - } - else - MessageBox(NULL, "Failed To Make Pit\nTry Making The Brush Bigger", "Error", MB_OK); - - g_FuncTable.m_pfnReleaseSelectedBrushHandles(); -} +/* +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 +*/ + +#include "StdAfx.h" + +#include "funchandlers.h" + +#include "IntersectDialog.h" +#include "PolygonDialog.h" +#include "StairDialog.h" +#include "DoorDialog.h" +#include "IntersectInfoDialog.h" +#include "BrushCheckDialog.h" +#include "AutoCaulkDialog.h" +#include "AutoCaulkStartDialog.h" +#include "TextureResetDialog.h" +#include "pathplotterdialog.h" + +#include "DEntity.h" +#include "shapes.h" +#include "lists.h" +#include "misc.h" +#include "DShape.h" + +// for autocaulk +list exclusionList; // whole brush exclusion +list exclusionList_Face; // single face exclusion + +BOOL el1Loaded; +BOOL el2Loaded; + +DBobView* g_PathView = NULL; +// ------------- + +/************************ + Global Variables +************************/ + +CPolygonDialog polygonDlg; +CIntersectDialog intrDlg; +CStairDialog stairDlg; +CDoorDialog doorDlg; +CAutoCaulkStartDialog autocaulkDlg; +CTextureResetDialog texRstDlg; +CPathPlotterDialog ppDlg; + +/************************ + --Main Functions-- +************************/ + +void LoadLists() +{ + char buffer[256]; + + if(!el1Loaded) + el1Loaded = LoadExclusionList(GetFilename(buffer, "bt\\bt-el1.txt"), &exclusionList); + if(!el2Loaded) + el2Loaded = LoadExclusionList(GetFilename(buffer, "bt\\bt-el2.txt"), &exclusionList); +} + +void PolygonBuilder(vec3_t vMin, vec3_t vMax) +{ + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + // ask user for type, size, etc.... + if(polygonDlg.DoModal() == IDOK) + { + DShape poly; + + g_FuncTable.m_pfnDeleteBrushHandle(brush); + + if(polygonDlg.m_bInverse) + poly.BuildInversePrism(vMin, vMax, polygonDlg.m_nSideCount, polygonDlg.m_bAlignTop); + else + { + if(polygonDlg.m_bBorder) + poly.BuildBorderedPrism(vMin, vMax, polygonDlg.m_nSideCount, polygonDlg.m_nBorderSize, polygonDlg.m_bAlignTop); + else + poly.BuildRegularPrism(vMin, vMax, polygonDlg.m_nSideCount, polygonDlg.m_bAlignTop); + } + + poly.Commit(); + } + + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + + +void IntersectionFinder() +{ + if(intrDlg.DoModal() == IDCANCEL) + return; + + if(intrDlg.m_nBrushOptions == BRUSH_OPT_SELECTED) + { + // ensure we have enough brushes selected + if( g_FuncTable.m_pfnSelectedBrushCount() < 2 ) + { + MessageBox(NULL, "Invalid number of brushes selected, choose at least 2", "Error", MB_OK); + return; + } + } + + CIntersectInfoDialog* intrInfoDlg = new CIntersectInfoDialog(); + intrInfoDlg->Create(IDD_INTERSECT_INFO_DIALOG); + + DEntity world; + + switch(intrDlg.m_nBrushOptions) + { + case BRUSH_OPT_SELECTED: + { + world.LoadSelectedBrushes(&intrInfoDlg->m_prog1); + break; + } + case BRUSH_OPT_WHOLE_MAP: + { + world.LoadFromEntity(0, &intrInfoDlg->m_prog1); + break; + } + } + + world.RemoveNonCheckBrushes(&exclusionList, intrDlg.m_bUseDetail); + BOOL* pbSelectList; + if(intrDlg.m_bDuplicateOnly) + pbSelectList = world.BuildDuplicateList(); + else + pbSelectList = world.BuildIntersectList(); + + world.SelectBrushes(pbSelectList); + + intrInfoDlg->DestroyWindow(); + delete[] pbSelectList; +} + +void StairBuilder(vec3_t vMin, vec3_t vMax) +{ + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + + // ask user for type, size, etc.... + if(stairDlg.DoModal() == IDOK) + { + + // calc brush size + vec3_t size; + _VectorSubtract(vMax, vMin, size); + + + if(((int)size[2] % stairDlg.m_nStairHeight) != 0) + { + // stairs must fit evenly into brush + MessageBox(NULL, "Invalid stair height\nHeight of block must be divisable by stair height", "Error", MB_OK); + } + else + { + + // Remove Size Brush + g_FuncTable.m_pfnDeleteBrushHandle(brush); + + + // Get Step Count, Direction of Stairs, Stair Style + int numSteps = (int)size[2] / stairDlg.m_nStairHeight; + int direction = stairDlg.m_StairDir; + int style = stairDlg.m_StairStyle; + + if(stairDlg.m_StairStyle == STYLE_CORNER) + { + BuildCornerStairs(vMin, vMax, numSteps, "textures/common/caulk", (LPCTSTR)stairDlg.m_riserTexture); + } + else + { + // Get Step Dimensions + float stairHeight = (float)stairDlg.m_nStairHeight; + float stairWidth; + if((direction == MOVE_EAST) || (direction == MOVE_WEST)) + stairWidth = (size[0])/numSteps; + else + stairWidth = (size[1])/numSteps; + + + // Build Base For Stair (bob's style) + if(style == STYLE_BOB) + Build_Wedge(direction, vMin, vMax, TRUE); + + + // Set First Step Starting Position + vMax[2] = vMin[2] + stairHeight; + SetInitialStairPos(direction, vMin, vMax, stairWidth); + + + // Build The Steps + for(int i = 0; i < numSteps; i++) + { + if(style == STYLE_BOB) + Build_StairStep_Wedge(direction, vMin, vMax, "textures/common/caulk", (LPCTSTR)stairDlg.m_riserTexture, stairDlg.m_bDetail); + else if(style == STYLE_ORIGINAL) + Build_StairStep(vMin, vMax, "textures/common/caulk", (LPCTSTR)stairDlg.m_riserTexture, direction); + + // get step into next position + MoveBlock(direction, vMin, vMax, stairWidth); + vMax[2] += stairHeight; + if(style == STYLE_BOB) + vMin[2] += stairHeight; // wedge bottom must be raised + } + } + } + } + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoorBuilder(vec3_t vMin, vec3_t vMax) +{ + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + + + strcpy(doorDlg.m_fbTextureName.GetBuffer(256), g_FuncTable.m_pfnGetCurrentTexture()); + + if(doorDlg.DoModal() == IDOK) + { + g_FuncTable.m_pfnDeleteBrushHandle(brush); + + BuildDoorsX2(vMin, vMax, + doorDlg.m_bSclMainHor, doorDlg.m_bSclMainVert, + doorDlg.m_bSclTrimHor, doorDlg.m_bSclTrimVert, + (LPCTSTR)doorDlg.m_fbTextureName, + (LPCTSTR)doorDlg.m_trimTextureName, + doorDlg.m_doorDirection); + } + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void FixBrushes() +{ + DEntity world; + + CIntersectInfoDialog* intrInfoDlg = new CIntersectInfoDialog(); + intrInfoDlg->Create(IDD_INTERSECT_INFO_DIALOG); + + world.LoadFromEntity(0, &intrInfoDlg->m_prog1); + + intrInfoDlg->DestroyWindow(); + + CBrushCheckDialog* chkDlg = new CBrushCheckDialog(); + chkDlg->Create(IDD_BRUSHCHECKER_DIALOG); + + int count = world.FixBrushes(TRUE, &chkDlg->m_prog1); + + chkDlg->DestroyWindow(); + + Sys_Printf("%i invalid/duplicate planes removed\n", count); +} + +void AutoCaulk() +{ + if(!el1Loaded) + autocaulkDlg.m_Warning1 = "WARNING: Brush exclusion list not found\n, ALL BRUSHES WILL BE USED"; + + if(autocaulkDlg.DoModal() == IDCANCEL) + return; + + if(autocaulkDlg.m_nMode == MODE_AC_BUILD_MINI_PRT) + { + BuildMiniPrt(&exclusionList); + return; + } + + CAutoCaulkDialog* acDlg = new CAutoCaulkDialog; + acDlg->Create(IDD_AUTOCAULK_DIALOG); + + char filename[1204]; + + if(autocaulkDlg.m_nMode == MODE_AC_NORMAL) + { + char* rad_filename = g_BSPTable.m_pfnGetMapName(); + if(!rad_filename) + { + MessageBox(NULL, "An Error Occurred While Trying To Get The Map Filename", "Error", MB_OK); + acDlg->DestroyWindow(); + return; + } + + strcpy(filename, rad_filename); + + char* ext = strrchr(filename, '.')+1; + strcpy(ext, "prt");// rename the extension + } + else + { + IEpair* pEp = g_EpairTable.m_pfnIEpairForProjectKeys(); + char *pn = pEp->ValueForKey("mapspath"); + pEp->DecRef(); + + strcpy( filename, pn ); + strcat( filename, "/ac_prt.prt" ); + } + + DEntity portals; + if(!portals.LoadFromPrt(filename, &acDlg->m_prog1)) + { + MessageBox(NULL, "Failed To Load Portal File", "Error", MB_OK); + acDlg->DestroyWindow(); + return; + } + // load portal file + + CIntersectInfoDialog* intrInfoDlg = new CIntersectInfoDialog(); + intrInfoDlg->Create(IDD_INTERSECT_INFO_DIALOG); + + DEntity world; + + world.LoadFromEntity(0, &intrInfoDlg->m_prog1); + intrInfoDlg->DestroyWindow(); + + if(autocaulkDlg.m_nMode == MODE_AC_NORMAL) + world.RemoveNonCheckBrushes(&exclusionList, FALSE); + else + world.RemoveNonCheckBrushes(&exclusionList, TRUE); + + world.ResetChecks(&exclusionList_Face); + + int caulkedCount = 0; + int killCnt = world.AutoCaulk(&portals, autocaulkDlg.m_bAllowDestruction, &caulkedCount, &acDlg->m_prog2); + + if(autocaulkDlg.m_bAllowDestruction) + Sys_Printf("%i unrequired brush(es) killed\n", killCnt); + Sys_Printf("%i face(s) caulked\n", caulkedCount); + + acDlg->DestroyWindow(); +} + +void ResetTextures() +{ + texRstDlg.m_TextureName = GetCurrentTexture(); + texRstDlg.m_NewTextureName = GetCurrentTexture(); + + if(texRstDlg.DoModal() == IDCANCEL) + return; + + float fScale[2]; + float fShift[2]; + fScale[1] = texRstDlg.m_fScaleVertical; + fScale[0] = texRstDlg.m_fScaleHorizontal; + + fShift[1] = (float)texRstDlg.m_nShiftVertical; + fShift[0] = (float)texRstDlg.m_nShiftHorizontal; + + DEntity world; + world.LoadFromEntity(0, NULL); + + if(texRstDlg.m_bAllTextures) + world.ResetTextures(NULL, fScale, fShift, texRstDlg.m_nRotation, texRstDlg.m_NewTextureName, texRstDlg.m_bOnlyTexture); + else + world.ResetTextures(texRstDlg.m_TextureName, fScale, fShift, texRstDlg.m_nRotation, texRstDlg.m_NewTextureName, texRstDlg.m_bOnlyTexture); +} + +void PathPlotter() +{ + int ret = ppDlg.DoModal(); + if(ret == IDCANCEL) + return; + if(ret == IDNO) + { + if(g_PathView) + delete g_PathView; + + return; + } + + if( g_FuncTable.m_pfnSelectedBrushCount() != 1) + { + MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + DEntity world; + world.LoadEPairList(*g_FuncTable.m_pfnGetEntityKeyValList(brush->owner)); + + DEPair* trigger_ep = world.FindEPairByKey("targetname"); + + if(trigger_ep) + { + if(!strcmp(world.m_Classname, "trigger_push")) + { + DEPair* target_ep = world.FindEPairByKey("target"); + if(target_ep) + { + entity_s* entTarget = FindEntityFromTargetname(target_ep->value); + if(entTarget) + { + if(g_PathView) + delete g_PathView; + g_PathView = new DBobView; + + g_PathView->Begin(trigger_ep->value, target_ep->value, ppDlg.m_fMultiplier, ppDlg.m_nPoints, ppDlg.m_fGravity, ppDlg.m_bNoUpdate, ppDlg.m_bShowExtra); + } + else + MessageBox(NULL, "trigger_push target could not be found.", "Error", MB_OK); + } + else + MessageBox(NULL, "trigger_push has no target.", "Error", MB_OK); + } + else + MessageBox(NULL, "You must select a 'trigger_push' entity.", "Error", MB_OK); + } + else + MessageBox(NULL, "Entity must have a targetname", "Error", MB_OK); + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void PitBuilder(vec3_t vMin, vec3_t vMax) +{ + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + DShape pit; + + if(pit.BuildPit(vMin, vMax)) + { + pit.Commit(); + + g_FuncTable.m_pfnDeleteBrushHandle(brush); + } + else + MessageBox(NULL, "Failed To Make Pit\nTry Making The Brush Bigger", "Error", MB_OK); + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} diff --git a/contrib/bobtoolz/lists.cpp b/contrib/bobtoolz/lists.cpp index b4a97815..51744680 100644 --- a/contrib/bobtoolz/lists.cpp +++ b/contrib/bobtoolz/lists.cpp @@ -1,85 +1,85 @@ -/* -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 -*/ - -#include "StdAfx.h" - -#ifdef _WIN32 -#pragma warning(disable : 4786) -#endif - -#include "lists.h" -#include "misc.h" - -bool LoadExclusionList(char* filename, list* exclusionList) -{ - FILE* eFile = fopen(filename, "r"); - if(eFile) - { - char buffer[256]; - int cnt = 0; - while(!feof(eFile)) - { - memset(buffer, 0, 256); - fscanf(eFile, "%s\n", buffer); - - if(strlen(buffer) > 0) - exclusionList->push_back(buffer); - else - cnt++; - } - - fclose(eFile); - - return TRUE; - } - - Sys_ERROR("Failed To Load Exclusion List: %s\n", filename); - return FALSE; -} - -bool LoadGList(char* filename, GList** loadlist) -{ - FILE* eFile = fopen(filename, "r"); - if(eFile) - { - char buffer[256]; - int cnt = 0; - while(!feof(eFile)) - { - memset(buffer, 0, 256); - fscanf(eFile, "%s\n", buffer); - - if(strlen(buffer) > 0) - { - char* buffer2 = new char[strlen(buffer) + 1]; - strcpy(buffer2, buffer); - *loadlist = g_list_append(*loadlist, buffer2); - } - else - cnt++; - } - - fclose(eFile); - - return TRUE; - } - - Sys_ERROR("Failed To Load GList: %s\n", filename); - return FALSE; -} +/* +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 +*/ + +#include "StdAfx.h" + +#ifdef _WIN32 +#pragma warning(disable : 4786) +#endif + +#include "lists.h" +#include "misc.h" + +bool LoadExclusionList(char* filename, list* exclusionList) +{ + FILE* eFile = fopen(filename, "r"); + if(eFile) + { + char buffer[256]; + int cnt = 0; + while(!feof(eFile)) + { + memset(buffer, 0, 256); + fscanf(eFile, "%s\n", buffer); + + if(strlen(buffer) > 0) + exclusionList->push_back(buffer); + else + cnt++; + } + + fclose(eFile); + + return TRUE; + } + + Sys_ERROR("Failed To Load Exclusion List: %s\n", filename); + return FALSE; +} + +bool LoadGList(char* filename, GList** loadlist) +{ + FILE* eFile = fopen(filename, "r"); + if(eFile) + { + char buffer[256]; + int cnt = 0; + while(!feof(eFile)) + { + memset(buffer, 0, 256); + fscanf(eFile, "%s\n", buffer); + + if(strlen(buffer) > 0) + { + char* buffer2 = new char[strlen(buffer) + 1]; + strcpy(buffer2, buffer); + *loadlist = g_list_append(*loadlist, buffer2); + } + else + cnt++; + } + + fclose(eFile); + + return TRUE; + } + + Sys_ERROR("Failed To Load GList: %s\n", filename); + return FALSE; +} diff --git a/contrib/bobtoolz/misc.cpp b/contrib/bobtoolz/misc.cpp index bebc2b24..a061e867 100644 --- a/contrib/bobtoolz/misc.cpp +++ b/contrib/bobtoolz/misc.cpp @@ -1,424 +1,424 @@ -/* -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 -*/ - -#include "StdAfx.h" - -#include "DEntity.h" -#include "funchandlers.h" - -#ifdef __linux__ -#include -#include -#endif - -/*========================== - Global Vars -==========================*/ - -//HANDLE bsp_process; -char g_CurrentTexture[256] = ""; - -//============================================================= -//============================================================= - -void ReadCurrentTexture() -{ - const char* textureName = g_FuncTable.m_pfnGetCurrentTexture(); - strcpy(g_CurrentTexture, textureName); -} - -const char* GetCurrentTexture() -{ - ReadCurrentTexture(); - return g_CurrentTexture; -} - -epair_t* GetNextChainItem(epair_t* lastItem, char* key, char* value) -{ - epair_t* nextEPair = g_FuncTable.m_pfnAllocateEpair(key, value); - - if(lastItem != NULL) - lastItem->next = nextEPair; - - return nextEPair; -} - -void MoveBlock(int dir, vec3_t min, vec3_t max, float dist) -{ - switch(dir) - { - case MOVE_EAST: - { - min[0]+=dist; - max[0]+=dist; - break; - } - case MOVE_WEST: - { - min[0]-=dist; - max[0]-=dist; - break; - } - case MOVE_NORTH: - { - min[1]+=dist; - max[1]+=dist; - break; - } - case MOVE_SOUTH: - { - min[1]-=dist; - max[1]-=dist; - break; - } - } -} - -void SetInitialStairPos(int dir, vec3_t min, vec3_t max, float width) -{ - switch(dir) - { - case MOVE_EAST: - { - max[0] = min[0] + width; - break; - } - case MOVE_WEST: - { - min[0] = max[0] - width; - break; - } - case MOVE_NORTH: - { - max[1] = min[1] + width; - break; - } - case MOVE_SOUTH: - { - min[1] = max[1] - width; - break; - } - } -} - -char* TranslateString (char *buf) -{ - static char buf2[32768]; - int i, l; - char *out; - - l = strlen(buf); - out = buf2; - for (i=0 ; i%s", buf); -} - -/*void Sys_Printf (char *text, ...) -{ - va_list argptr; - char buf[32768]; - - va_start (argptr,text); - vsprintf (buf, text,argptr); - va_end (argptr); - - g_FuncTable.m_pfnSysMsg ( buf ); -}*/ - -char* UnixToDosPath(char* path) -{ -#ifndef _WIN32 - return path; -#else - for(char* p = path; *p; p++) - { - if(*p == '/') - *p = '\\'; - } - return path; -#endif -} - -const char* ExtractFilename(const char* path) -{ - char* p = strrchr(path, '/'); - if(!p) - { - p = strrchr(path, '\\'); - - if(!p) - return path; - } - return ++p; -} - -extern char* PLUGIN_NAME; -/*char* GetGameFilename(char* buffer, const char* filename) -{ - strcpy(buffer, g_FuncTable.m_pfnGetGamePath()); - char* p = strrchr(buffer, '/'); - *++p = '\0'; - strcat(buffer, filename); - buffer = UnixToDosPath(buffer); - return buffer; -}*/ - -#if defined (__linux__) || defined (__APPLE__) -// the bCreateConsole parameter is ignored on linux .. -bool Q_Exec( const char *pCmd, bool bCreateConsole ) -{ - switch (fork()) - { - case -1: - return false; -// Error ("CreateProcess failed"); - break; - case 0: -#ifdef _DEBUG - printf("Running system...\n"); - printf("Command: %s\n", pCmd); -#endif - // NOTE: we could use that to detect when a step finishes. But then it - // would not work for remote compiling stuff. -// execlp (pCmd, pCmd, NULL); - system( pCmd ); - printf ("system() returned"); - _exit (0); - break; - } - return true; -} -#endif - -#ifdef _WIN32 -bool Q_Exec( const char *pCmd, bool bCreateConsole ) -{ - // G_DeWan: Don't know if this is needed for linux version - - PROCESS_INFORMATION pi; - STARTUPINFO si = {0}; // Initialize all members to zero - si.cb = sizeof(STARTUPINFO); // Set byte count - DWORD dwCreationFlags; - - if (bCreateConsole) - dwCreationFlags = CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS; - else - dwCreationFlags = DETACHED_PROCESS | NORMAL_PRIORITY_CLASS; - - for(; *pCmd == ' '; pCmd++); - - if(!CreateProcess(NULL, (char *)pCmd, NULL, NULL, FALSE, dwCreationFlags, NULL, NULL, &si, &pi)) - return false; - - return true; -} -#endif - -void StartBSP() -{ - char exename[256]; - GetFilename(exename, "q3map"); - UnixToDosPath(exename); // do we want this done in linux version? - - char mapname[256]; - const char *pn = g_FuncTable.m_pfnReadProjectKey("mapspath"); - - strcpy( mapname, pn ); - strcat( mapname, "/ac_prt.map" ); - UnixToDosPath(mapname); - - char command[1024]; - sprintf(command, "%s -nowater -fulldetail %s", exename, mapname); - - Q_Exec( command, TRUE ); -} - -void BuildMiniPrt(list* exclusionList) -{ - // yes, we could just use -fulldetail option, but, as SPOG said - // it'd be faster without all the hint, donotenter etc textures and - // doors, etc - - DEntity world; - - char buffer[128]; - const char *pn = g_FuncTable.m_pfnReadProjectKey("mapspath"); - - strcpy( buffer, pn ); - strcat( buffer, "/ac_prt.map" ); - FILE* pFile = fopen(buffer, "w"); - - // ahem, thx rr2 - if(!pFile) - return; - - int count = g_FuncTable.m_pfnGetEntityCount(); - for(int i = 0; i < count; i++) - { - entity_t* ent = (entity_t*)g_FuncTable.m_pfnGetEntityHandle(i); - - epair_t* epl = *g_EntityTable.m_pfnGetEntityKeyValList(ent); - - epair_t* ep = epl; - while(ep) - { - if(!strcmp(ep->key, "classname")) - { - if(!strcmp(ep->value, "worldspawn")) - { - world.LoadFromEntity(i, FALSE); - world.RemoveNonCheckBrushes(exclusionList, TRUE); - world.SaveToFile(pFile); - } - else if(strstr(ep->value, "info_")) - { - world.ClearBrushes(); - world.ClearEPairs(); - world.LoadEPairList(epl); - world.SaveToFile(pFile); - } - break; - } - - ep = ep->next; - } - } - - fclose(pFile); - - StartBSP(); -} - -entity_s* FindEntityFromTargetname(const char* targetname, int* entNum) -{ - DEntity world; - - int count = g_FuncTable.m_pfnGetEntityCount(); - for(int i = 0; i < count; i++) - { - world.ClearEPairs(); - - entity_s* ent = (entity_s*)g_FuncTable.m_pfnGetEntityHandle(i); - - world.LoadEPairList(*g_EntityTable.m_pfnGetEntityKeyValList(ent)); - - DEPair* tn = world.FindEPairByKey("targetname"); - if(tn) - { - if(!stricmp(tn->value, targetname)) { - if(entNum) { - *entNum = i; - } - return ent; - } - } - } - return NULL; -} - -void FillDefaultTexture(_QERFaceData* faceData, vec3_t va, vec3_t vb, vec3_t vc, const char* texture) -{ - faceData->m_bBPrimit = FALSE; - faceData->m_fRotate = 0; - faceData->m_fScale[0] = 0.5; - faceData->m_fScale[1] = 0.5; - faceData->m_fShift[0] = 0; - faceData->m_fShift[1] = 0; - faceData->m_nContents = 0; - faceData->m_nFlags = 0; - faceData->m_nValue = 0; - if(*texture) - strcpy(faceData->m_TextureName, texture); - else - strcpy(faceData->m_TextureName, "textures/common/caulk"); - VectorCopy(va, faceData->m_v1); - VectorCopy(vb, faceData->m_v2); - VectorCopy(vc, faceData->m_v3); -} - -float Determinant3x3(float a1, float a2, float a3, - float b1, float b2, float b3, - float c1, float c2, float c3) -{ - return a1*(b2*c3-b3*c2) - a2*(b1*c3-b3*c1) + a3*(b1*c2-b2*c1); -} - -bool GetEntityCentre(const char* entity, vec3_t centre) -{ - entity_s* ent = FindEntityFromTargetname(entity, NULL); - if(!ent) - return FALSE; - - int cnt = g_FuncTable.m_pfnAllocateEntityBrushHandles(ent); - if(cnt == 0) - { - g_FuncTable.m_pfnReleaseEntityBrushHandles(); - return FALSE; - } - - brush_t* brush = (brush_t*)g_FuncTable.m_pfnGetEntityBrushHandle(0); - DBrush cBrush; - cBrush.LoadFromBrush_t(brush, FALSE); - - vec3_t min, max; - cBrush.GetBounds(min, max); - - VectorAdd(min, max, centre); - VectorScale(centre, 0.5f, centre); - - g_FuncTable.m_pfnReleaseEntityBrushHandles(); - return TRUE; -} - -vec_t Min(vec_t a, vec_t b) -{ - if(a < b) - return a; - return b; -} - -void MakeNormal( vec_t* va, vec_t* vb, vec_t* vc, vec_t* out ) { - vec3_t v1, v2; - VectorSubtract(va, vb, v1); - VectorSubtract(vc, vb, v2); - CrossProduct(v1, v2, out); -} +/* +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 +*/ + +#include "StdAfx.h" + +#include "DEntity.h" +#include "funchandlers.h" + +#ifdef __linux__ +#include +#include +#endif + +/*========================== + Global Vars +==========================*/ + +//HANDLE bsp_process; +char g_CurrentTexture[256] = ""; + +//============================================================= +//============================================================= + +void ReadCurrentTexture() +{ + const char* textureName = g_FuncTable.m_pfnGetCurrentTexture(); + strcpy(g_CurrentTexture, textureName); +} + +const char* GetCurrentTexture() +{ + ReadCurrentTexture(); + return g_CurrentTexture; +} + +epair_t* GetNextChainItem(epair_t* lastItem, char* key, char* value) +{ + epair_t* nextEPair = g_FuncTable.m_pfnAllocateEpair(key, value); + + if(lastItem != NULL) + lastItem->next = nextEPair; + + return nextEPair; +} + +void MoveBlock(int dir, vec3_t min, vec3_t max, float dist) +{ + switch(dir) + { + case MOVE_EAST: + { + min[0]+=dist; + max[0]+=dist; + break; + } + case MOVE_WEST: + { + min[0]-=dist; + max[0]-=dist; + break; + } + case MOVE_NORTH: + { + min[1]+=dist; + max[1]+=dist; + break; + } + case MOVE_SOUTH: + { + min[1]-=dist; + max[1]-=dist; + break; + } + } +} + +void SetInitialStairPos(int dir, vec3_t min, vec3_t max, float width) +{ + switch(dir) + { + case MOVE_EAST: + { + max[0] = min[0] + width; + break; + } + case MOVE_WEST: + { + min[0] = max[0] - width; + break; + } + case MOVE_NORTH: + { + max[1] = min[1] + width; + break; + } + case MOVE_SOUTH: + { + min[1] = max[1] - width; + break; + } + } +} + +char* TranslateString (char *buf) +{ + static char buf2[32768]; + int i, l; + char *out; + + l = strlen(buf); + out = buf2; + for (i=0 ; i%s", buf); +} + +/*void Sys_Printf (char *text, ...) +{ + va_list argptr; + char buf[32768]; + + va_start (argptr,text); + vsprintf (buf, text,argptr); + va_end (argptr); + + g_FuncTable.m_pfnSysMsg ( buf ); +}*/ + +char* UnixToDosPath(char* path) +{ +#ifndef _WIN32 + return path; +#else + for(char* p = path; *p; p++) + { + if(*p == '/') + *p = '\\'; + } + return path; +#endif +} + +const char* ExtractFilename(const char* path) +{ + char* p = strrchr(path, '/'); + if(!p) + { + p = strrchr(path, '\\'); + + if(!p) + return path; + } + return ++p; +} + +extern char* PLUGIN_NAME; +/*char* GetGameFilename(char* buffer, const char* filename) +{ + strcpy(buffer, g_FuncTable.m_pfnGetGamePath()); + char* p = strrchr(buffer, '/'); + *++p = '\0'; + strcat(buffer, filename); + buffer = UnixToDosPath(buffer); + return buffer; +}*/ + +#if defined (__linux__) || defined (__APPLE__) +// the bCreateConsole parameter is ignored on linux .. +bool Q_Exec( const char *pCmd, bool bCreateConsole ) +{ + switch (fork()) + { + case -1: + return false; +// Error ("CreateProcess failed"); + break; + case 0: +#ifdef _DEBUG + printf("Running system...\n"); + printf("Command: %s\n", pCmd); +#endif + // NOTE: we could use that to detect when a step finishes. But then it + // would not work for remote compiling stuff. +// execlp (pCmd, pCmd, NULL); + system( pCmd ); + printf ("system() returned"); + _exit (0); + break; + } + return true; +} +#endif + +#ifdef _WIN32 +bool Q_Exec( const char *pCmd, bool bCreateConsole ) +{ + // G_DeWan: Don't know if this is needed for linux version + + PROCESS_INFORMATION pi; + STARTUPINFO si = {0}; // Initialize all members to zero + si.cb = sizeof(STARTUPINFO); // Set byte count + DWORD dwCreationFlags; + + if (bCreateConsole) + dwCreationFlags = CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS; + else + dwCreationFlags = DETACHED_PROCESS | NORMAL_PRIORITY_CLASS; + + for(; *pCmd == ' '; pCmd++); + + if(!CreateProcess(NULL, (char *)pCmd, NULL, NULL, FALSE, dwCreationFlags, NULL, NULL, &si, &pi)) + return false; + + return true; +} +#endif + +void StartBSP() +{ + char exename[256]; + GetFilename(exename, "q3map"); + UnixToDosPath(exename); // do we want this done in linux version? + + char mapname[256]; + const char *pn = g_FuncTable.m_pfnReadProjectKey("mapspath"); + + strcpy( mapname, pn ); + strcat( mapname, "/ac_prt.map" ); + UnixToDosPath(mapname); + + char command[1024]; + sprintf(command, "%s -nowater -fulldetail %s", exename, mapname); + + Q_Exec( command, TRUE ); +} + +void BuildMiniPrt(list* exclusionList) +{ + // yes, we could just use -fulldetail option, but, as SPOG said + // it'd be faster without all the hint, donotenter etc textures and + // doors, etc + + DEntity world; + + char buffer[128]; + const char *pn = g_FuncTable.m_pfnReadProjectKey("mapspath"); + + strcpy( buffer, pn ); + strcat( buffer, "/ac_prt.map" ); + FILE* pFile = fopen(buffer, "w"); + + // ahem, thx rr2 + if(!pFile) + return; + + int count = g_FuncTable.m_pfnGetEntityCount(); + for(int i = 0; i < count; i++) + { + entity_t* ent = (entity_t*)g_FuncTable.m_pfnGetEntityHandle(i); + + epair_t* epl = *g_EntityTable.m_pfnGetEntityKeyValList(ent); + + epair_t* ep = epl; + while(ep) + { + if(!strcmp(ep->key, "classname")) + { + if(!strcmp(ep->value, "worldspawn")) + { + world.LoadFromEntity(i, FALSE); + world.RemoveNonCheckBrushes(exclusionList, TRUE); + world.SaveToFile(pFile); + } + else if(strstr(ep->value, "info_")) + { + world.ClearBrushes(); + world.ClearEPairs(); + world.LoadEPairList(epl); + world.SaveToFile(pFile); + } + break; + } + + ep = ep->next; + } + } + + fclose(pFile); + + StartBSP(); +} + +entity_s* FindEntityFromTargetname(const char* targetname, int* entNum) +{ + DEntity world; + + int count = g_FuncTable.m_pfnGetEntityCount(); + for(int i = 0; i < count; i++) + { + world.ClearEPairs(); + + entity_s* ent = (entity_s*)g_FuncTable.m_pfnGetEntityHandle(i); + + world.LoadEPairList(*g_EntityTable.m_pfnGetEntityKeyValList(ent)); + + DEPair* tn = world.FindEPairByKey("targetname"); + if(tn) + { + if(!stricmp(tn->value, targetname)) { + if(entNum) { + *entNum = i; + } + return ent; + } + } + } + return NULL; +} + +void FillDefaultTexture(_QERFaceData* faceData, vec3_t va, vec3_t vb, vec3_t vc, const char* texture) +{ + faceData->m_bBPrimit = FALSE; + faceData->m_fRotate = 0; + faceData->m_fScale[0] = 0.5; + faceData->m_fScale[1] = 0.5; + faceData->m_fShift[0] = 0; + faceData->m_fShift[1] = 0; + faceData->m_nContents = 0; + faceData->m_nFlags = 0; + faceData->m_nValue = 0; + if(*texture) + strcpy(faceData->m_TextureName, texture); + else + strcpy(faceData->m_TextureName, "textures/common/caulk"); + VectorCopy(va, faceData->m_v1); + VectorCopy(vb, faceData->m_v2); + VectorCopy(vc, faceData->m_v3); +} + +float Determinant3x3(float a1, float a2, float a3, + float b1, float b2, float b3, + float c1, float c2, float c3) +{ + return a1*(b2*c3-b3*c2) - a2*(b1*c3-b3*c1) + a3*(b1*c2-b2*c1); +} + +bool GetEntityCentre(const char* entity, vec3_t centre) +{ + entity_s* ent = FindEntityFromTargetname(entity, NULL); + if(!ent) + return FALSE; + + int cnt = g_FuncTable.m_pfnAllocateEntityBrushHandles(ent); + if(cnt == 0) + { + g_FuncTable.m_pfnReleaseEntityBrushHandles(); + return FALSE; + } + + brush_t* brush = (brush_t*)g_FuncTable.m_pfnGetEntityBrushHandle(0); + DBrush cBrush; + cBrush.LoadFromBrush_t(brush, FALSE); + + vec3_t min, max; + cBrush.GetBounds(min, max); + + VectorAdd(min, max, centre); + VectorScale(centre, 0.5f, centre); + + g_FuncTable.m_pfnReleaseEntityBrushHandles(); + return TRUE; +} + +vec_t Min(vec_t a, vec_t b) +{ + if(a < b) + return a; + return b; +} + +void MakeNormal( vec_t* va, vec_t* vb, vec_t* vc, vec_t* out ) { + vec3_t v1, v2; + VectorSubtract(va, vb, v1); + VectorSubtract(vc, vb, v2); + CrossProduct(v1, v2, out); +} diff --git a/contrib/bobtoolz/shapes.cpp b/contrib/bobtoolz/shapes.cpp index d69023ee..035179a7 100644 --- a/contrib/bobtoolz/shapes.cpp +++ b/contrib/bobtoolz/shapes.cpp @@ -1,666 +1,666 @@ -/* -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 -*/ - - -#include "StdAfx.h" - -#include "shapes.h" - -#include "DPlane.h" - -#include "misc.h" -#include "funchandlers.h" - -//#include "dialogs-gtk.h" - -/************************ - Cube Diagram -************************/ - -/* - - 7 ----- 5 - /| /| - / | / | - / | / | - 4 ----- 6 | - | 2|_|___|8 - | / | / - | / | / ----> WEST, definitely - |/ | / - 1|_____|/3 - -*/ - -/************************ - Global Variables -************************/ - -vec3_t g_Origin = {0.0f, 0.0f, 0.0f}; - -extern bool bFacesAll[]; - -/************************ - Helper Functions -************************/ - -float Deg2Rad(float angle) -{ - return (float)(angle*Q_PI/180); -} - -void AddFaceWithTexture(brush_t* brush, vec3_t va, vec3_t vb, vec3_t vc, const char* texture, bool detail) -{ - _QERFaceData faceData; - FillDefaultTexture(&faceData, va, vb, vc, texture); - if(detail) - faceData.m_nContents |= FACE_DETAIL; - - g_FuncTable.m_pfnAddFaceData(brush, &faceData); -} - -void AddFaceWithTextureScaled(brush_t* brush, vec3_t va, vec3_t vb, vec3_t vc, - const char* texture, bool bVertScale, bool bHorScale, - float minX, float minY, float maxX, float maxY) -{ - g_ShadersTable.m_pfnShader_ForName(texture); // need to call frist to load? - - qtexture_t* pqtTexInfo; - - // TTimo: there used to be a call to pfnHasShader here - // this was not necessary. In Radiant everything is shader. - // If a texture doesn't have a shader script, a default shader object is used. - // The IShader object was leaking also - // collect texture info: sizes, etc - IShader* i = g_ShadersTable.m_pfnShader_ForName(texture); - pqtTexInfo = i->getTexture(); // shader width/height doesn't come out properly - - if(pqtTexInfo) - { - float scale[2] = {0.5f, 0.5f}; - float shift[2] = {0, 0}; - - if(bHorScale) - { - int texWidth = pqtTexInfo->width; - float width = maxX - minX; - - scale[0] = width/texWidth; - shift[0] = -(float)((int)maxX%(int)width)/scale[0]; - } - - if(bVertScale) - { - int texHeight = pqtTexInfo->height; - float height = maxY - minY; - - scale[1] = height/texHeight; - shift[1] = (float)((int)minY%(int)height)/scale[1]; - } - - _QERFaceData addFace; - FillDefaultTexture(&addFace, va, vb, vc, texture); - addFace.m_fScale[0] = scale[0]; - addFace.m_fScale[1] = scale[1]; - addFace.m_fShift[0] = shift[0]; - addFace.m_fShift[1] = shift[1]; - - g_FuncTable.m_pfnAddFaceData(brush, &addFace); - } - else - { - // shouldn't even get here, as default missing texture should be returned if - // texture doesn't exist, but just in case - AddFaceWithTexture(brush, va, vb, vc, texture, FALSE); - Sys_ERROR("BobToolz::Invalid Texture Name-> %s", texture); - } - // the IShader is not kept referenced, DecRef it - i->DecRef(); -} - -/************************ - --Main Functions-- -************************/ - -void Build_Wedge(int dir, vec3_t min, vec3_t max, bool bUp) -{ - brush_t* newBrush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); - - vec3_t v1, v2, v3, v5, v6, v7, v8; - VectorCopy(min, v1); - VectorCopy(min, v2); - VectorCopy(min, v3); - VectorCopy(max, v5); - VectorCopy(max, v6); - VectorCopy(max, v7); - VectorCopy(max, v8); - - v2[0] = max[0]; - v3[1] = max[1]; - - v6[0] = min[0]; - v7[1] = min[1]; - v8[2] = min[2]; - - if(bUp) - { - - if(dir != MOVE_EAST) - AddFaceWithTexture(newBrush, v1, v3, v6, "textures/common/caulk", FALSE); - - if(dir != MOVE_WEST) - AddFaceWithTexture(newBrush, v7, v5, v8, "textures/common/caulk", FALSE); - - if(dir != MOVE_NORTH) - AddFaceWithTexture(newBrush, v1, v7, v2, "textures/common/caulk", FALSE); - - if(dir != MOVE_SOUTH) - AddFaceWithTexture(newBrush, v3, v8, v6, "textures/common/caulk", FALSE); - - AddFaceWithTexture(newBrush, v1, v2, v3, "textures/common/caulk", FALSE); - - if(dir == MOVE_EAST) - AddFaceWithTexture(newBrush, v1, v3, v5, "textures/common/caulk", FALSE); - - if(dir == MOVE_WEST) - AddFaceWithTexture(newBrush, v2, v6, v8, "textures/common/caulk", FALSE); - - if(dir == MOVE_NORTH) - AddFaceWithTexture(newBrush, v1, v6, v5, "textures/common/caulk", FALSE); - - if(dir == MOVE_SOUTH) - AddFaceWithTexture(newBrush, v7, v3, v8, "textures/common/caulk", FALSE); - } - else - { - if(dir != MOVE_WEST) - AddFaceWithTexture(newBrush, v7, v5, v8, "textures/common/caulk", FALSE); - - if(dir != MOVE_EAST) - AddFaceWithTexture(newBrush, v1, v3, v6, "textures/common/caulk", FALSE); - - if(dir != MOVE_NORTH) - AddFaceWithTexture(newBrush, v3, v8, v6, "textures/common/caulk", FALSE); - - if(dir != MOVE_SOUTH) - AddFaceWithTexture(newBrush, v1, v7, v2, "textures/common/caulk", FALSE); - - - AddFaceWithTexture(newBrush, v6, v5, v7, "textures/common/caulk", FALSE); - - if(dir == MOVE_WEST) - AddFaceWithTexture(newBrush, v1, v5, v3, "textures/common/caulk", FALSE); - - if(dir == MOVE_EAST) - AddFaceWithTexture(newBrush, v2, v8, v6, "textures/common/caulk", FALSE); - - if(dir == MOVE_NORTH) - AddFaceWithTexture(newBrush, v1, v5, v6, "textures/common/caulk", FALSE); - - if(dir == MOVE_SOUTH) - AddFaceWithTexture(newBrush, v7, v8, v3, "textures/common/caulk", FALSE); - } - - g_FuncTable.m_pfnCommitBrushHandle(newBrush); -} - -//----------------------------------------------------------------------------------- -//----------------------------------------------------------------------------------- - -void Build_StairStep_Wedge(int dir, vec3_t min, vec3_t max, const char* mainTexture, const char* riserTexture, bool detail) -{ - brush_t* newBrush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); - - //----- Build Outer Bounds --------- - - vec3_t v1, v2, v3, v5, v6, v7, v8; - VectorCopy(min, v1); - VectorCopy(min, v2); - VectorCopy(min, v3); - VectorCopy(max, v5); - VectorCopy(max, v6); - VectorCopy(max, v7); - VectorCopy(max, v8); - - v2[0] = max[0]; - v3[1] = max[1]; - - v6[0] = min[0]; - v7[1] = min[1]; - - v8[2] = min[2]; - //v8 needed this time, becoz of sloping faces (2-4-6-8) - - //---------------------------------- - - AddFaceWithTexture(newBrush, v6, v5, v7, mainTexture, detail); - - if(dir != MOVE_EAST) - { - if(dir == MOVE_WEST) - AddFaceWithTexture(newBrush, v5, v2, v7, riserTexture, detail); - else - AddFaceWithTexture(newBrush, v5, v2, v7, "textures/common/caulk", detail); - } - - if(dir != MOVE_WEST) - { - if(dir == MOVE_EAST) - AddFaceWithTexture(newBrush, v1, v3, v6, riserTexture, detail); - else - AddFaceWithTexture(newBrush, v1, v3, v6, "textures/common/caulk", detail); - } - - if(dir != MOVE_NORTH) - { - if(dir == MOVE_SOUTH) - AddFaceWithTexture(newBrush, v3, v5, v6, riserTexture, detail); - else - AddFaceWithTexture(newBrush, v3, v5, v6, "textures/common/caulk", detail); - } - - if(dir != MOVE_SOUTH) - { - if(dir == MOVE_NORTH) - AddFaceWithTexture(newBrush, v1, v7, v2, riserTexture, detail); - else - AddFaceWithTexture(newBrush, v1, v7, v2, "textures/common/caulk", detail); - } - - - if(dir == MOVE_EAST) - AddFaceWithTexture(newBrush, v1, v5, v3, "textures/common/caulk", detail); - - if(dir == MOVE_WEST) - AddFaceWithTexture(newBrush, v2, v8, v6, "textures/common/caulk", detail); - - if(dir == MOVE_NORTH) - AddFaceWithTexture(newBrush, v1, v5, v6, "textures/common/caulk", detail); - - if(dir == MOVE_SOUTH) - AddFaceWithTexture(newBrush, v7, v8, v3, "textures/common/caulk", detail); - - g_FuncTable.m_pfnCommitBrushHandle(newBrush); -} - -//----------------------------------------------------------------------------------- -//----------------------------------------------------------------------------------- - -// internal use only, to get a box without finishing construction -brush_t* Build_Get_BoundingCube_Selective(vec3_t min, vec3_t max, char* texture, bool* useFaces) -{ - brush_t* newBrush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); - - //----- Build Outer Bounds --------- - - vec3_t v1, v2, v3, v5, v6, v7; - VectorCopy(min, v1); - VectorCopy(min, v2); - VectorCopy(min, v3); - VectorCopy(max, v5); - VectorCopy(max, v6); - VectorCopy(max, v7); - - v2[0] = max[0]; - v3[1] = max[1]; - - v6[0] = min[0]; - v7[1] = min[1]; - - //---------------------------------- - - //----- Add Six Cube Faces --------- - - if(useFaces[0]) - AddFaceWithTexture(newBrush, v1, v2, v3, texture, FALSE); - if(useFaces[1]) - AddFaceWithTexture(newBrush, v1, v3, v6, texture, FALSE); - if(useFaces[2]) - AddFaceWithTexture(newBrush, v1, v7, v2, texture, FALSE); - - if(useFaces[3]) - AddFaceWithTexture(newBrush, v5, v6, v3, texture, FALSE); - if(useFaces[4]) - AddFaceWithTexture(newBrush, v5, v2, v7, texture, FALSE); - if(useFaces[5]) - AddFaceWithTexture(newBrush, v5, v7, v6, texture, FALSE); - - //---------------------------------- - - return newBrush; -} - -brush_t* Build_Get_BoundingCube(vec3_t min, vec3_t max, char* texture) -{ - return Build_Get_BoundingCube_Selective(min, max, texture, bFacesAll); -} - -//----------------------------------------------------------------------------------- -//----------------------------------------------------------------------------------- - -void Build_StairStep(vec3_t min, vec3_t max, const char* mainTexture, const char* riserTexture, int direction) -{ - brush_t* newBrush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); - - //----- Build Outer Bounds --------- - - vec3_t v1, v2, v3, v5, v6, v7; - VectorCopy(min, v1); - VectorCopy(min, v2); - VectorCopy(min, v3); - VectorCopy(max, v5); - VectorCopy(max, v6); - VectorCopy(max, v7); - - v2[0] = max[0]; - v3[1] = max[1]; - - v6[0] = min[0]; - v7[1] = min[1]; - - //---------------------------------- - - AddFaceWithTexture(newBrush, v6, v5, v7, mainTexture, FALSE); - // top gets current texture - - - if(direction == MOVE_EAST) - AddFaceWithTexture(newBrush, v1, v3, v6, riserTexture, FALSE); - else - AddFaceWithTexture(newBrush, v1, v3, v6, "textures/common/caulk", FALSE); - // west facing side, etc... - - - if(direction == MOVE_NORTH) - AddFaceWithTexture(newBrush, v1, v7, v2, riserTexture, FALSE); - else - AddFaceWithTexture(newBrush, v1, v7, v2, "textures/common/caulk", FALSE); - - if(direction == MOVE_SOUTH) - AddFaceWithTexture(newBrush, v3, v5, v6, riserTexture, FALSE); - else - AddFaceWithTexture(newBrush, v3, v5, v6, "textures/common/caulk", FALSE); - - if(direction == MOVE_WEST) - AddFaceWithTexture(newBrush, v7, v5, v2, riserTexture, FALSE); - else - AddFaceWithTexture(newBrush, v7, v5, v2, "textures/common/caulk", FALSE); - - - AddFaceWithTexture(newBrush, v1, v2, v3, "textures/common/caulk", FALSE); - // base is caulked - - g_FuncTable.m_pfnCommitBrushHandle(newBrush); - // finish brush -} - -//----------------------------------------------------------------------------------- -//----------------------------------------------------------------------------------- - -void BuildDoorsX2(vec3_t min, vec3_t max, - bool bSclMainHor, bool bSclMainVert, - bool bSclTrimHor, bool bSclTrimVert, - const char* mainTexture, const char* trimTexture, - int direction) -{ - int xy; - if(direction == 0) - xy = 0; - else - xy = 1; - - //----- Build Outer Bounds --------- - - vec3_t v1, v2, v3, v5, v6, v7, ve_1, ve_2, ve_3; - VectorCopy(min, v1); - VectorCopy(min, v2); - VectorCopy(min, v3); - VectorCopy(max, v5); - VectorCopy(max, v6); - VectorCopy(max, v7); - - v2[0] = max[0]; - v3[1] = max[1]; - - v6[0] = min[0]; - v7[1] = min[1]; - - float width = (max[xy] - min[xy])/2; - - if(direction == 0) - { - VectorCopy(v1, ve_1); - VectorCopy(v3, ve_2); - VectorCopy(v6, ve_3); - } - else - { - VectorCopy(v7, ve_1); - VectorCopy(v1, ve_2); - VectorCopy(v2, ve_3); - } - - ve_1[xy] += width; - ve_2[xy] += width; - ve_3[xy] += width; - - //---------------------------------- - - brush_t* newBrush1 = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); - brush_t* newBrush2 = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); - - AddFaceWithTexture(newBrush1, v1, v2, v3, "textures/common/caulk", FALSE); - AddFaceWithTexture(newBrush1, v5, v7, v6, "textures/common/caulk", FALSE); - - AddFaceWithTexture(newBrush2, v1, v2, v3, "textures/common/caulk", FALSE); - AddFaceWithTexture(newBrush2, v5, v7, v6, "textures/common/caulk", FALSE); - - if(direction == 0) - { - AddFaceWithTexture(newBrush1, v1, v3, v6, "textures/common/caulk", FALSE); - AddFaceWithTexture(newBrush2, v5, v2, v7, "textures/common/caulk", FALSE); - } - else - { - AddFaceWithTexture(newBrush1, v1, v7, v2, "textures/common/caulk", FALSE); - AddFaceWithTexture(newBrush2, v5, v6, v3, "textures/common/caulk", FALSE); - } - - if(direction == 0) - { - AddFaceWithTextureScaled(newBrush1, v1, v7, v2, mainTexture, bSclMainVert, bSclMainHor, - min[0], min[2], max[0], max[2]); - AddFaceWithTextureScaled(newBrush1, v5, v6, v3, mainTexture, bSclMainVert, bSclMainHor, - max[0], min[2], min[0], max[2]); - - - AddFaceWithTextureScaled(newBrush2, v1, v7, v2, mainTexture, bSclMainVert, bSclMainHor, - min[0], min[2], max[0], max[2]); - AddFaceWithTextureScaled(newBrush2, v5, v6, v3, mainTexture, bSclMainVert, bSclMainHor, - max[0], min[2], min[0], max[2]); // flip max/min to reverse tex dir - - - - AddFaceWithTextureScaled(newBrush1, ve_3, ve_2, ve_1, trimTexture, bSclTrimVert, bSclTrimHor, - min[1], min[2], max[1], max[2]); - - AddFaceWithTextureScaled(newBrush2, ve_1, ve_2, ve_3, trimTexture, bSclTrimVert, bSclTrimHor, - max[1], min[2], min[1], max[2]); - } - else - { - AddFaceWithTextureScaled(newBrush1, v1, v3, v6, mainTexture, bSclMainVert, bSclMainHor, - min[1], min[2], max[1], max[2]); - AddFaceWithTextureScaled(newBrush1, v5, v2, v7, mainTexture, bSclMainVert, bSclMainHor, - max[1], min[2], min[1], max[2]); - - - AddFaceWithTextureScaled(newBrush2, v1, v3, v6, mainTexture, bSclMainVert, bSclMainHor, - min[1], min[2], max[1], max[2]); - AddFaceWithTextureScaled(newBrush2, v5, v2, v7, mainTexture, bSclMainVert, bSclMainHor, - max[1], min[2], min[1], max[2]); // flip max/min to reverse tex dir - - - AddFaceWithTextureScaled(newBrush1, ve_1, ve_2, ve_3, trimTexture, bSclTrimVert, bSclTrimHor, - min[0], min[2], max[0], max[2]); - - AddFaceWithTextureScaled(newBrush2, ve_3, ve_2, ve_1, trimTexture, bSclTrimVert, bSclTrimHor, - max[0], min[2], min[0], max[2]); - } - - //---------------------------------- - - - entity_t* pEDoor1 = (entity_t*)g_FuncTable.m_pfnCreateEntityHandle(); - entity_t* pEDoor2 = (entity_t*)g_FuncTable.m_pfnCreateEntityHandle(); - - epair_t* epDoor11 = GetNextChainItem(NULL, "classname", "func_door"); - epair_t* epDoor21 = GetNextChainItem(NULL, "classname", "func_door"); - - epair_t* epDoor12; - epair_t* epDoor22; - - if(direction == 0) - { - epDoor12 = GetNextChainItem(epDoor11, "angle", "180"); - epDoor22 = GetNextChainItem(epDoor21, "angle", "360"); - } - else - { - epDoor12 = GetNextChainItem(epDoor11, "angle", "270"); - epDoor22 = GetNextChainItem(epDoor21, "angle", "90"); - } - - srand((unsigned)time(NULL)); - - char teamname[256]; - sprintf(teamname, "t%i", rand()); - /*epair_t* epDoor13 = */ GetNextChainItem(epDoor12, "team", teamname); - /*epair_t* epDoor23 = */ GetNextChainItem(epDoor22, "team", teamname); - - g_FuncTable.m_pfnCommitBrushHandleToEntity(newBrush1, pEDoor1); - g_FuncTable.m_pfnCommitBrushHandleToEntity(newBrush2, pEDoor2); - - g_EntityTable.m_pfnSetEntityKeyValList(pEDoor1, epDoor11); - g_EntityTable.m_pfnSetEntityKeyValList(pEDoor2, epDoor21); - - g_FuncTable.m_pfnCommitEntityHandleToMap(pEDoor1); - g_FuncTable.m_pfnCommitEntityHandleToMap(pEDoor2); - -// ResetCurrentTexture(); -} - -//----------------------------------------------------------------------------------- -//----------------------------------------------------------------------------------- - -void MakeBevel(vec3_t vMin, vec3_t vMax) -{ - int nIndex = g_FuncTable.m_pfnCreatePatchHandle(); - //$ FIXME: m_pfnGetPatchHandle - patchMesh_t* pm = g_FuncTable.m_pfnGetPatchData(nIndex); - - pm->height = 3; - pm->width = 3; - - vec3_t x_3, y_3, z_3; - x_3[0] = vMin[0]; x_3[1] = vMin[0]; x_3[2] = vMax[0]; - y_3[0] = vMin[1]; y_3[1] = vMax[1]; y_3[2] = vMax[1]; - z_3[0] = vMin[2]; z_3[1] = (vMax[2] + vMin[2])/2; z_3[2] = vMax[2]; - -/* x_3[0] = 0; x_3[1] = 0; x_3[2] = 64; - y_3[0] = 0; y_3[1] = 64; y_3[2] = 64; - z_3[0] = 0; z_3[1] = 32; z_3[2] = 64;*/ - - for(int i = 0; i < 3; i++) - { - for(int j = 0; j < 3; j++) - { - pm->ctrl[i][j].xyz[0] = x_3[i]; - pm->ctrl[i][j].xyz[1] = y_3[i]; - pm->ctrl[i][j].xyz[2] = z_3[j]; - } - } - - - g_FuncTable.m_pfnCommitPatchHandleToMap(nIndex, pm, "textures/common/caulk"); -} - -void BuildCornerStairs(vec3_t vMin, vec3_t vMax, int nSteps, const char* mainTexture, const char* riserTex) -{ - vec3_t* topPoints = new vec3_t[nSteps+1]; - vec3_t* botPoints = new vec3_t[nSteps+1]; - - bool bFacesUse[6] = {TRUE, TRUE, FALSE, TRUE, FALSE, FALSE}; - - vec3_t centre; - VectorCopy(vMin, centre); - centre[0] = vMax[0]; - - int height = (int)(vMax[2] - vMin[2]) / nSteps; - - vec3_t vTop, vBot; - VectorCopy(vMax, vTop); - VectorCopy(vMin, vBot); - vTop[2] = vMin[2] + height; - - int i; - for(i = 0; i <= nSteps; i++) - { - VectorCopy(centre, topPoints[i]); - VectorCopy(centre, botPoints[i]); - - topPoints[i][2] = vMax[2]; - botPoints[i][2] = vMin[2]; - - topPoints[i][0] -= 10 * sinf( Q_PI * i / ( 2 * nSteps ) ); - topPoints[i][1] += 10 * cosf( Q_PI * i / ( 2 * nSteps ) ); - - botPoints[i][0] = topPoints[i][0]; - botPoints[i][1] = topPoints[i][1]; - } - - vec3_t tp[3]; - for(int j = 0; j < 3; j++) - VectorCopy(topPoints[j], tp[j]); - - for(i = 0; i < nSteps; i++) - { - brush_t* brush = Build_Get_BoundingCube_Selective(vBot, vTop, "textures/common/caulk", bFacesUse); - - for(int j = 0; j < 3; j++) - tp[j][2] = vTop[2]; - - AddFaceWithTexture(brush, tp[2], tp[1], tp[0], mainTexture, FALSE); - - AddFaceWithTexture(brush, centre, botPoints[i+1], topPoints[i+1], "textures/common/caulk", FALSE); - AddFaceWithTexture(brush, centre, topPoints[i], botPoints[i], riserTex, FALSE); - - g_FuncTable.m_pfnCommitBrushHandle(brush); - - vTop[2] += height; - vBot[2] += height; - } - - delete[] topPoints; - delete[] botPoints; - - vMin[2] += height; - vMax[2] += height; - MakeBevel(vMin, vMax); -} +/* +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 +*/ + + +#include "StdAfx.h" + +#include "shapes.h" + +#include "DPlane.h" + +#include "misc.h" +#include "funchandlers.h" + +//#include "dialogs-gtk.h" + +/************************ + Cube Diagram +************************/ + +/* + + 7 ----- 5 + /| /| + / | / | + / | / | + 4 ----- 6 | + | 2|_|___|8 + | / | / + | / | / ----> WEST, definitely + |/ | / + 1|_____|/3 + +*/ + +/************************ + Global Variables +************************/ + +vec3_t g_Origin = {0.0f, 0.0f, 0.0f}; + +extern bool bFacesAll[]; + +/************************ + Helper Functions +************************/ + +float Deg2Rad(float angle) +{ + return (float)(angle*Q_PI/180); +} + +void AddFaceWithTexture(brush_t* brush, vec3_t va, vec3_t vb, vec3_t vc, const char* texture, bool detail) +{ + _QERFaceData faceData; + FillDefaultTexture(&faceData, va, vb, vc, texture); + if(detail) + faceData.m_nContents |= FACE_DETAIL; + + g_FuncTable.m_pfnAddFaceData(brush, &faceData); +} + +void AddFaceWithTextureScaled(brush_t* brush, vec3_t va, vec3_t vb, vec3_t vc, + const char* texture, bool bVertScale, bool bHorScale, + float minX, float minY, float maxX, float maxY) +{ + g_ShadersTable.m_pfnShader_ForName(texture); // need to call frist to load? + + qtexture_t* pqtTexInfo; + + // TTimo: there used to be a call to pfnHasShader here + // this was not necessary. In Radiant everything is shader. + // If a texture doesn't have a shader script, a default shader object is used. + // The IShader object was leaking also + // collect texture info: sizes, etc + IShader* i = g_ShadersTable.m_pfnShader_ForName(texture); + pqtTexInfo = i->getTexture(); // shader width/height doesn't come out properly + + if(pqtTexInfo) + { + float scale[2] = {0.5f, 0.5f}; + float shift[2] = {0, 0}; + + if(bHorScale) + { + int texWidth = pqtTexInfo->width; + float width = maxX - minX; + + scale[0] = width/texWidth; + shift[0] = -(float)((int)maxX%(int)width)/scale[0]; + } + + if(bVertScale) + { + int texHeight = pqtTexInfo->height; + float height = maxY - minY; + + scale[1] = height/texHeight; + shift[1] = (float)((int)minY%(int)height)/scale[1]; + } + + _QERFaceData addFace; + FillDefaultTexture(&addFace, va, vb, vc, texture); + addFace.m_fScale[0] = scale[0]; + addFace.m_fScale[1] = scale[1]; + addFace.m_fShift[0] = shift[0]; + addFace.m_fShift[1] = shift[1]; + + g_FuncTable.m_pfnAddFaceData(brush, &addFace); + } + else + { + // shouldn't even get here, as default missing texture should be returned if + // texture doesn't exist, but just in case + AddFaceWithTexture(brush, va, vb, vc, texture, FALSE); + Sys_ERROR("BobToolz::Invalid Texture Name-> %s", texture); + } + // the IShader is not kept referenced, DecRef it + i->DecRef(); +} + +/************************ + --Main Functions-- +************************/ + +void Build_Wedge(int dir, vec3_t min, vec3_t max, bool bUp) +{ + brush_t* newBrush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); + + vec3_t v1, v2, v3, v5, v6, v7, v8; + VectorCopy(min, v1); + VectorCopy(min, v2); + VectorCopy(min, v3); + VectorCopy(max, v5); + VectorCopy(max, v6); + VectorCopy(max, v7); + VectorCopy(max, v8); + + v2[0] = max[0]; + v3[1] = max[1]; + + v6[0] = min[0]; + v7[1] = min[1]; + v8[2] = min[2]; + + if(bUp) + { + + if(dir != MOVE_EAST) + AddFaceWithTexture(newBrush, v1, v3, v6, "textures/common/caulk", FALSE); + + if(dir != MOVE_WEST) + AddFaceWithTexture(newBrush, v7, v5, v8, "textures/common/caulk", FALSE); + + if(dir != MOVE_NORTH) + AddFaceWithTexture(newBrush, v1, v7, v2, "textures/common/caulk", FALSE); + + if(dir != MOVE_SOUTH) + AddFaceWithTexture(newBrush, v3, v8, v6, "textures/common/caulk", FALSE); + + AddFaceWithTexture(newBrush, v1, v2, v3, "textures/common/caulk", FALSE); + + if(dir == MOVE_EAST) + AddFaceWithTexture(newBrush, v1, v3, v5, "textures/common/caulk", FALSE); + + if(dir == MOVE_WEST) + AddFaceWithTexture(newBrush, v2, v6, v8, "textures/common/caulk", FALSE); + + if(dir == MOVE_NORTH) + AddFaceWithTexture(newBrush, v1, v6, v5, "textures/common/caulk", FALSE); + + if(dir == MOVE_SOUTH) + AddFaceWithTexture(newBrush, v7, v3, v8, "textures/common/caulk", FALSE); + } + else + { + if(dir != MOVE_WEST) + AddFaceWithTexture(newBrush, v7, v5, v8, "textures/common/caulk", FALSE); + + if(dir != MOVE_EAST) + AddFaceWithTexture(newBrush, v1, v3, v6, "textures/common/caulk", FALSE); + + if(dir != MOVE_NORTH) + AddFaceWithTexture(newBrush, v3, v8, v6, "textures/common/caulk", FALSE); + + if(dir != MOVE_SOUTH) + AddFaceWithTexture(newBrush, v1, v7, v2, "textures/common/caulk", FALSE); + + + AddFaceWithTexture(newBrush, v6, v5, v7, "textures/common/caulk", FALSE); + + if(dir == MOVE_WEST) + AddFaceWithTexture(newBrush, v1, v5, v3, "textures/common/caulk", FALSE); + + if(dir == MOVE_EAST) + AddFaceWithTexture(newBrush, v2, v8, v6, "textures/common/caulk", FALSE); + + if(dir == MOVE_NORTH) + AddFaceWithTexture(newBrush, v1, v5, v6, "textures/common/caulk", FALSE); + + if(dir == MOVE_SOUTH) + AddFaceWithTexture(newBrush, v7, v8, v3, "textures/common/caulk", FALSE); + } + + g_FuncTable.m_pfnCommitBrushHandle(newBrush); +} + +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- + +void Build_StairStep_Wedge(int dir, vec3_t min, vec3_t max, const char* mainTexture, const char* riserTexture, bool detail) +{ + brush_t* newBrush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); + + //----- Build Outer Bounds --------- + + vec3_t v1, v2, v3, v5, v6, v7, v8; + VectorCopy(min, v1); + VectorCopy(min, v2); + VectorCopy(min, v3); + VectorCopy(max, v5); + VectorCopy(max, v6); + VectorCopy(max, v7); + VectorCopy(max, v8); + + v2[0] = max[0]; + v3[1] = max[1]; + + v6[0] = min[0]; + v7[1] = min[1]; + + v8[2] = min[2]; + //v8 needed this time, becoz of sloping faces (2-4-6-8) + + //---------------------------------- + + AddFaceWithTexture(newBrush, v6, v5, v7, mainTexture, detail); + + if(dir != MOVE_EAST) + { + if(dir == MOVE_WEST) + AddFaceWithTexture(newBrush, v5, v2, v7, riserTexture, detail); + else + AddFaceWithTexture(newBrush, v5, v2, v7, "textures/common/caulk", detail); + } + + if(dir != MOVE_WEST) + { + if(dir == MOVE_EAST) + AddFaceWithTexture(newBrush, v1, v3, v6, riserTexture, detail); + else + AddFaceWithTexture(newBrush, v1, v3, v6, "textures/common/caulk", detail); + } + + if(dir != MOVE_NORTH) + { + if(dir == MOVE_SOUTH) + AddFaceWithTexture(newBrush, v3, v5, v6, riserTexture, detail); + else + AddFaceWithTexture(newBrush, v3, v5, v6, "textures/common/caulk", detail); + } + + if(dir != MOVE_SOUTH) + { + if(dir == MOVE_NORTH) + AddFaceWithTexture(newBrush, v1, v7, v2, riserTexture, detail); + else + AddFaceWithTexture(newBrush, v1, v7, v2, "textures/common/caulk", detail); + } + + + if(dir == MOVE_EAST) + AddFaceWithTexture(newBrush, v1, v5, v3, "textures/common/caulk", detail); + + if(dir == MOVE_WEST) + AddFaceWithTexture(newBrush, v2, v8, v6, "textures/common/caulk", detail); + + if(dir == MOVE_NORTH) + AddFaceWithTexture(newBrush, v1, v5, v6, "textures/common/caulk", detail); + + if(dir == MOVE_SOUTH) + AddFaceWithTexture(newBrush, v7, v8, v3, "textures/common/caulk", detail); + + g_FuncTable.m_pfnCommitBrushHandle(newBrush); +} + +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- + +// internal use only, to get a box without finishing construction +brush_t* Build_Get_BoundingCube_Selective(vec3_t min, vec3_t max, char* texture, bool* useFaces) +{ + brush_t* newBrush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); + + //----- Build Outer Bounds --------- + + vec3_t v1, v2, v3, v5, v6, v7; + VectorCopy(min, v1); + VectorCopy(min, v2); + VectorCopy(min, v3); + VectorCopy(max, v5); + VectorCopy(max, v6); + VectorCopy(max, v7); + + v2[0] = max[0]; + v3[1] = max[1]; + + v6[0] = min[0]; + v7[1] = min[1]; + + //---------------------------------- + + //----- Add Six Cube Faces --------- + + if(useFaces[0]) + AddFaceWithTexture(newBrush, v1, v2, v3, texture, FALSE); + if(useFaces[1]) + AddFaceWithTexture(newBrush, v1, v3, v6, texture, FALSE); + if(useFaces[2]) + AddFaceWithTexture(newBrush, v1, v7, v2, texture, FALSE); + + if(useFaces[3]) + AddFaceWithTexture(newBrush, v5, v6, v3, texture, FALSE); + if(useFaces[4]) + AddFaceWithTexture(newBrush, v5, v2, v7, texture, FALSE); + if(useFaces[5]) + AddFaceWithTexture(newBrush, v5, v7, v6, texture, FALSE); + + //---------------------------------- + + return newBrush; +} + +brush_t* Build_Get_BoundingCube(vec3_t min, vec3_t max, char* texture) +{ + return Build_Get_BoundingCube_Selective(min, max, texture, bFacesAll); +} + +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- + +void Build_StairStep(vec3_t min, vec3_t max, const char* mainTexture, const char* riserTexture, int direction) +{ + brush_t* newBrush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); + + //----- Build Outer Bounds --------- + + vec3_t v1, v2, v3, v5, v6, v7; + VectorCopy(min, v1); + VectorCopy(min, v2); + VectorCopy(min, v3); + VectorCopy(max, v5); + VectorCopy(max, v6); + VectorCopy(max, v7); + + v2[0] = max[0]; + v3[1] = max[1]; + + v6[0] = min[0]; + v7[1] = min[1]; + + //---------------------------------- + + AddFaceWithTexture(newBrush, v6, v5, v7, mainTexture, FALSE); + // top gets current texture + + + if(direction == MOVE_EAST) + AddFaceWithTexture(newBrush, v1, v3, v6, riserTexture, FALSE); + else + AddFaceWithTexture(newBrush, v1, v3, v6, "textures/common/caulk", FALSE); + // west facing side, etc... + + + if(direction == MOVE_NORTH) + AddFaceWithTexture(newBrush, v1, v7, v2, riserTexture, FALSE); + else + AddFaceWithTexture(newBrush, v1, v7, v2, "textures/common/caulk", FALSE); + + if(direction == MOVE_SOUTH) + AddFaceWithTexture(newBrush, v3, v5, v6, riserTexture, FALSE); + else + AddFaceWithTexture(newBrush, v3, v5, v6, "textures/common/caulk", FALSE); + + if(direction == MOVE_WEST) + AddFaceWithTexture(newBrush, v7, v5, v2, riserTexture, FALSE); + else + AddFaceWithTexture(newBrush, v7, v5, v2, "textures/common/caulk", FALSE); + + + AddFaceWithTexture(newBrush, v1, v2, v3, "textures/common/caulk", FALSE); + // base is caulked + + g_FuncTable.m_pfnCommitBrushHandle(newBrush); + // finish brush +} + +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- + +void BuildDoorsX2(vec3_t min, vec3_t max, + bool bSclMainHor, bool bSclMainVert, + bool bSclTrimHor, bool bSclTrimVert, + const char* mainTexture, const char* trimTexture, + int direction) +{ + int xy; + if(direction == 0) + xy = 0; + else + xy = 1; + + //----- Build Outer Bounds --------- + + vec3_t v1, v2, v3, v5, v6, v7, ve_1, ve_2, ve_3; + VectorCopy(min, v1); + VectorCopy(min, v2); + VectorCopy(min, v3); + VectorCopy(max, v5); + VectorCopy(max, v6); + VectorCopy(max, v7); + + v2[0] = max[0]; + v3[1] = max[1]; + + v6[0] = min[0]; + v7[1] = min[1]; + + float width = (max[xy] - min[xy])/2; + + if(direction == 0) + { + VectorCopy(v1, ve_1); + VectorCopy(v3, ve_2); + VectorCopy(v6, ve_3); + } + else + { + VectorCopy(v7, ve_1); + VectorCopy(v1, ve_2); + VectorCopy(v2, ve_3); + } + + ve_1[xy] += width; + ve_2[xy] += width; + ve_3[xy] += width; + + //---------------------------------- + + brush_t* newBrush1 = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); + brush_t* newBrush2 = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); + + AddFaceWithTexture(newBrush1, v1, v2, v3, "textures/common/caulk", FALSE); + AddFaceWithTexture(newBrush1, v5, v7, v6, "textures/common/caulk", FALSE); + + AddFaceWithTexture(newBrush2, v1, v2, v3, "textures/common/caulk", FALSE); + AddFaceWithTexture(newBrush2, v5, v7, v6, "textures/common/caulk", FALSE); + + if(direction == 0) + { + AddFaceWithTexture(newBrush1, v1, v3, v6, "textures/common/caulk", FALSE); + AddFaceWithTexture(newBrush2, v5, v2, v7, "textures/common/caulk", FALSE); + } + else + { + AddFaceWithTexture(newBrush1, v1, v7, v2, "textures/common/caulk", FALSE); + AddFaceWithTexture(newBrush2, v5, v6, v3, "textures/common/caulk", FALSE); + } + + if(direction == 0) + { + AddFaceWithTextureScaled(newBrush1, v1, v7, v2, mainTexture, bSclMainVert, bSclMainHor, + min[0], min[2], max[0], max[2]); + AddFaceWithTextureScaled(newBrush1, v5, v6, v3, mainTexture, bSclMainVert, bSclMainHor, + max[0], min[2], min[0], max[2]); + + + AddFaceWithTextureScaled(newBrush2, v1, v7, v2, mainTexture, bSclMainVert, bSclMainHor, + min[0], min[2], max[0], max[2]); + AddFaceWithTextureScaled(newBrush2, v5, v6, v3, mainTexture, bSclMainVert, bSclMainHor, + max[0], min[2], min[0], max[2]); // flip max/min to reverse tex dir + + + + AddFaceWithTextureScaled(newBrush1, ve_3, ve_2, ve_1, trimTexture, bSclTrimVert, bSclTrimHor, + min[1], min[2], max[1], max[2]); + + AddFaceWithTextureScaled(newBrush2, ve_1, ve_2, ve_3, trimTexture, bSclTrimVert, bSclTrimHor, + max[1], min[2], min[1], max[2]); + } + else + { + AddFaceWithTextureScaled(newBrush1, v1, v3, v6, mainTexture, bSclMainVert, bSclMainHor, + min[1], min[2], max[1], max[2]); + AddFaceWithTextureScaled(newBrush1, v5, v2, v7, mainTexture, bSclMainVert, bSclMainHor, + max[1], min[2], min[1], max[2]); + + + AddFaceWithTextureScaled(newBrush2, v1, v3, v6, mainTexture, bSclMainVert, bSclMainHor, + min[1], min[2], max[1], max[2]); + AddFaceWithTextureScaled(newBrush2, v5, v2, v7, mainTexture, bSclMainVert, bSclMainHor, + max[1], min[2], min[1], max[2]); // flip max/min to reverse tex dir + + + AddFaceWithTextureScaled(newBrush1, ve_1, ve_2, ve_3, trimTexture, bSclTrimVert, bSclTrimHor, + min[0], min[2], max[0], max[2]); + + AddFaceWithTextureScaled(newBrush2, ve_3, ve_2, ve_1, trimTexture, bSclTrimVert, bSclTrimHor, + max[0], min[2], min[0], max[2]); + } + + //---------------------------------- + + + entity_t* pEDoor1 = (entity_t*)g_FuncTable.m_pfnCreateEntityHandle(); + entity_t* pEDoor2 = (entity_t*)g_FuncTable.m_pfnCreateEntityHandle(); + + epair_t* epDoor11 = GetNextChainItem(NULL, "classname", "func_door"); + epair_t* epDoor21 = GetNextChainItem(NULL, "classname", "func_door"); + + epair_t* epDoor12; + epair_t* epDoor22; + + if(direction == 0) + { + epDoor12 = GetNextChainItem(epDoor11, "angle", "180"); + epDoor22 = GetNextChainItem(epDoor21, "angle", "360"); + } + else + { + epDoor12 = GetNextChainItem(epDoor11, "angle", "270"); + epDoor22 = GetNextChainItem(epDoor21, "angle", "90"); + } + + srand((unsigned)time(NULL)); + + char teamname[256]; + sprintf(teamname, "t%i", rand()); + /*epair_t* epDoor13 = */ GetNextChainItem(epDoor12, "team", teamname); + /*epair_t* epDoor23 = */ GetNextChainItem(epDoor22, "team", teamname); + + g_FuncTable.m_pfnCommitBrushHandleToEntity(newBrush1, pEDoor1); + g_FuncTable.m_pfnCommitBrushHandleToEntity(newBrush2, pEDoor2); + + g_EntityTable.m_pfnSetEntityKeyValList(pEDoor1, epDoor11); + g_EntityTable.m_pfnSetEntityKeyValList(pEDoor2, epDoor21); + + g_FuncTable.m_pfnCommitEntityHandleToMap(pEDoor1); + g_FuncTable.m_pfnCommitEntityHandleToMap(pEDoor2); + +// ResetCurrentTexture(); +} + +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- + +void MakeBevel(vec3_t vMin, vec3_t vMax) +{ + int nIndex = g_FuncTable.m_pfnCreatePatchHandle(); + //$ FIXME: m_pfnGetPatchHandle + patchMesh_t* pm = g_FuncTable.m_pfnGetPatchData(nIndex); + + pm->height = 3; + pm->width = 3; + + vec3_t x_3, y_3, z_3; + x_3[0] = vMin[0]; x_3[1] = vMin[0]; x_3[2] = vMax[0]; + y_3[0] = vMin[1]; y_3[1] = vMax[1]; y_3[2] = vMax[1]; + z_3[0] = vMin[2]; z_3[1] = (vMax[2] + vMin[2])/2; z_3[2] = vMax[2]; + +/* x_3[0] = 0; x_3[1] = 0; x_3[2] = 64; + y_3[0] = 0; y_3[1] = 64; y_3[2] = 64; + z_3[0] = 0; z_3[1] = 32; z_3[2] = 64;*/ + + for(int i = 0; i < 3; i++) + { + for(int j = 0; j < 3; j++) + { + pm->ctrl[i][j].xyz[0] = x_3[i]; + pm->ctrl[i][j].xyz[1] = y_3[i]; + pm->ctrl[i][j].xyz[2] = z_3[j]; + } + } + + + g_FuncTable.m_pfnCommitPatchHandleToMap(nIndex, pm, "textures/common/caulk"); +} + +void BuildCornerStairs(vec3_t vMin, vec3_t vMax, int nSteps, const char* mainTexture, const char* riserTex) +{ + vec3_t* topPoints = new vec3_t[nSteps+1]; + vec3_t* botPoints = new vec3_t[nSteps+1]; + + bool bFacesUse[6] = {TRUE, TRUE, FALSE, TRUE, FALSE, FALSE}; + + vec3_t centre; + VectorCopy(vMin, centre); + centre[0] = vMax[0]; + + int height = (int)(vMax[2] - vMin[2]) / nSteps; + + vec3_t vTop, vBot; + VectorCopy(vMax, vTop); + VectorCopy(vMin, vBot); + vTop[2] = vMin[2] + height; + + int i; + for(i = 0; i <= nSteps; i++) + { + VectorCopy(centre, topPoints[i]); + VectorCopy(centre, botPoints[i]); + + topPoints[i][2] = vMax[2]; + botPoints[i][2] = vMin[2]; + + topPoints[i][0] -= 10 * sinf( Q_PI * i / ( 2 * nSteps ) ); + topPoints[i][1] += 10 * cosf( Q_PI * i / ( 2 * nSteps ) ); + + botPoints[i][0] = topPoints[i][0]; + botPoints[i][1] = topPoints[i][1]; + } + + vec3_t tp[3]; + for(int j = 0; j < 3; j++) + VectorCopy(topPoints[j], tp[j]); + + for(i = 0; i < nSteps; i++) + { + brush_t* brush = Build_Get_BoundingCube_Selective(vBot, vTop, "textures/common/caulk", bFacesUse); + + for(int j = 0; j < 3; j++) + tp[j][2] = vTop[2]; + + AddFaceWithTexture(brush, tp[2], tp[1], tp[0], mainTexture, FALSE); + + AddFaceWithTexture(brush, centre, botPoints[i+1], topPoints[i+1], "textures/common/caulk", FALSE); + AddFaceWithTexture(brush, centre, topPoints[i], botPoints[i], riserTex, FALSE); + + g_FuncTable.m_pfnCommitBrushHandle(brush); + + vTop[2] += height; + vBot[2] += height; + } + + delete[] topPoints; + delete[] botPoints; + + vMin[2] += height; + vMax[2] += height; + MakeBevel(vMin, vMax); +} diff --git a/contrib/bobtoolz/visfind.cpp b/contrib/bobtoolz/visfind.cpp index 28525ff9..6a54ab44 100644 --- a/contrib/bobtoolz/visfind.cpp +++ b/contrib/bobtoolz/visfind.cpp @@ -1,245 +1,245 @@ -// Requries parts of the q3 tools source to compile -// Date: Oct 5, 2001 -// Written by: Brad Whitehead (whiteheb@gamerstv.net) - -#include "StdAfx.h" -#include "dialogs/dialogs-gtk.h" -#include "DWinding.h" -#include "bsploader.h" - -typedef struct { - int portalclusters; - int leafbytes; //leafbytes = ((portalclusters+63)&~63)>>3; -} vis_header; - -// added because int shift = 32; i = 0xFFFFFFFF >> shift; -// then i = 0xFFFFFFFF, when it should = 0 -const unsigned long bitmasks[33] = -{ - 0x00000000, - 0x00000001, 0x00000003, 0x00000007, 0x0000000F, - 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF, - 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF, - 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF, - 0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF, - 0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF, - 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF, - 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF -}; - -int bsp_leafnumfororigin(vec3_t origin) -{ - dnode_t *node; - dplane_t *plane; - float d; - - // TODO: check if origin is in the map?? - - node = dnodes; - while (true) - { - plane = &dplanes[node->planeNum]; - d = DotProduct (origin, plane->normal) - plane->dist; - if ( d >= 0 ) - if ( node->children[0] < 0 ) - return -(node->children[0]+1); - else - node = &dnodes[node->children[0]]; - else - if ( node->children[1] < 0 ) - return -(node->children[1]+1); - else - node = &dnodes[node->children[1]]; - } - return 0; -} - -int bsp_leafnumforcluster(int cluster) -{ - dleaf_t *l; - int i; - - for ( i = 0, l = dleafs; i < numleafs; i++, l++ ) - if ( l->cluster == cluster ) return(i); - return(0); -} - -// leaf1 = origin leaf -// leaf2 = leaf to test for -/*int bsp_InPVS(int cluster1, int cluster2) -{ - vis_header *vheader; - byte *visdata; - - vheader = (vis_header *) visBytes; - visdata = visBytes + VIS_HEADER_SIZE; - - return( *( visdata + ( cluster1 * vheader->leafbytes ) + (cluster2 / 8) ) & ( 1 << ( cluster2 % 8 ) ) ); -}*/ - -void bsp_setbitvectorlength( byte *v, int length_bits, int length_vector ) -{ - int i; - - i = length_bits/8; - - *(v+i) = (byte) bitmasks[length_bits % 8]; - - memset((v+i+1), 0, length_vector-i-1); -} - - -void bsp_bitvectorsubtract(byte *first, byte *second, byte *out, int length) -{ - - int i; - - for ( i = 0; i < length; i++ ) - *(out+i) = *(first+i) & ~(*(second+i)); -} - -int bsp_countclusters(byte *bitvector, int length) -{ - int i, j, c; - - c = 0; - for ( i = 0; i < length; i++ ) - for ( j = 0; j < 8; j++ ) - if ( (*(bitvector+i) & (1 << j)) ) c++; - return(c); -} - -int bsp_countclusters_mask(byte *bitvector, byte *maskvector, int length) -{ - int i, j, c; - - c = 0; - for ( i = 0; i < length; i++ ) - for ( j = 0; j < 8; j++ ) - if ( (*(bitvector+i) & (1 << j)) && (*(maskvector+i) & (1 << j)) ) c++; - return(c); -} - -void AddCluster(list *pointlist, dleaf_t *cl, qboolean* repeatlist, vec3_t clr) -{ - DWinding* w; - - int* leafsurf = &dleafsurfaces[cl->firstLeafSurface]; - for(int k = 0; k < cl->numLeafSurfaces; k++, leafsurf++) - { - if(repeatlist[*leafsurf]) - continue; - - dsurface_t* surf = &drawSurfaces[*leafsurf]; - if(surf->surfaceType != MST_PLANAR) - continue; - - qdrawVert_t* vert = &drawVerts[surf->firstVert]; - if(surf->firstVert + surf->numVerts > numDrawVerts) - DoMessageBox("Warning", "Warning", MB_OK); - - w = new DWinding(); - w->AllocWinding(surf->numVerts); - - for (int l = 0; l < surf->numVerts; l++, vert++) - { - (w->p[l])[0] = vert->xyz[0]; - (w->p[l])[1] = vert->xyz[1]; - (w->p[l])[2] = vert->xyz[2]; - - w->clr[0] = clr[0]; - w->clr[1] = clr[1]; - w->clr[2] = clr[2]; - } - pointlist->push_back(w); - - repeatlist[*leafsurf] = true; - } -} - -/* -============= -CreateTrace -============= -*/ -list *CreateTrace( dleaf_t *leaf, int c, vis_header *header, byte *visdata, byte *seen ) -{ - byte *vis; - int i, j, clusterNum; - list *pointlist = new list; - qboolean* repeatlist = new qboolean[numDrawSurfaces]; - dleaf_t *cl; - - vec3_t clrRnd[5] = { - {0.f, 0.f, 1.f}, - {0.f, 1.f, 1.f}, - {1.f, 0.f, 0.f}, - {1.f, 0.f, 1.f}, - {1.f, 1.f, 0.f}, - }; - - vec3_t clrGreen = {0.f, 1.f, 0.f}; - - memset(repeatlist, 0, sizeof(qboolean)*numDrawSurfaces); - - vis = visdata + ( c * header->leafbytes ); - - clusterNum = 0; - - AddCluster(pointlist, &(dleafs[bsp_leafnumforcluster( c )]), repeatlist, clrGreen); - - for ( i = 0; i < header->leafbytes; i++ ) - { - for ( j = 0; j < 8; j++ ) - { - cl = &(dleafs[bsp_leafnumforcluster( clusterNum )]); - - if ( ( *(vis + i) & (1 << j) ) && (*(seen+i) & (1 << j)) && (leaf->area == cl->area)) - AddCluster(pointlist, cl, repeatlist, clrRnd[rand()%5]); - clusterNum++; - } - } - - delete repeatlist; - - return pointlist; -} - -/* -============= -TraceCluster - -setup for CreateTrace -============= -*/ -list *TraceCluster (int leafnum) -{ - byte seen[(MAX_MAP_LEAFS/8) + 1]; - vis_header *vheader; - byte *visdata; - dleaf_t *leaf; - - vheader = (vis_header *) visBytes; - visdata = visBytes + sizeof(vis_header); - - memset(seen, 0xFF, sizeof(seen)); - bsp_setbitvectorlength(seen, vheader->portalclusters, sizeof(seen)); - - leaf = &(dleafs[leafnum]); - - return CreateTrace(leaf, leaf->cluster, vheader, visdata, seen); -} - -list* BuildTrace(char* filename, vec3_t v_origin) -{ - if(!LoadBSPFile(filename)) - return NULL; - - int leafnum = bsp_leafnumfororigin(v_origin); - - list *pointlist = TraceCluster(leafnum); - - FreeBSPData(); - - return pointlist; -} +// Requries parts of the q3 tools source to compile +// Date: Oct 5, 2001 +// Written by: Brad Whitehead (whiteheb@gamerstv.net) + +#include "StdAfx.h" +#include "dialogs/dialogs-gtk.h" +#include "DWinding.h" +#include "bsploader.h" + +typedef struct { + int portalclusters; + int leafbytes; //leafbytes = ((portalclusters+63)&~63)>>3; +} vis_header; + +// added because int shift = 32; i = 0xFFFFFFFF >> shift; +// then i = 0xFFFFFFFF, when it should = 0 +const unsigned long bitmasks[33] = +{ + 0x00000000, + 0x00000001, 0x00000003, 0x00000007, 0x0000000F, + 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF, + 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF, + 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF, + 0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF, + 0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF, + 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF, + 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF +}; + +int bsp_leafnumfororigin(vec3_t origin) +{ + dnode_t *node; + dplane_t *plane; + float d; + + // TODO: check if origin is in the map?? + + node = dnodes; + while (true) + { + plane = &dplanes[node->planeNum]; + d = DotProduct (origin, plane->normal) - plane->dist; + if ( d >= 0 ) + if ( node->children[0] < 0 ) + return -(node->children[0]+1); + else + node = &dnodes[node->children[0]]; + else + if ( node->children[1] < 0 ) + return -(node->children[1]+1); + else + node = &dnodes[node->children[1]]; + } + return 0; +} + +int bsp_leafnumforcluster(int cluster) +{ + dleaf_t *l; + int i; + + for ( i = 0, l = dleafs; i < numleafs; i++, l++ ) + if ( l->cluster == cluster ) return(i); + return(0); +} + +// leaf1 = origin leaf +// leaf2 = leaf to test for +/*int bsp_InPVS(int cluster1, int cluster2) +{ + vis_header *vheader; + byte *visdata; + + vheader = (vis_header *) visBytes; + visdata = visBytes + VIS_HEADER_SIZE; + + return( *( visdata + ( cluster1 * vheader->leafbytes ) + (cluster2 / 8) ) & ( 1 << ( cluster2 % 8 ) ) ); +}*/ + +void bsp_setbitvectorlength( byte *v, int length_bits, int length_vector ) +{ + int i; + + i = length_bits/8; + + *(v+i) = (byte) bitmasks[length_bits % 8]; + + memset((v+i+1), 0, length_vector-i-1); +} + + +void bsp_bitvectorsubtract(byte *first, byte *second, byte *out, int length) +{ + + int i; + + for ( i = 0; i < length; i++ ) + *(out+i) = *(first+i) & ~(*(second+i)); +} + +int bsp_countclusters(byte *bitvector, int length) +{ + int i, j, c; + + c = 0; + for ( i = 0; i < length; i++ ) + for ( j = 0; j < 8; j++ ) + if ( (*(bitvector+i) & (1 << j)) ) c++; + return(c); +} + +int bsp_countclusters_mask(byte *bitvector, byte *maskvector, int length) +{ + int i, j, c; + + c = 0; + for ( i = 0; i < length; i++ ) + for ( j = 0; j < 8; j++ ) + if ( (*(bitvector+i) & (1 << j)) && (*(maskvector+i) & (1 << j)) ) c++; + return(c); +} + +void AddCluster(list *pointlist, dleaf_t *cl, qboolean* repeatlist, vec3_t clr) +{ + DWinding* w; + + int* leafsurf = &dleafsurfaces[cl->firstLeafSurface]; + for(int k = 0; k < cl->numLeafSurfaces; k++, leafsurf++) + { + if(repeatlist[*leafsurf]) + continue; + + dsurface_t* surf = &drawSurfaces[*leafsurf]; + if(surf->surfaceType != MST_PLANAR) + continue; + + qdrawVert_t* vert = &drawVerts[surf->firstVert]; + if(surf->firstVert + surf->numVerts > numDrawVerts) + DoMessageBox("Warning", "Warning", MB_OK); + + w = new DWinding(); + w->AllocWinding(surf->numVerts); + + for (int l = 0; l < surf->numVerts; l++, vert++) + { + (w->p[l])[0] = vert->xyz[0]; + (w->p[l])[1] = vert->xyz[1]; + (w->p[l])[2] = vert->xyz[2]; + + w->clr[0] = clr[0]; + w->clr[1] = clr[1]; + w->clr[2] = clr[2]; + } + pointlist->push_back(w); + + repeatlist[*leafsurf] = true; + } +} + +/* +============= +CreateTrace +============= +*/ +list *CreateTrace( dleaf_t *leaf, int c, vis_header *header, byte *visdata, byte *seen ) +{ + byte *vis; + int i, j, clusterNum; + list *pointlist = new list; + qboolean* repeatlist = new qboolean[numDrawSurfaces]; + dleaf_t *cl; + + vec3_t clrRnd[5] = { + {0.f, 0.f, 1.f}, + {0.f, 1.f, 1.f}, + {1.f, 0.f, 0.f}, + {1.f, 0.f, 1.f}, + {1.f, 1.f, 0.f}, + }; + + vec3_t clrGreen = {0.f, 1.f, 0.f}; + + memset(repeatlist, 0, sizeof(qboolean)*numDrawSurfaces); + + vis = visdata + ( c * header->leafbytes ); + + clusterNum = 0; + + AddCluster(pointlist, &(dleafs[bsp_leafnumforcluster( c )]), repeatlist, clrGreen); + + for ( i = 0; i < header->leafbytes; i++ ) + { + for ( j = 0; j < 8; j++ ) + { + cl = &(dleafs[bsp_leafnumforcluster( clusterNum )]); + + if ( ( *(vis + i) & (1 << j) ) && (*(seen+i) & (1 << j)) && (leaf->area == cl->area)) + AddCluster(pointlist, cl, repeatlist, clrRnd[rand()%5]); + clusterNum++; + } + } + + delete repeatlist; + + return pointlist; +} + +/* +============= +TraceCluster + +setup for CreateTrace +============= +*/ +list *TraceCluster (int leafnum) +{ + byte seen[(MAX_MAP_LEAFS/8) + 1]; + vis_header *vheader; + byte *visdata; + dleaf_t *leaf; + + vheader = (vis_header *) visBytes; + visdata = visBytes + sizeof(vis_header); + + memset(seen, 0xFF, sizeof(seen)); + bsp_setbitvectorlength(seen, vheader->portalclusters, sizeof(seen)); + + leaf = &(dleafs[leafnum]); + + return CreateTrace(leaf, leaf->cluster, vheader, visdata, seen); +} + +list* BuildTrace(char* filename, vec3_t v_origin) +{ + if(!LoadBSPFile(filename)) + return NULL; + + int leafnum = bsp_leafnumfororigin(v_origin); + + list *pointlist = TraceCluster(leafnum); + + FreeBSPData(); + + return pointlist; +} diff --git a/contrib/camera/camera.cpp b/contrib/camera/camera.cpp index bd38dabc..dbad8085 100644 --- a/contrib/camera/camera.cpp +++ b/contrib/camera/camera.cpp @@ -1,297 +1,297 @@ -/* -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 -*/ - -/* -Camera plugin for GtkRadiant -Copyright (C) 2002 Splash Damage Ltd. -*/ - -#include "camera.h" - -// Render view -CRenderer *Renderer = NULL; - -// Interaction -CListener *Listener = NULL; - -// plugin name -static const char *PLUGIN_NAME = "Camera"; - -// commands in the menu -static const char *PLUGIN_COMMANDS = "About...,-,Load Camera...,-,Preview Camera,-,Camera Inspector...,-,New Spline Camera,New Interpolated Camera,New Fixed Camera"; - -// globals -GtkWidget *g_pRadiantWnd = NULL; -GtkWidget *g_pCameraInspectorWnd = NULL; -CCamera *firstCam = NULL; // double linked list -CCamera *firstFreeCam = NULL; // single linked list -CCamera *currentCam = NULL; // single item -bool g_bEditOn = false; -int g_iEditMode = 0; // 0: editting points 1: adding points -int g_iActiveTarget = -1; -int g_iPreviewRunning = 0; // 0: no preview 1: start preview 2: preview in progress - -static const char *PLUGIN_ABOUT = "Camera v1.0 for GtkRadiant\n" - "by Arnout van Meer (rr2do2@splashdamage.com)\n\n" - "This product contains software technology\n" - "from id Software, Inc. ('id Technology').\n" - "id Technology (c) 2001, 2002 id Software, Inc."; - - -#include "iplugin.h" - -const char* QERPlug_Init(void* hApp, void* pMainWidget) -{ - g_pRadiantWnd = (GtkWidget*)pMainWidget; - - // initialize cams - for( int i = 0; i < MAX_CAMERAS; i++ ) { - if( i == 0 ) { - firstFreeCam = new CCamera( i ); - firstCam = firstFreeCam; - } else { - firstCam->SetNext( new CCamera( i ) ); - firstCam = firstCam->GetNext(); - } - } - firstCam = NULL; - - if( !Renderer ) - { - Renderer = new CRenderer; - } - - if( g_pCameraInspectorWnd == NULL ) - g_pCameraInspectorWnd = CreateCameraInspectorDialog(); - - InitIglToQgl(&g_QglTable); - - GetFileTypeRegistry()->addType("camera", filetype_t("Camera file", "*.camera")); - - return "Camera for GtkRadiant"; -} - -const char* QERPlug_GetName() -{ - return PLUGIN_NAME; -} - -const char* QERPlug_GetCommandList() -{ - return PLUGIN_COMMANDS; -} - -void QERPlug_Dispatch (const char* p, float* vMin, float* vMax, bool bSingleBrush) -{ - if( !strcmp( p, "New Fixed Camera" ) ) - DoNewFixedCamera(); - else if( !strcmp( p, "New Interpolated Camera" ) ) - DoNewInterpolatedCamera(); - else if( !strcmp( p, "New Spline Camera" ) ) - DoNewSplineCamera(); - else if( !strcmp( p, "Camera Inspector..." ) ) - DoCameraInspector(); - else if( !strcmp( p, "Preview Camera" ) ) - DoPreviewCamera(); - else if( !strcmp( p, "Load Camera..." ) ) - DoLoadCamera(); - else if( !strcmp( p, "About..." ) ) - g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, PLUGIN_ABOUT, "About", MB_OK, NULL ); -} - - -// toolbar - -#include "itoolbar.h" - -unsigned int ToolbarButtonCount() -{ - return 1; -} - -class CameraInspectorButton : public IToolbarButton -{ -public: - virtual const char* getImage() const - { - return "camera_insp.bmp"; - } - virtual const char* getText() const - { - return "Inspector"; - } - virtual const char* getTooltip() const - { - return "Camera Inspector"; - } - virtual void activate() const - { - DoCameraInspector(); - } - virtual EType getType() const - { - return eButton; - } -}; - -CameraInspectorButton g_camerainspectorbutton; - -const IToolbarButton* GetToolbarButton(unsigned int index) -{ - return &g_camerainspectorbutton; -} - - -_QERFuncTable_1 g_FuncTable; -_QERQglTable g_QglTable; -_QERUITable g_UITable; -_QERCameraTable g_CameraTable; - -// ============================================================================= -// SYNAPSE - -#include "synapse.h" - -class CameraSynapseClient : public CSynapseClient -{ -public: - // CSynapseClient API - bool RequestAPI(APIDescriptor_t *pAPI); - const char* GetInfo(); - - CameraSynapseClient() { } - virtual ~CameraSynapseClient() { } -}; - -CSynapseServer* g_pSynapseServer = NULL; -CameraSynapseClient 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, "camera", sizeof(_QERPlugToolbarTable)); - g_SynapseClient.AddAPI(PLUGIN_MAJOR, "camera", sizeof(_QERPluginTable)); - - g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); - g_SynapseClient.AddAPI(UI_MAJOR, NULL, sizeof(_QERUITable), SYN_REQUIRE, &g_UITable); - g_SynapseClient.AddAPI(QGL_MAJOR, NULL, sizeof(_QERQglTable), SYN_REQUIRE, &g_QglTable); - g_SynapseClient.AddAPI(CAMERA_MAJOR, NULL, sizeof(_QERCameraTable), SYN_REQUIRE, &g_CameraTable); - - return &g_SynapseClient; -} - -bool CameraSynapseClient::RequestAPI(APIDescriptor_t *pAPI) -{ - if (!strcmp(pAPI->major_name, TOOLBAR_MAJOR)) - { - _QERPlugToolbarTable* pTable= static_cast<_QERPlugToolbarTable*>(pAPI->mpTable); - - pTable->m_pfnToolbarButtonCount = &ToolbarButtonCount; - pTable->m_pfnGetToolbarButton = &GetToolbarButton; - return true; - } - else 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; - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -#include "version.h" - -const char* CameraSynapseClient::GetInfo() -{ - return "Camera plugin v1.0 - Arnout van Meer - built " __DATE__ " " RADIANT_VERSION; -} - - - -// -// CCamera -// -CCamera *AllocCam() { - if( !firstFreeCam ) - return( NULL ); - - CCamera *cam = firstFreeCam; - firstFreeCam = firstFreeCam->GetNext(); - cam->Init(); - if( firstCam ) { - cam->SetNext( firstCam ); - firstCam->SetPrev( cam ); - } - firstCam = cam; - - return( cam ); -} - -void FreeCam( CCamera *cam ) { - if( cam->GetPrev() ) { - if( cam->GetNext() ) { - cam->GetPrev()->SetNext( cam->GetNext() ); - cam->GetNext()->SetPrev( cam->GetPrev() ); - } else { - cam->GetPrev()->SetNext( NULL ); - } - } else if( cam->GetNext() ) { - cam->GetNext()->SetPrev( NULL ); - firstCam = cam->GetNext(); - } else { - firstCam = NULL; - } - - cam->GetCam()->clear(); - cam->Init(); - - if( firstFreeCam ) { - cam->SetNext( firstFreeCam ); - } - firstFreeCam = cam; -} - -void SetCurrentCam( CCamera *cam ) { - currentCam = cam; -} - -CCamera *GetCurrentCam() { - return( currentCam ); -} +/* +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 +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#include "camera.h" + +// Render view +CRenderer *Renderer = NULL; + +// Interaction +CListener *Listener = NULL; + +// plugin name +static const char *PLUGIN_NAME = "Camera"; + +// commands in the menu +static const char *PLUGIN_COMMANDS = "About...,-,Load Camera...,-,Preview Camera,-,Camera Inspector...,-,New Spline Camera,New Interpolated Camera,New Fixed Camera"; + +// globals +GtkWidget *g_pRadiantWnd = NULL; +GtkWidget *g_pCameraInspectorWnd = NULL; +CCamera *firstCam = NULL; // double linked list +CCamera *firstFreeCam = NULL; // single linked list +CCamera *currentCam = NULL; // single item +bool g_bEditOn = false; +int g_iEditMode = 0; // 0: editting points 1: adding points +int g_iActiveTarget = -1; +int g_iPreviewRunning = 0; // 0: no preview 1: start preview 2: preview in progress + +static const char *PLUGIN_ABOUT = "Camera v1.0 for GtkRadiant\n" + "by Arnout van Meer (rr2do2@splashdamage.com)\n\n" + "This product contains software technology\n" + "from id Software, Inc. ('id Technology').\n" + "id Technology (c) 2001, 2002 id Software, Inc."; + + +#include "iplugin.h" + +const char* QERPlug_Init(void* hApp, void* pMainWidget) +{ + g_pRadiantWnd = (GtkWidget*)pMainWidget; + + // initialize cams + for( int i = 0; i < MAX_CAMERAS; i++ ) { + if( i == 0 ) { + firstFreeCam = new CCamera( i ); + firstCam = firstFreeCam; + } else { + firstCam->SetNext( new CCamera( i ) ); + firstCam = firstCam->GetNext(); + } + } + firstCam = NULL; + + if( !Renderer ) + { + Renderer = new CRenderer; + } + + if( g_pCameraInspectorWnd == NULL ) + g_pCameraInspectorWnd = CreateCameraInspectorDialog(); + + InitIglToQgl(&g_QglTable); + + GetFileTypeRegistry()->addType("camera", filetype_t("Camera file", "*.camera")); + + return "Camera for GtkRadiant"; +} + +const char* QERPlug_GetName() +{ + return PLUGIN_NAME; +} + +const char* QERPlug_GetCommandList() +{ + return PLUGIN_COMMANDS; +} + +void QERPlug_Dispatch (const char* p, float* vMin, float* vMax, bool bSingleBrush) +{ + if( !strcmp( p, "New Fixed Camera" ) ) + DoNewFixedCamera(); + else if( !strcmp( p, "New Interpolated Camera" ) ) + DoNewInterpolatedCamera(); + else if( !strcmp( p, "New Spline Camera" ) ) + DoNewSplineCamera(); + else if( !strcmp( p, "Camera Inspector..." ) ) + DoCameraInspector(); + else if( !strcmp( p, "Preview Camera" ) ) + DoPreviewCamera(); + else if( !strcmp( p, "Load Camera..." ) ) + DoLoadCamera(); + else if( !strcmp( p, "About..." ) ) + g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, PLUGIN_ABOUT, "About", MB_OK, NULL ); +} + + +// toolbar + +#include "itoolbar.h" + +unsigned int ToolbarButtonCount() +{ + return 1; +} + +class CameraInspectorButton : public IToolbarButton +{ +public: + virtual const char* getImage() const + { + return "camera_insp.bmp"; + } + virtual const char* getText() const + { + return "Inspector"; + } + virtual const char* getTooltip() const + { + return "Camera Inspector"; + } + virtual void activate() const + { + DoCameraInspector(); + } + virtual EType getType() const + { + return eButton; + } +}; + +CameraInspectorButton g_camerainspectorbutton; + +const IToolbarButton* GetToolbarButton(unsigned int index) +{ + return &g_camerainspectorbutton; +} + + +_QERFuncTable_1 g_FuncTable; +_QERQglTable g_QglTable; +_QERUITable g_UITable; +_QERCameraTable g_CameraTable; + +// ============================================================================= +// SYNAPSE + +#include "synapse.h" + +class CameraSynapseClient : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + + CameraSynapseClient() { } + virtual ~CameraSynapseClient() { } +}; + +CSynapseServer* g_pSynapseServer = NULL; +CameraSynapseClient 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, "camera", sizeof(_QERPlugToolbarTable)); + g_SynapseClient.AddAPI(PLUGIN_MAJOR, "camera", sizeof(_QERPluginTable)); + + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(UI_MAJOR, NULL, sizeof(_QERUITable), SYN_REQUIRE, &g_UITable); + g_SynapseClient.AddAPI(QGL_MAJOR, NULL, sizeof(_QERQglTable), SYN_REQUIRE, &g_QglTable); + g_SynapseClient.AddAPI(CAMERA_MAJOR, NULL, sizeof(_QERCameraTable), SYN_REQUIRE, &g_CameraTable); + + return &g_SynapseClient; +} + +bool CameraSynapseClient::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, TOOLBAR_MAJOR)) + { + _QERPlugToolbarTable* pTable= static_cast<_QERPlugToolbarTable*>(pAPI->mpTable); + + pTable->m_pfnToolbarButtonCount = &ToolbarButtonCount; + pTable->m_pfnGetToolbarButton = &GetToolbarButton; + return true; + } + else 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; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CameraSynapseClient::GetInfo() +{ + return "Camera plugin v1.0 - Arnout van Meer - built " __DATE__ " " RADIANT_VERSION; +} + + + +// +// CCamera +// +CCamera *AllocCam() { + if( !firstFreeCam ) + return( NULL ); + + CCamera *cam = firstFreeCam; + firstFreeCam = firstFreeCam->GetNext(); + cam->Init(); + if( firstCam ) { + cam->SetNext( firstCam ); + firstCam->SetPrev( cam ); + } + firstCam = cam; + + return( cam ); +} + +void FreeCam( CCamera *cam ) { + if( cam->GetPrev() ) { + if( cam->GetNext() ) { + cam->GetPrev()->SetNext( cam->GetNext() ); + cam->GetNext()->SetPrev( cam->GetPrev() ); + } else { + cam->GetPrev()->SetNext( NULL ); + } + } else if( cam->GetNext() ) { + cam->GetNext()->SetPrev( NULL ); + firstCam = cam->GetNext(); + } else { + firstCam = NULL; + } + + cam->GetCam()->clear(); + cam->Init(); + + if( firstFreeCam ) { + cam->SetNext( firstFreeCam ); + } + firstFreeCam = cam; +} + +void SetCurrentCam( CCamera *cam ) { + currentCam = cam; +} + +CCamera *GetCurrentCam() { + return( currentCam ); +} diff --git a/contrib/camera/dialogs.cpp b/contrib/camera/dialogs.cpp index 2e8e5b0e..866afd17 100644 --- a/contrib/camera/dialogs.cpp +++ b/contrib/camera/dialogs.cpp @@ -1,1352 +1,1352 @@ -/* -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 -*/ - -/* -Camera plugin for GtkRadiant -Copyright (C) 2002 Splash Damage Ltd. -*/ - -#include "camera.h" - -static GSList *g_pEditTypeRadio = NULL; -static GtkWidget *g_pEditModeEditRadioButton = NULL; -GtkWidget *g_pEditModeAddRadioButton = NULL; -static GtkWidget *g_pSecondsEntry = NULL; -static GtkWidget *g_pEventsList = NULL; -static GtkLabel *g_pCurrentTime = NULL; -static GtkLabel *g_pTotalTime = NULL; -static GtkAdjustment *g_pTimeLine = NULL; -static GtkWidget *g_pTrackCamera = NULL; -static GtkWidget *g_pCamName = NULL; -static char *g_cNull = '\0'; - -static gint ci_editmode_edit( GtkWidget *widget, gpointer data ) -{ - g_iEditMode = 0; - - return TRUE; -} - -static gint ci_editmode_add( GtkWidget *widget, gpointer data ) -{ - g_iEditMode = 1; - - return TRUE; -} - -/*static gint ci_delete_selected( GtkWidget *widget, gpointer data ) -{ - return TRUE; -} - -static gint ci_select_all( GtkWidget *widget, gpointer data ) -{ - return TRUE; -}*/ - -static gint ci_new( GtkWidget *widget, gpointer data ) -{ - GtkWidget *window, *w, *vbox, *vbox2, *hbox, *frame; //, *name; - GtkWidget *fixed, *interpolated, *spline; - int ret, loop = 1; - GSList *targetTypeRadio = NULL; -// char buf[128]; - - // create the window - window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); - gtk_window_set_title( GTK_WINDOW (window), "New Camera" ); - gtk_signal_connect( GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC( dialog_delete_callback ), NULL ); - gtk_signal_connect( GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL ); - gtk_window_set_transient_for( GTK_WINDOW( window ), GTK_WINDOW( g_pCameraInspectorWnd ) ); - - g_object_set_data (G_OBJECT (window), "loop", &loop); - g_object_set_data (G_OBJECT (window), "ret", &ret); - - gtk_widget_realize (window); - - // fill the window - vbox = gtk_vbox_new( FALSE, 5 ); - gtk_container_add (GTK_CONTAINER (window), vbox); - gtk_widget_show( vbox ); - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - frame = gtk_frame_new( "Type" ); - gtk_box_pack_start( GTK_BOX( hbox ), frame, TRUE, TRUE, 0 ); - gtk_widget_show( frame ); - - vbox2 = gtk_vbox_new( FALSE, 5 ); - gtk_container_add( GTK_CONTAINER( frame ), vbox2 ); - gtk_container_set_border_width( GTK_CONTAINER (vbox2), 5 ); - gtk_widget_show( vbox2 ); - - // -------------------------- // - - fixed = gtk_radio_button_new_with_label( targetTypeRadio, "Fixed" ); - gtk_box_pack_start( GTK_BOX( vbox2 ), fixed, FALSE, FALSE, 3 ); - gtk_widget_show( fixed ); - targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( fixed ) ); - - interpolated = gtk_radio_button_new_with_label( targetTypeRadio, "Interpolated" ); - gtk_box_pack_start( GTK_BOX( vbox2 ), interpolated, FALSE, FALSE, 3 ); - gtk_widget_show( interpolated ); - targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( interpolated ) ); - - spline = gtk_radio_button_new_with_label( targetTypeRadio, "Spline" ); - gtk_box_pack_start( GTK_BOX( vbox2 ), spline, FALSE, FALSE, 3 ); - gtk_widget_show( spline ); - targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( spline ) ); - - // -------------------------- // - - w = gtk_hseparator_new (); - gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); - gtk_widget_show (w); - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - w = gtk_button_new_with_label ("Ok"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_show (w); - - GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); - gtk_widget_grab_default( w ); - - w = gtk_button_new_with_label ("Cancel"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_show (w); - ret = IDCANCEL; - - // -------------------------- // - - gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); - gtk_widget_show (window); - gtk_grab_add (window); - - bool dialogError = TRUE; - while (dialogError) { - loop = 1; - while (loop) - gtk_main_iteration (); - - dialogError = FALSE; - - if( ret == IDOK ) { - if( gtk_toggle_button_get_active( (GtkToggleButton*)fixed ) ) - DoNewFixedCamera(); - else if( gtk_toggle_button_get_active( (GtkToggleButton*)interpolated ) ) - DoNewInterpolatedCamera(); - else if( gtk_toggle_button_get_active( (GtkToggleButton*)spline ) ) - DoNewSplineCamera(); - } - } - - gtk_grab_remove (window); - gtk_widget_destroy (window); - - return TRUE; -} - -static gint ci_load( GtkWidget *widget, gpointer data ) -{ - DoLoadCamera(); - - return TRUE; -} - -static gint ci_save( GtkWidget *widget, gpointer data ) -{ - DoSaveCamera(); - - return TRUE; -} - -static gint ci_unload( GtkWidget *widget, gpointer data ) -{ - DoUnloadCamera(); - - return TRUE; -} - -static gint ci_apply( GtkWidget *widget, gpointer data ) -{ - if( GetCurrentCam() ) { - const char *str; - char buf[128]; - bool build = false; - - str = gtk_entry_get_text( GTK_ENTRY(g_pCamName) ); - - if( str ) { - GetCurrentCam()->GetCam()->setName( str ); - build = true; - } - - str = gtk_entry_get_text( GTK_ENTRY(g_pSecondsEntry) ); - - if( str ) { - GetCurrentCam()->GetCam()->setBaseTime( atof( str ) ); - build = true; - } - - if( build ) { - GetCurrentCam()->GetCam()->buildCamera(); - } - - sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getBaseTime() ); - gtk_entry_set_text( GTK_ENTRY(g_pSecondsEntry), buf ); - - sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getTotalTime() ); - gtk_label_set_text( g_pCurrentTime, "0.00" ); - gtk_label_set_text( g_pTotalTime, buf ); - - gtk_adjustment_set_value( g_pTimeLine, 0.f ); - g_pTimeLine->upper = GetCurrentCam()->GetCam()->getTotalTime() * 1000; - - GetCurrentCam()->HasBeenModified(); - } - - return TRUE; -} - -static gint ci_preview( GtkWidget *widget, gpointer data ) -{ - if( GetCurrentCam() ) { - g_iPreviewRunning = 1; - g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); - } - - return TRUE; -} - -static gint ci_expose( GtkWidget *widget, gpointer data ) -{ - // start edit mode - DoStartEdit( GetCurrentCam() ); - - return FALSE; -} - -static gint ci_close( GtkWidget *widget, gpointer data ) -{ - gtk_widget_hide( g_pCameraInspectorWnd ); - - // exit edit mode - DoStopEdit(); - - return TRUE; -} - -static GtkWidget *g_pPathListCombo = NULL; -static GtkLabel *g_pPathType = NULL; - -static void RefreshPathListCombo( void ) -{ - if( !g_pPathListCombo ) - return; - - GList *combo_list = (GList*)NULL; - - if( GetCurrentCam() ) { - combo_list = g_list_append( combo_list, (void *)GetCurrentCam()->GetCam()->getPositionObj()->getName() ); - for( int i = 0; i < GetCurrentCam()->GetCam()->numTargets(); i++ ) { - combo_list = g_list_append( combo_list, (void *)GetCurrentCam()->GetCam()->getActiveTarget( i )->getName() ); - } - } else { - // add one empty string make gtk be quiet - combo_list = g_list_append( combo_list, (gpointer)g_cNull ); - } - - gtk_combo_set_popdown_strings( GTK_COMBO( g_pPathListCombo ), combo_list ); - g_list_free( combo_list ); -} - -static gint ci_pathlist_changed( GtkWidget *widget, gpointer data ) -{ - const char *str = gtk_entry_get_text( GTK_ENTRY(widget) ); - - if( !str || !GetCurrentCam() ) - return TRUE; - - int i; - for( i = 0; i < GetCurrentCam()->GetCam()->numTargets(); i++ ) { - if( !strcmp( str, GetCurrentCam()->GetCam()->getActiveTarget( i )->getName() ) ) - break; - } - - if( i >= 0 && i < GetCurrentCam()->GetCam()->numTargets() ) { - GetCurrentCam()->GetCam()->setActiveTarget( i ); - - g_iActiveTarget = i; - if( g_pPathType ) - gtk_label_set_text( g_pPathType, GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->typeStr() ); - } else { - g_iActiveTarget = -1; - if( g_pPathType ) - gtk_label_set_text( g_pPathType, GetCurrentCam()->GetCam()->getPositionObj()->typeStr() ); - } - - // start edit mode - if( g_pCameraInspectorWnd && GTK_WIDGET_VISIBLE( g_pCameraInspectorWnd ) ) - DoStartEdit( GetCurrentCam() ); - - return TRUE; -} - -static void RefreshEventList( void ) -{ - int i; - char buf[128]; - - // Clear events list - gtk_clist_freeze( GTK_CLIST(g_pEventsList) ); - gtk_clist_clear( GTK_CLIST(g_pEventsList) ); - - if( GetCurrentCam() ) { - // Fill events list - for( i = 0; i < GetCurrentCam()->GetCam()->numEvents(); i++ ) { - char rowbuf[3][128], *row[3]; - // FIXME: sort by time? - sprintf( rowbuf[0], "%li", GetCurrentCam()->GetCam()->getEvent(i)->getTime() ); row[0] = rowbuf[0]; - strncpy( rowbuf[1], GetCurrentCam()->GetCam()->getEvent(i)->typeStr(), sizeof(rowbuf[0]) ); row[1] = rowbuf[1]; - strncpy( rowbuf[2], GetCurrentCam()->GetCam()->getEvent(i)->getParam(), sizeof(rowbuf[1]) ); row[2] = rowbuf[2]; - gtk_clist_append( GTK_CLIST(g_pEventsList), row ); - } - - // Total duration might have changed - sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getTotalTime() ); - gtk_label_set_text( g_pCurrentTime, "0.00" ); - gtk_label_set_text( g_pTotalTime, buf ); - - gtk_adjustment_set_value( g_pTimeLine, 0.f ); - g_pTimeLine->upper = ( GetCurrentCam()->GetCam()->getTotalTime() * 1000 ); - } - - gtk_clist_thaw( GTK_CLIST(g_pEventsList) ); -} - -static gint ci_rename( GtkWidget *widget, gpointer data ) -{ - GtkWidget *window, *w, *vbox, *hbox, *name; - int ret, loop = 1; - - if( !GetCurrentCam() ) - return TRUE; - - // create the window - window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); - gtk_window_set_title( GTK_WINDOW (window), "Rename Path" ); - gtk_signal_connect( GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC( dialog_delete_callback ), NULL ); - gtk_signal_connect( GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL ); - gtk_window_set_transient_for( GTK_WINDOW( window ), GTK_WINDOW( g_pCameraInspectorWnd ) ); - - g_object_set_data (G_OBJECT (window), "loop", &loop); - g_object_set_data (G_OBJECT (window), "ret", &ret); - - gtk_widget_realize ( window ); - - // fill the window - vbox = gtk_vbox_new( FALSE, 5 ); - gtk_container_add (GTK_CONTAINER (window), vbox); - gtk_widget_show( vbox ); - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - w = gtk_label_new( "Name:" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - - name = gtk_entry_new(); - gtk_box_pack_start( GTK_BOX( hbox ), name, FALSE, FALSE, 0 ); - gtk_widget_show( name ); - - if( g_iActiveTarget < 0 ) - gtk_entry_set_text( GTK_ENTRY(name), GetCurrentCam()->GetCam()->getPositionObj()->getName() ); - else - gtk_entry_set_text( GTK_ENTRY(name), GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->getName() ); - - // -------------------------- // - - w = gtk_hseparator_new (); - gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); - gtk_widget_show (w); - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - w = gtk_button_new_with_label ("Ok"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_show (w); - - GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); - gtk_widget_grab_default( w ); - - w = gtk_button_new_with_label ("Cancel"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_show (w); - ret = IDCANCEL; - - // -------------------------- // - - gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); - gtk_widget_show (window); - gtk_grab_add (window); - - bool dialogError = TRUE; - while (dialogError) { - loop = 1; - while (loop) - gtk_main_iteration (); - - dialogError = FALSE; - - if( ret == IDOK ) { - const char *str = gtk_entry_get_text( GTK_ENTRY(name) ); - - if( str && str[0] ) { - // Update the path - if( g_iActiveTarget < 0 ) - GetCurrentCam()->GetCam()->getPositionObj()->setName( str ); - else - GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->setName( str ); - - GetCurrentCam()->GetCam()->buildCamera(); - - // Rebuild the listbox - RefreshPathListCombo(); - } else { - dialogError = TRUE; - } - } - } - - gtk_grab_remove (window); - gtk_widget_destroy (window); - - return TRUE; -} - -static gint ci_add_target( GtkWidget *widget, gpointer data ) -{ - GtkWidget *window, *w, *vbox, *vbox2, *hbox, *frame, *name; - GtkWidget *fixed, *interpolated, *spline; - int ret, loop = 1; - GSList *targetTypeRadio = NULL; - char buf[128]; - - if( !GetCurrentCam() ) - return TRUE; - - // create the window - window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); - gtk_window_set_title( GTK_WINDOW (window), "Add Target" ); - gtk_signal_connect( GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC( dialog_delete_callback ), NULL ); - gtk_signal_connect( GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL ); - gtk_window_set_transient_for( GTK_WINDOW( window ), GTK_WINDOW( g_pCameraInspectorWnd ) ); - - g_object_set_data (G_OBJECT (window), "loop", &loop); - g_object_set_data (G_OBJECT (window), "ret", &ret); - - gtk_widget_realize (window); - - // fill the window - vbox = gtk_vbox_new( FALSE, 5 ); - gtk_container_add (GTK_CONTAINER (window), vbox); - gtk_widget_show( vbox ); - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - w = gtk_label_new( "Name:" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - - name = gtk_entry_new(); - gtk_box_pack_start( GTK_BOX( hbox ), name, TRUE, TRUE, 0 ); - gtk_widget_show( name ); - - sprintf( buf, "target%i", GetCurrentCam()->GetCam()->numTargets() + 1 ); - gtk_entry_set_text( GTK_ENTRY(name), buf ); - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - frame = gtk_frame_new( "Type" ); - gtk_box_pack_start( GTK_BOX( hbox ), frame, TRUE, TRUE, 0 ); - gtk_widget_show( frame ); - - vbox2 = gtk_vbox_new( FALSE, 5 ); - gtk_container_add( GTK_CONTAINER( frame ), vbox2 ); - gtk_container_set_border_width( GTK_CONTAINER (vbox2), 5 ); - gtk_widget_show( vbox2 ); - - // -------------------------- // - - fixed = gtk_radio_button_new_with_label( targetTypeRadio, "Fixed" ); - gtk_box_pack_start( GTK_BOX( vbox2 ), fixed, FALSE, FALSE, 3 ); - gtk_widget_show( fixed ); - targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( fixed ) ); - - interpolated = gtk_radio_button_new_with_label( targetTypeRadio, "Interpolated" ); - gtk_box_pack_start( GTK_BOX( vbox2 ), interpolated, FALSE, FALSE, 3 ); - gtk_widget_show( interpolated ); - targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( interpolated ) ); - - spline = gtk_radio_button_new_with_label( targetTypeRadio, "Spline" ); - gtk_box_pack_start( GTK_BOX( vbox2 ), spline, FALSE, FALSE, 3 ); - gtk_widget_show( spline ); - targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( spline ) ); - - // -------------------------- // - - w = gtk_hseparator_new (); - gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); - gtk_widget_show (w); - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - w = gtk_button_new_with_label ("Ok"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_show (w); - - GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); - gtk_widget_grab_default( w ); - - w = gtk_button_new_with_label ("Cancel"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_show (w); - ret = IDCANCEL; - - // -------------------------- // - - gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); - gtk_widget_show (window); - gtk_grab_add (window); - - bool dialogError = TRUE; - while (dialogError) { - loop = 1; - while (loop) - gtk_main_iteration (); - - dialogError = FALSE; - - if( ret == IDOK ) { - const char *str = gtk_entry_get_text( GTK_ENTRY(name) ); - - if( str && str[0] ) { - int type; - GList *li; - - if( gtk_toggle_button_get_active( (GtkToggleButton*)fixed ) ) - type = 0; - else if( gtk_toggle_button_get_active( (GtkToggleButton*)interpolated ) ) - type = 1; - else if( gtk_toggle_button_get_active( (GtkToggleButton*)spline ) ) - type = 2; - - // Add the target - GetCurrentCam()->GetCam()->addTarget( str, static_cast(type) ); - - // Rebuild the listbox - RefreshPathListCombo(); - - // Select the last item in the listbox - li = g_list_last( GTK_LIST(GTK_COMBO(g_pPathListCombo)->list)->children ); - gtk_list_select_child( GTK_LIST(GTK_COMBO(g_pPathListCombo)->list), GTK_WIDGET (li->data) ); - - // If this was the first one, refresh the event list - if( GetCurrentCam()->GetCam()->numTargets() == 1 ) { - RefreshEventList(); - } - - // Go to editmode Add - gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(g_pEditModeAddRadioButton), TRUE ); - - } else { - dialogError = TRUE; - } - } - } - - gtk_grab_remove (window); - gtk_widget_destroy (window); - - return TRUE; -} - -static GtkWidget *g_pCamListCombo = NULL; -static GtkLabel *g_pCamType = NULL; - -void RefreshCamListCombo( void ) -{ - if( !g_pCamListCombo ) - return; - - GList *combo_list = (GList*)NULL; - CCamera *combo_cam = firstCam; - if( combo_cam ) { - while( combo_cam ) { - //combo_list = g_list_append( combo_list, (void *)combo_cam->GetCam()->getName() ); - //if( combo_cam->HasBeenSaved() ) { - combo_list = g_list_append( combo_list, (void *)combo_cam->GetFileName() ); - /*} else { - char buf[128]; - sprintf( buf, "Unsaved Camera %i", combo_cam->GetCamNum() ); - combo_list = g_list_append( combo_list, (void *)buf ); - - //combo_list = g_list_append( combo_list, (void *)combo_cam->GetCam()->getName() ); // FIXME: this requires camera.dll to create unique names for new cams - }*/ - combo_cam = combo_cam->GetNext(); - } - }else { - // add one empty string make gtk be quiet - combo_list = g_list_append( combo_list, (gpointer)g_cNull ); - } - gtk_combo_set_popdown_strings( GTK_COMBO( g_pCamListCombo ), combo_list ); - g_list_free( combo_list ); - - // select our current entry in the list - if( GetCurrentCam() ) { - // stop editing on the current cam - //GetCurrentCam()->GetCam()->stopEdit(); // FIXME: this crashed on creating new cameras, why is it here? - - GList *li = GTK_LIST( GTK_COMBO(g_pCamListCombo)->list)->children; - combo_cam = firstCam; - while( li && combo_cam ) { - if( combo_cam == GetCurrentCam() ) { - gtk_list_select_child( GTK_LIST( GTK_COMBO(g_pCamListCombo)->list ), GTK_WIDGET( li->data ) ); - break; - } - li = li->next; - combo_cam = combo_cam->GetNext(); - } - } - - RefreshPathListCombo(); -} - -static gint ci_camlist_changed( GtkWidget *widget, gpointer data ) -{ - const char *str = gtk_entry_get_text( GTK_ENTRY(widget) ); - - CCamera *combo_cam = firstCam; - while( str && combo_cam ) { - //if( !strcmp( str, combo_cam->GetCam()->getName() ) ) - //if( combo_cam->HasBeenSaved() ) { - if( !strcmp( str, combo_cam->GetFileName() ) ) - break; - /*} else { - char buf[128]; - sprintf( buf, "Unsaved Camera %i", combo_cam->GetCamNum() ); - if( !strcmp( str, buf ) ) - //if( !strcmp( str, combo_cam->GetCam()->getName() ) ) - break; - }*/ - - combo_cam = combo_cam->GetNext(); - } - - SetCurrentCam( combo_cam ); - - if( g_pCamType ) { - if( GetCurrentCam() ) { - // Fill in our widgets fields for this camera - char buf[128]; - - // Set Name - gtk_entry_set_text( GTK_ENTRY(g_pCamName), GetCurrentCam()->GetCam()->getName() ); - - // Set type - gtk_label_set_text( g_pCamType, GetCurrentCam()->GetCam()->getPositionObj()->typeStr() ); - - // Set duration - sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getBaseTime() ); - gtk_entry_set_text( GTK_ENTRY(g_pSecondsEntry), buf ); - - sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getTotalTime() ); - gtk_label_set_text( g_pCurrentTime, "0.00" ); - gtk_label_set_text( g_pTotalTime, buf ); - - gtk_adjustment_set_value( g_pTimeLine, 0.f ); - g_pTimeLine->upper = GetCurrentCam()->GetCam()->getTotalTime() * 1000; - } else { - // Set Name - gtk_entry_set_text( GTK_ENTRY(g_pCamName), "" ); - - // Set type - gtk_label_set_text( g_pCamType, "" ); - - // Set duration - gtk_entry_set_text( GTK_ENTRY(g_pSecondsEntry), "30.00" ); - - gtk_label_set_text( g_pCurrentTime, "0.00" ); - gtk_label_set_text( g_pTotalTime, "30.00" ); - - gtk_adjustment_set_value( g_pTimeLine, 0.f ); - g_pTimeLine->upper = 30000; - } - - // Refresh event list - RefreshEventList(); - } - - RefreshPathListCombo(); - - // start edit mode - g_iActiveTarget = -1; - if( g_pCameraInspectorWnd && GTK_WIDGET_VISIBLE( g_pCameraInspectorWnd ) ) - DoStartEdit( GetCurrentCam() ); - - return TRUE; -} - -enum camEventType { - EVENT_NA = 0x00, - EVENT_WAIT, // - EVENT_TARGETWAIT, // - EVENT_SPEED, // - EVENT_TARGET, // char(name) - EVENT_SNAPTARGET, // - EVENT_FOV, // int(time), int(targetfov) - EVENT_CMD, // - EVENT_TRIGGER, // - EVENT_STOP, // - EVENT_CAMERA, // - EVENT_FADEOUT, // int(time) - EVENT_FADEIN, // int(time) - EVENT_FEATHER, // - EVENT_COUNT -}; - -// { requires parameters, enabled } -const bool camEventFlags[][2] = { - { false, false }, - { false, true }, - { false, false }, - { false, false }, - { true, true }, - { false, false }, - { true, true }, - { false, false }, - { false, false }, - { false, true }, - { true, true }, - { true, true }, - { true, true }, - { false, true }, -}; - -const char *camEventStr[] = { - "n/a", - "Wait", - "Target wait", - "Speed", - "Change Target ", - "Snap Target", - "FOV ", - "Run Script", - "Trigger", - "Stop", - "Change to Camera (or ", - "Fade Out ", - "Fade In ", - "Feather" -}; - -static gint ci_add( GtkWidget *widget, gpointer data ) -{ - GtkWidget *window, *w, *vbox, *vbox2, *hbox, *frame, *parameters; - GtkWidget *eventWidget[EVENT_COUNT]; - int i, ret, loop = 1; - GSList *eventTypeRadio = NULL; -// char buf[128]; - - if( !GetCurrentCam() ) - return TRUE; - - // create the window - window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); - gtk_window_set_title( GTK_WINDOW (window), "Add Event" ); - gtk_signal_connect( GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC( dialog_delete_callback ), NULL ); - gtk_signal_connect( GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL ); - gtk_window_set_transient_for( GTK_WINDOW( window ), GTK_WINDOW( g_pCameraInspectorWnd ) ); - - g_object_set_data (G_OBJECT (window), "loop", &loop); - g_object_set_data (G_OBJECT (window), "ret", &ret); - - gtk_widget_realize (window); - - // fill the window - vbox = gtk_vbox_new( FALSE, 5 ); - gtk_container_add (GTK_CONTAINER (window), vbox); - gtk_widget_show( vbox ); - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - frame = gtk_frame_new( "Type" ); - gtk_box_pack_start( GTK_BOX( hbox ), frame, TRUE, TRUE, 0 ); - gtk_widget_show( frame ); - - vbox2 = gtk_vbox_new( FALSE, 5 ); - gtk_container_add( GTK_CONTAINER( frame ), vbox2 ); - gtk_container_set_border_width( GTK_CONTAINER (vbox2), 5 ); - gtk_widget_show( vbox2 ); - - // -------------------------- // - - for( i = 1; i < EVENT_COUNT; i++ ) { - eventWidget[i] = gtk_radio_button_new_with_label( eventTypeRadio, camEventStr[i] ); - gtk_box_pack_start( GTK_BOX( vbox2 ), eventWidget[i], FALSE, FALSE, 3 ); - gtk_widget_show( eventWidget[i] ); - eventTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( eventWidget[i] ) ); - if( camEventFlags[i][1] == false ) - gtk_widget_set_sensitive (eventWidget[i], FALSE); - } - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - w = gtk_label_new( "Parameters:" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - - parameters = gtk_entry_new(); - gtk_box_pack_start( GTK_BOX( hbox ), parameters, TRUE, TRUE, 0 ); - gtk_widget_show( parameters ); - - // -------------------------- // - - w = gtk_hseparator_new (); - gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); - gtk_widget_show (w); - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - w = gtk_button_new_with_label ("Ok"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_show (w); - - GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); - gtk_widget_grab_default( w ); - - w = gtk_button_new_with_label ("Cancel"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_show (w); - ret = IDCANCEL; - - // -------------------------- // - - gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); - gtk_widget_show (window); - gtk_grab_add (window); - - bool dialogError = TRUE; - while (dialogError) { - loop = 1; - while (loop) - gtk_main_iteration (); - - dialogError = FALSE; - - if( ret == IDOK ) { - const char *str = gtk_entry_get_text( GTK_ENTRY(parameters) ); - - if( !camEventFlags[i][0] || ( str && str[0] ) ) { - int type = 0; -// GList *li; - - for( type = 1; type < EVENT_COUNT; type++ ) { - if( gtk_toggle_button_get_active( (GtkToggleButton*)eventWidget[type] ) ) - break; - } - - // Add the event - GetCurrentCam()->GetCam()->addEvent( static_cast(type), str, (long)(g_pTimeLine->value) ); - - // Refresh event list - RefreshEventList(); - } else { - dialogError = TRUE; - } - } - } - - gtk_grab_remove (window); - gtk_widget_destroy (window); - - return TRUE; -} - -static gint ci_del( GtkWidget *widget, gpointer data ) -{ - // TODO: add support to splines lib - if( GetCurrentCam() && GTK_CLIST(g_pEventsList)->focus_row >= 0 ) { - GetCurrentCam()->GetCam()->removeEvent( GTK_CLIST(g_pEventsList)->focus_row ); - // Refresh event list - RefreshEventList(); - } - - return TRUE; -} - -static gint ci_timeline_changed( GtkAdjustment *adjustment ) -{ - char buf[128]; - - sprintf( buf, "%.2f", adjustment->value / 1000.f ); - gtk_label_set_text( g_pCurrentTime, buf ); - - // FIXME: this will never work completely perfect. Startcamera calls buildcamera, which sets all events to 'nottriggered'. - // So if you have a wait at the end of the path, this will go to nontriggered immediately when you go over it and the camera - // will have no idea where on the track it should be. - if( GetCurrentCam() && gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(g_pTrackCamera) ) ) { - float fov; - vec3_t origin = { 0.0f, 0.0f, 0.0f }, dir = { 0.0f, 0.0f, 0.0f}, angles; - - GetCurrentCam()->GetCam()->startCamera( 0 ); - - GetCurrentCam()->GetCam()->getCameraInfo( (long)(adjustment->value), &origin[0], &dir[0], &fov ); - VectorSet( angles, asin (dir[2])*180/3.14159, atan2 (dir[1], dir[0])*180/3.14159, 0 ); - g_CameraTable.m_pfnSetCamera( origin, angles ); - } - - return TRUE; -} - -GtkWidget *CreateCameraInspectorDialog( void ) -{ - GtkWidget *window, *w, *vbox, *hbox, *table, *frame; - - // create the window - window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); - gtk_window_set_title( GTK_WINDOW (window), "Camera Inspector" ); - gtk_signal_connect( GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC( ci_close ), NULL ); - gtk_signal_connect( GTK_OBJECT (window), "expose_event", GTK_SIGNAL_FUNC( ci_expose ), NULL ); - // gtk_signal_connect( GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL ); - gtk_window_set_transient_for( GTK_WINDOW( window ), GTK_WINDOW( g_pRadiantWnd ) ); - - // don't use show, as you don't want to have it displayed on startup ;-) - gtk_widget_realize( window ); - - // fill the window - - // the table - // -------------------------- // - - table = gtk_table_new( 3, 2, FALSE ); - gtk_widget_show( table ); - gtk_container_add( GTK_CONTAINER( window ), table ); - gtk_container_set_border_width( GTK_CONTAINER( table ), 5 ); - gtk_table_set_row_spacings( GTK_TABLE( table ), 5 ); - gtk_table_set_col_spacings( GTK_TABLE( table ), 5 ); - - // the properties column - // -------------------------- // - - vbox = gtk_vbox_new( FALSE, 5 ); - gtk_widget_show( vbox ); - gtk_table_attach( GTK_TABLE( table ), vbox, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0 ); - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - w = gtk_label_new( "File:" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - - g_pCamListCombo = gtk_combo_new(); - gtk_box_pack_start (GTK_BOX( hbox ), g_pCamListCombo, TRUE, TRUE, 0); - gtk_widget_show( g_pCamListCombo ); - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - w = gtk_label_new( "Name:" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - - g_pCamName = gtk_entry_new(); - gtk_box_pack_start( GTK_BOX( hbox ), g_pCamName, FALSE, FALSE, 0 ); - gtk_widget_show( g_pCamName ); - - w = gtk_label_new( "Type: " ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - - w = gtk_label_new( "" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - g_pCamType = GTK_LABEL( w ); - - RefreshCamListCombo(); - - gtk_entry_set_editable( GTK_ENTRY( GTK_COMBO(g_pCamListCombo)->entry ), FALSE ); - gtk_signal_connect( GTK_OBJECT(GTK_COMBO(g_pCamListCombo)->entry), "changed", GTK_SIGNAL_FUNC( ci_camlist_changed ), NULL ); - - // -------------------------- // - - frame = gtk_frame_new( "Path and Target editing" ); - gtk_widget_show( frame ); - gtk_table_attach( GTK_TABLE( table ), frame, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0 ); - - vbox = gtk_vbox_new( FALSE, 5 ); - gtk_container_add( GTK_CONTAINER( frame ), vbox ); - gtk_container_set_border_width( GTK_CONTAINER (vbox), 5 ); - gtk_widget_show( vbox ); - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - w = gtk_label_new( "Edit:" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - - g_pPathListCombo = gtk_combo_new(); - gtk_box_pack_start (GTK_BOX( hbox ), g_pPathListCombo, TRUE, TRUE, 0); - gtk_widget_show( g_pPathListCombo ); - - RefreshPathListCombo(); - - gtk_entry_set_editable( GTK_ENTRY( GTK_COMBO(g_pPathListCombo)->entry ), FALSE ); - gtk_signal_connect( GTK_OBJECT(GTK_COMBO(g_pPathListCombo)->entry), "changed", GTK_SIGNAL_FUNC( ci_pathlist_changed ), NULL ); - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - g_pEditModeEditRadioButton = gtk_radio_button_new_with_label( g_pEditTypeRadio, "Edit Points" ); - gtk_box_pack_start( GTK_BOX( hbox ), g_pEditModeEditRadioButton, FALSE, FALSE, 3 ); - gtk_widget_show( g_pEditModeEditRadioButton ); - g_pEditTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( g_pEditModeEditRadioButton ) ); - - gtk_signal_connect( GTK_OBJECT( g_pEditModeEditRadioButton ), "clicked", GTK_SIGNAL_FUNC( ci_editmode_edit ), NULL ); - - g_pEditModeAddRadioButton = gtk_radio_button_new_with_label( g_pEditTypeRadio, "Add Points" ); - gtk_box_pack_start( GTK_BOX( hbox ), g_pEditModeAddRadioButton, FALSE, FALSE, 3 ); - gtk_widget_show( g_pEditModeAddRadioButton ); - g_pEditTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( g_pEditModeAddRadioButton ) ); - - gtk_signal_connect( GTK_OBJECT( g_pEditModeAddRadioButton ), "clicked", GTK_SIGNAL_FUNC( ci_editmode_add ), NULL ); - - // see if we should use a different default - if( g_iEditMode == 1 ) { - // Go to editmode Add - gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(g_pEditModeAddRadioButton), TRUE ); - } - - w = gtk_label_new( "Type: " ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - - w = gtk_label_new( "" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - g_pPathType = GTK_LABEL( w ); - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - w = gtk_button_new_with_label( "Rename..." ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, TRUE, 0); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_rename ), NULL ); - gtk_widget_show( w ); - - w = gtk_button_new_with_label( "Add Target..." ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, TRUE, 0); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_add_target ), NULL ); - gtk_widget_show( w ); - - // not available in splines library - /*w = gtk_button_new_with_label( "Delete Selected" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, TRUE, 0); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_delete_selected ), NULL ); - gtk_widget_show( w ); - - w = gtk_button_new_with_label( "Select All" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, TRUE, 0); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_select_all ), NULL ); - gtk_widget_show( w );*/ - - // -------------------------- // - - frame = gtk_frame_new( "Time" ); - gtk_widget_show( frame ); - gtk_table_attach( GTK_TABLE( table ), frame, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0 ); - - vbox = gtk_vbox_new( FALSE, 5 ); - gtk_container_add( GTK_CONTAINER( frame ), vbox ); - gtk_container_set_border_width( GTK_CONTAINER (vbox), 5 ); - gtk_widget_show( vbox ); - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - w = gtk_label_new( "Length (seconds):" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - - g_pSecondsEntry = gtk_entry_new(); - gtk_box_pack_start( GTK_BOX( hbox ), g_pSecondsEntry, FALSE, FALSE, 0 ); - gtk_widget_show( g_pSecondsEntry ); - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - w = gtk_label_new( "Current Time: " ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - - w = gtk_label_new( "0.00" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - g_pCurrentTime = GTK_LABEL( w ); - - w = gtk_label_new( " of " ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - - w = gtk_label_new( "0.00" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - g_pTotalTime = GTK_LABEL( w ); - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - g_pTimeLine = GTK_ADJUSTMENT( gtk_adjustment_new( 0, 0, 30000, 100, 250, 0 ) ); - gtk_signal_connect( GTK_OBJECT(g_pTimeLine), "value_changed", GTK_SIGNAL_FUNC( ci_timeline_changed ), NULL ); - w = gtk_hscale_new( g_pTimeLine ); - gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); - gtk_widget_show( w ); - gtk_scale_set_draw_value( GTK_SCALE( w ), FALSE ); - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - g_pTrackCamera = gtk_check_button_new_with_label( "Track Camera" ); - gtk_box_pack_start( GTK_BOX( hbox ), g_pTrackCamera, FALSE, FALSE, 0 ); - gtk_widget_show( g_pTrackCamera ); - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - w = gtk_label_new( "Events:" ); - gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); - gtk_widget_show( w ); - - // -------------------------- // - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); - gtk_widget_show( hbox ); - - w = gtk_scrolled_window_new( NULL, NULL ); - gtk_widget_set_usize( w, 0, 150 ); - gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( w ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); - gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); - gtk_widget_show( w ); - - g_pEventsList = gtk_clist_new( 3 ); - gtk_container_add( GTK_CONTAINER(w), g_pEventsList); - //gtk_signal_connect( GTK_OBJECT(g_pEventsList), "select_row", GTK_SIGNAL_FUNC (proplist_select_row), NULL); - gtk_clist_set_selection_mode( GTK_CLIST(g_pEventsList), GTK_SELECTION_BROWSE ); - gtk_clist_column_titles_hide( GTK_CLIST(g_pEventsList) ); - gtk_clist_set_column_auto_resize( GTK_CLIST(g_pEventsList), 0, TRUE ); - gtk_clist_set_column_auto_resize( GTK_CLIST(g_pEventsList), 1, TRUE ); - gtk_clist_set_column_auto_resize( GTK_CLIST(g_pEventsList), 2, TRUE ); - gtk_widget_show( g_pEventsList ); - - vbox = gtk_vbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( hbox ), vbox, FALSE, FALSE, 0 ); - gtk_widget_show( vbox ); - - w = gtk_button_new_with_label( "Add..." ); - gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_add ), NULL ); - gtk_widget_show( w ); - - w = gtk_button_new_with_label( "Del" ); - gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_del ), NULL ); - gtk_widget_show( w ); - - // -------------------------- // - - /*/ - | - | - | - */ - - // the buttons column - // -------------------------- // - - vbox = gtk_vbox_new( FALSE, 5 ); - gtk_widget_show( vbox ); - gtk_table_attach( GTK_TABLE( table ), vbox, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0 ); - - w = gtk_button_new_with_label( "New..." ); - gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_new ), NULL ); - gtk_widget_show( w ); - - w = gtk_button_new_with_label( "Load..." ); - gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_load ), NULL ); - gtk_widget_show( w ); - - // -------------------------- // - - vbox = gtk_vbox_new( FALSE, 5 ); - gtk_widget_show( vbox ); - gtk_table_attach( GTK_TABLE( table ), vbox, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0 ); - - w = gtk_button_new_with_label( "Save..." ); - gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_save ), NULL ); - gtk_widget_show( w ); - - w = gtk_button_new_with_label( "Unload" ); - gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_unload ), NULL ); - gtk_widget_show( w ); - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, TRUE, TRUE, 0 ); - gtk_widget_show( hbox ); - - w = gtk_button_new_with_label( "Apply" ); - gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_apply ), NULL ); - gtk_widget_show( w ); - - w = gtk_button_new_with_label( "Preview" ); - gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_preview ), NULL ); - gtk_widget_show( w ); - - // -------------------------- // - - vbox = gtk_vbox_new( FALSE, 5 ); - gtk_widget_show( vbox ); - gtk_table_attach( GTK_TABLE( table ), vbox, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0 ); - - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, TRUE, TRUE, 0 ); - gtk_widget_show( hbox ); - - w = gtk_button_new_with_label( "Close" ); - gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); - gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_close ), NULL ); - GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); - gtk_widget_grab_default( w ); - gtk_widget_show( w ); - - // -------------------------- // - - return window; -} +/* +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 +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#include "camera.h" + +static GSList *g_pEditTypeRadio = NULL; +static GtkWidget *g_pEditModeEditRadioButton = NULL; +GtkWidget *g_pEditModeAddRadioButton = NULL; +static GtkWidget *g_pSecondsEntry = NULL; +static GtkWidget *g_pEventsList = NULL; +static GtkLabel *g_pCurrentTime = NULL; +static GtkLabel *g_pTotalTime = NULL; +static GtkAdjustment *g_pTimeLine = NULL; +static GtkWidget *g_pTrackCamera = NULL; +static GtkWidget *g_pCamName = NULL; +static char *g_cNull = '\0'; + +static gint ci_editmode_edit( GtkWidget *widget, gpointer data ) +{ + g_iEditMode = 0; + + return TRUE; +} + +static gint ci_editmode_add( GtkWidget *widget, gpointer data ) +{ + g_iEditMode = 1; + + return TRUE; +} + +/*static gint ci_delete_selected( GtkWidget *widget, gpointer data ) +{ + return TRUE; +} + +static gint ci_select_all( GtkWidget *widget, gpointer data ) +{ + return TRUE; +}*/ + +static gint ci_new( GtkWidget *widget, gpointer data ) +{ + GtkWidget *window, *w, *vbox, *vbox2, *hbox, *frame; //, *name; + GtkWidget *fixed, *interpolated, *spline; + int ret, loop = 1; + GSList *targetTypeRadio = NULL; +// char buf[128]; + + // create the window + window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_title( GTK_WINDOW (window), "New Camera" ); + gtk_signal_connect( GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC( dialog_delete_callback ), NULL ); + gtk_signal_connect( GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL ); + gtk_window_set_transient_for( GTK_WINDOW( window ), GTK_WINDOW( g_pCameraInspectorWnd ) ); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + // fill the window + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show( vbox ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + frame = gtk_frame_new( "Type" ); + gtk_box_pack_start( GTK_BOX( hbox ), frame, TRUE, TRUE, 0 ); + gtk_widget_show( frame ); + + vbox2 = gtk_vbox_new( FALSE, 5 ); + gtk_container_add( GTK_CONTAINER( frame ), vbox2 ); + gtk_container_set_border_width( GTK_CONTAINER (vbox2), 5 ); + gtk_widget_show( vbox2 ); + + // -------------------------- // + + fixed = gtk_radio_button_new_with_label( targetTypeRadio, "Fixed" ); + gtk_box_pack_start( GTK_BOX( vbox2 ), fixed, FALSE, FALSE, 3 ); + gtk_widget_show( fixed ); + targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( fixed ) ); + + interpolated = gtk_radio_button_new_with_label( targetTypeRadio, "Interpolated" ); + gtk_box_pack_start( GTK_BOX( vbox2 ), interpolated, FALSE, FALSE, 3 ); + gtk_widget_show( interpolated ); + targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( interpolated ) ); + + spline = gtk_radio_button_new_with_label( targetTypeRadio, "Spline" ); + gtk_box_pack_start( GTK_BOX( vbox2 ), spline, FALSE, FALSE, 3 ); + gtk_widget_show( spline ); + targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( spline ) ); + + // -------------------------- // + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_show (w); + + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // -------------------------- // + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if( ret == IDOK ) { + if( gtk_toggle_button_get_active( (GtkToggleButton*)fixed ) ) + DoNewFixedCamera(); + else if( gtk_toggle_button_get_active( (GtkToggleButton*)interpolated ) ) + DoNewInterpolatedCamera(); + else if( gtk_toggle_button_get_active( (GtkToggleButton*)spline ) ) + DoNewSplineCamera(); + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return TRUE; +} + +static gint ci_load( GtkWidget *widget, gpointer data ) +{ + DoLoadCamera(); + + return TRUE; +} + +static gint ci_save( GtkWidget *widget, gpointer data ) +{ + DoSaveCamera(); + + return TRUE; +} + +static gint ci_unload( GtkWidget *widget, gpointer data ) +{ + DoUnloadCamera(); + + return TRUE; +} + +static gint ci_apply( GtkWidget *widget, gpointer data ) +{ + if( GetCurrentCam() ) { + const char *str; + char buf[128]; + bool build = false; + + str = gtk_entry_get_text( GTK_ENTRY(g_pCamName) ); + + if( str ) { + GetCurrentCam()->GetCam()->setName( str ); + build = true; + } + + str = gtk_entry_get_text( GTK_ENTRY(g_pSecondsEntry) ); + + if( str ) { + GetCurrentCam()->GetCam()->setBaseTime( atof( str ) ); + build = true; + } + + if( build ) { + GetCurrentCam()->GetCam()->buildCamera(); + } + + sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getBaseTime() ); + gtk_entry_set_text( GTK_ENTRY(g_pSecondsEntry), buf ); + + sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getTotalTime() ); + gtk_label_set_text( g_pCurrentTime, "0.00" ); + gtk_label_set_text( g_pTotalTime, buf ); + + gtk_adjustment_set_value( g_pTimeLine, 0.f ); + g_pTimeLine->upper = GetCurrentCam()->GetCam()->getTotalTime() * 1000; + + GetCurrentCam()->HasBeenModified(); + } + + return TRUE; +} + +static gint ci_preview( GtkWidget *widget, gpointer data ) +{ + if( GetCurrentCam() ) { + g_iPreviewRunning = 1; + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + } + + return TRUE; +} + +static gint ci_expose( GtkWidget *widget, gpointer data ) +{ + // start edit mode + DoStartEdit( GetCurrentCam() ); + + return FALSE; +} + +static gint ci_close( GtkWidget *widget, gpointer data ) +{ + gtk_widget_hide( g_pCameraInspectorWnd ); + + // exit edit mode + DoStopEdit(); + + return TRUE; +} + +static GtkWidget *g_pPathListCombo = NULL; +static GtkLabel *g_pPathType = NULL; + +static void RefreshPathListCombo( void ) +{ + if( !g_pPathListCombo ) + return; + + GList *combo_list = (GList*)NULL; + + if( GetCurrentCam() ) { + combo_list = g_list_append( combo_list, (void *)GetCurrentCam()->GetCam()->getPositionObj()->getName() ); + for( int i = 0; i < GetCurrentCam()->GetCam()->numTargets(); i++ ) { + combo_list = g_list_append( combo_list, (void *)GetCurrentCam()->GetCam()->getActiveTarget( i )->getName() ); + } + } else { + // add one empty string make gtk be quiet + combo_list = g_list_append( combo_list, (gpointer)g_cNull ); + } + + gtk_combo_set_popdown_strings( GTK_COMBO( g_pPathListCombo ), combo_list ); + g_list_free( combo_list ); +} + +static gint ci_pathlist_changed( GtkWidget *widget, gpointer data ) +{ + const char *str = gtk_entry_get_text( GTK_ENTRY(widget) ); + + if( !str || !GetCurrentCam() ) + return TRUE; + + int i; + for( i = 0; i < GetCurrentCam()->GetCam()->numTargets(); i++ ) { + if( !strcmp( str, GetCurrentCam()->GetCam()->getActiveTarget( i )->getName() ) ) + break; + } + + if( i >= 0 && i < GetCurrentCam()->GetCam()->numTargets() ) { + GetCurrentCam()->GetCam()->setActiveTarget( i ); + + g_iActiveTarget = i; + if( g_pPathType ) + gtk_label_set_text( g_pPathType, GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->typeStr() ); + } else { + g_iActiveTarget = -1; + if( g_pPathType ) + gtk_label_set_text( g_pPathType, GetCurrentCam()->GetCam()->getPositionObj()->typeStr() ); + } + + // start edit mode + if( g_pCameraInspectorWnd && GTK_WIDGET_VISIBLE( g_pCameraInspectorWnd ) ) + DoStartEdit( GetCurrentCam() ); + + return TRUE; +} + +static void RefreshEventList( void ) +{ + int i; + char buf[128]; + + // Clear events list + gtk_clist_freeze( GTK_CLIST(g_pEventsList) ); + gtk_clist_clear( GTK_CLIST(g_pEventsList) ); + + if( GetCurrentCam() ) { + // Fill events list + for( i = 0; i < GetCurrentCam()->GetCam()->numEvents(); i++ ) { + char rowbuf[3][128], *row[3]; + // FIXME: sort by time? + sprintf( rowbuf[0], "%li", GetCurrentCam()->GetCam()->getEvent(i)->getTime() ); row[0] = rowbuf[0]; + strncpy( rowbuf[1], GetCurrentCam()->GetCam()->getEvent(i)->typeStr(), sizeof(rowbuf[0]) ); row[1] = rowbuf[1]; + strncpy( rowbuf[2], GetCurrentCam()->GetCam()->getEvent(i)->getParam(), sizeof(rowbuf[1]) ); row[2] = rowbuf[2]; + gtk_clist_append( GTK_CLIST(g_pEventsList), row ); + } + + // Total duration might have changed + sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getTotalTime() ); + gtk_label_set_text( g_pCurrentTime, "0.00" ); + gtk_label_set_text( g_pTotalTime, buf ); + + gtk_adjustment_set_value( g_pTimeLine, 0.f ); + g_pTimeLine->upper = ( GetCurrentCam()->GetCam()->getTotalTime() * 1000 ); + } + + gtk_clist_thaw( GTK_CLIST(g_pEventsList) ); +} + +static gint ci_rename( GtkWidget *widget, gpointer data ) +{ + GtkWidget *window, *w, *vbox, *hbox, *name; + int ret, loop = 1; + + if( !GetCurrentCam() ) + return TRUE; + + // create the window + window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_title( GTK_WINDOW (window), "Rename Path" ); + gtk_signal_connect( GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC( dialog_delete_callback ), NULL ); + gtk_signal_connect( GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL ); + gtk_window_set_transient_for( GTK_WINDOW( window ), GTK_WINDOW( g_pCameraInspectorWnd ) ); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize ( window ); + + // fill the window + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show( vbox ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Name:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + name = gtk_entry_new(); + gtk_box_pack_start( GTK_BOX( hbox ), name, FALSE, FALSE, 0 ); + gtk_widget_show( name ); + + if( g_iActiveTarget < 0 ) + gtk_entry_set_text( GTK_ENTRY(name), GetCurrentCam()->GetCam()->getPositionObj()->getName() ); + else + gtk_entry_set_text( GTK_ENTRY(name), GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->getName() ); + + // -------------------------- // + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_show (w); + + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // -------------------------- // + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if( ret == IDOK ) { + const char *str = gtk_entry_get_text( GTK_ENTRY(name) ); + + if( str && str[0] ) { + // Update the path + if( g_iActiveTarget < 0 ) + GetCurrentCam()->GetCam()->getPositionObj()->setName( str ); + else + GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->setName( str ); + + GetCurrentCam()->GetCam()->buildCamera(); + + // Rebuild the listbox + RefreshPathListCombo(); + } else { + dialogError = TRUE; + } + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return TRUE; +} + +static gint ci_add_target( GtkWidget *widget, gpointer data ) +{ + GtkWidget *window, *w, *vbox, *vbox2, *hbox, *frame, *name; + GtkWidget *fixed, *interpolated, *spline; + int ret, loop = 1; + GSList *targetTypeRadio = NULL; + char buf[128]; + + if( !GetCurrentCam() ) + return TRUE; + + // create the window + window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_title( GTK_WINDOW (window), "Add Target" ); + gtk_signal_connect( GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC( dialog_delete_callback ), NULL ); + gtk_signal_connect( GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL ); + gtk_window_set_transient_for( GTK_WINDOW( window ), GTK_WINDOW( g_pCameraInspectorWnd ) ); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + // fill the window + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show( vbox ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Name:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + name = gtk_entry_new(); + gtk_box_pack_start( GTK_BOX( hbox ), name, TRUE, TRUE, 0 ); + gtk_widget_show( name ); + + sprintf( buf, "target%i", GetCurrentCam()->GetCam()->numTargets() + 1 ); + gtk_entry_set_text( GTK_ENTRY(name), buf ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + frame = gtk_frame_new( "Type" ); + gtk_box_pack_start( GTK_BOX( hbox ), frame, TRUE, TRUE, 0 ); + gtk_widget_show( frame ); + + vbox2 = gtk_vbox_new( FALSE, 5 ); + gtk_container_add( GTK_CONTAINER( frame ), vbox2 ); + gtk_container_set_border_width( GTK_CONTAINER (vbox2), 5 ); + gtk_widget_show( vbox2 ); + + // -------------------------- // + + fixed = gtk_radio_button_new_with_label( targetTypeRadio, "Fixed" ); + gtk_box_pack_start( GTK_BOX( vbox2 ), fixed, FALSE, FALSE, 3 ); + gtk_widget_show( fixed ); + targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( fixed ) ); + + interpolated = gtk_radio_button_new_with_label( targetTypeRadio, "Interpolated" ); + gtk_box_pack_start( GTK_BOX( vbox2 ), interpolated, FALSE, FALSE, 3 ); + gtk_widget_show( interpolated ); + targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( interpolated ) ); + + spline = gtk_radio_button_new_with_label( targetTypeRadio, "Spline" ); + gtk_box_pack_start( GTK_BOX( vbox2 ), spline, FALSE, FALSE, 3 ); + gtk_widget_show( spline ); + targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( spline ) ); + + // -------------------------- // + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_show (w); + + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // -------------------------- // + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if( ret == IDOK ) { + const char *str = gtk_entry_get_text( GTK_ENTRY(name) ); + + if( str && str[0] ) { + int type; + GList *li; + + if( gtk_toggle_button_get_active( (GtkToggleButton*)fixed ) ) + type = 0; + else if( gtk_toggle_button_get_active( (GtkToggleButton*)interpolated ) ) + type = 1; + else if( gtk_toggle_button_get_active( (GtkToggleButton*)spline ) ) + type = 2; + + // Add the target + GetCurrentCam()->GetCam()->addTarget( str, static_cast(type) ); + + // Rebuild the listbox + RefreshPathListCombo(); + + // Select the last item in the listbox + li = g_list_last( GTK_LIST(GTK_COMBO(g_pPathListCombo)->list)->children ); + gtk_list_select_child( GTK_LIST(GTK_COMBO(g_pPathListCombo)->list), GTK_WIDGET (li->data) ); + + // If this was the first one, refresh the event list + if( GetCurrentCam()->GetCam()->numTargets() == 1 ) { + RefreshEventList(); + } + + // Go to editmode Add + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(g_pEditModeAddRadioButton), TRUE ); + + } else { + dialogError = TRUE; + } + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return TRUE; +} + +static GtkWidget *g_pCamListCombo = NULL; +static GtkLabel *g_pCamType = NULL; + +void RefreshCamListCombo( void ) +{ + if( !g_pCamListCombo ) + return; + + GList *combo_list = (GList*)NULL; + CCamera *combo_cam = firstCam; + if( combo_cam ) { + while( combo_cam ) { + //combo_list = g_list_append( combo_list, (void *)combo_cam->GetCam()->getName() ); + //if( combo_cam->HasBeenSaved() ) { + combo_list = g_list_append( combo_list, (void *)combo_cam->GetFileName() ); + /*} else { + char buf[128]; + sprintf( buf, "Unsaved Camera %i", combo_cam->GetCamNum() ); + combo_list = g_list_append( combo_list, (void *)buf ); + + //combo_list = g_list_append( combo_list, (void *)combo_cam->GetCam()->getName() ); // FIXME: this requires camera.dll to create unique names for new cams + }*/ + combo_cam = combo_cam->GetNext(); + } + }else { + // add one empty string make gtk be quiet + combo_list = g_list_append( combo_list, (gpointer)g_cNull ); + } + gtk_combo_set_popdown_strings( GTK_COMBO( g_pCamListCombo ), combo_list ); + g_list_free( combo_list ); + + // select our current entry in the list + if( GetCurrentCam() ) { + // stop editing on the current cam + //GetCurrentCam()->GetCam()->stopEdit(); // FIXME: this crashed on creating new cameras, why is it here? + + GList *li = GTK_LIST( GTK_COMBO(g_pCamListCombo)->list)->children; + combo_cam = firstCam; + while( li && combo_cam ) { + if( combo_cam == GetCurrentCam() ) { + gtk_list_select_child( GTK_LIST( GTK_COMBO(g_pCamListCombo)->list ), GTK_WIDGET( li->data ) ); + break; + } + li = li->next; + combo_cam = combo_cam->GetNext(); + } + } + + RefreshPathListCombo(); +} + +static gint ci_camlist_changed( GtkWidget *widget, gpointer data ) +{ + const char *str = gtk_entry_get_text( GTK_ENTRY(widget) ); + + CCamera *combo_cam = firstCam; + while( str && combo_cam ) { + //if( !strcmp( str, combo_cam->GetCam()->getName() ) ) + //if( combo_cam->HasBeenSaved() ) { + if( !strcmp( str, combo_cam->GetFileName() ) ) + break; + /*} else { + char buf[128]; + sprintf( buf, "Unsaved Camera %i", combo_cam->GetCamNum() ); + if( !strcmp( str, buf ) ) + //if( !strcmp( str, combo_cam->GetCam()->getName() ) ) + break; + }*/ + + combo_cam = combo_cam->GetNext(); + } + + SetCurrentCam( combo_cam ); + + if( g_pCamType ) { + if( GetCurrentCam() ) { + // Fill in our widgets fields for this camera + char buf[128]; + + // Set Name + gtk_entry_set_text( GTK_ENTRY(g_pCamName), GetCurrentCam()->GetCam()->getName() ); + + // Set type + gtk_label_set_text( g_pCamType, GetCurrentCam()->GetCam()->getPositionObj()->typeStr() ); + + // Set duration + sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getBaseTime() ); + gtk_entry_set_text( GTK_ENTRY(g_pSecondsEntry), buf ); + + sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getTotalTime() ); + gtk_label_set_text( g_pCurrentTime, "0.00" ); + gtk_label_set_text( g_pTotalTime, buf ); + + gtk_adjustment_set_value( g_pTimeLine, 0.f ); + g_pTimeLine->upper = GetCurrentCam()->GetCam()->getTotalTime() * 1000; + } else { + // Set Name + gtk_entry_set_text( GTK_ENTRY(g_pCamName), "" ); + + // Set type + gtk_label_set_text( g_pCamType, "" ); + + // Set duration + gtk_entry_set_text( GTK_ENTRY(g_pSecondsEntry), "30.00" ); + + gtk_label_set_text( g_pCurrentTime, "0.00" ); + gtk_label_set_text( g_pTotalTime, "30.00" ); + + gtk_adjustment_set_value( g_pTimeLine, 0.f ); + g_pTimeLine->upper = 30000; + } + + // Refresh event list + RefreshEventList(); + } + + RefreshPathListCombo(); + + // start edit mode + g_iActiveTarget = -1; + if( g_pCameraInspectorWnd && GTK_WIDGET_VISIBLE( g_pCameraInspectorWnd ) ) + DoStartEdit( GetCurrentCam() ); + + return TRUE; +} + +enum camEventType { + EVENT_NA = 0x00, + EVENT_WAIT, // + EVENT_TARGETWAIT, // + EVENT_SPEED, // + EVENT_TARGET, // char(name) + EVENT_SNAPTARGET, // + EVENT_FOV, // int(time), int(targetfov) + EVENT_CMD, // + EVENT_TRIGGER, // + EVENT_STOP, // + EVENT_CAMERA, // + EVENT_FADEOUT, // int(time) + EVENT_FADEIN, // int(time) + EVENT_FEATHER, // + EVENT_COUNT +}; + +// { requires parameters, enabled } +const bool camEventFlags[][2] = { + { false, false }, + { false, true }, + { false, false }, + { false, false }, + { true, true }, + { false, false }, + { true, true }, + { false, false }, + { false, false }, + { false, true }, + { true, true }, + { true, true }, + { true, true }, + { false, true }, +}; + +const char *camEventStr[] = { + "n/a", + "Wait", + "Target wait", + "Speed", + "Change Target ", + "Snap Target", + "FOV ", + "Run Script", + "Trigger", + "Stop", + "Change to Camera (or ", + "Fade Out ", + "Fade In ", + "Feather" +}; + +static gint ci_add( GtkWidget *widget, gpointer data ) +{ + GtkWidget *window, *w, *vbox, *vbox2, *hbox, *frame, *parameters; + GtkWidget *eventWidget[EVENT_COUNT]; + int i, ret, loop = 1; + GSList *eventTypeRadio = NULL; +// char buf[128]; + + if( !GetCurrentCam() ) + return TRUE; + + // create the window + window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_title( GTK_WINDOW (window), "Add Event" ); + gtk_signal_connect( GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC( dialog_delete_callback ), NULL ); + gtk_signal_connect( GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL ); + gtk_window_set_transient_for( GTK_WINDOW( window ), GTK_WINDOW( g_pCameraInspectorWnd ) ); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + // fill the window + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show( vbox ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + frame = gtk_frame_new( "Type" ); + gtk_box_pack_start( GTK_BOX( hbox ), frame, TRUE, TRUE, 0 ); + gtk_widget_show( frame ); + + vbox2 = gtk_vbox_new( FALSE, 5 ); + gtk_container_add( GTK_CONTAINER( frame ), vbox2 ); + gtk_container_set_border_width( GTK_CONTAINER (vbox2), 5 ); + gtk_widget_show( vbox2 ); + + // -------------------------- // + + for( i = 1; i < EVENT_COUNT; i++ ) { + eventWidget[i] = gtk_radio_button_new_with_label( eventTypeRadio, camEventStr[i] ); + gtk_box_pack_start( GTK_BOX( vbox2 ), eventWidget[i], FALSE, FALSE, 3 ); + gtk_widget_show( eventWidget[i] ); + eventTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( eventWidget[i] ) ); + if( camEventFlags[i][1] == false ) + gtk_widget_set_sensitive (eventWidget[i], FALSE); + } + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Parameters:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + parameters = gtk_entry_new(); + gtk_box_pack_start( GTK_BOX( hbox ), parameters, TRUE, TRUE, 0 ); + gtk_widget_show( parameters ); + + // -------------------------- // + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_show (w); + + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // -------------------------- // + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if( ret == IDOK ) { + const char *str = gtk_entry_get_text( GTK_ENTRY(parameters) ); + + if( !camEventFlags[i][0] || ( str && str[0] ) ) { + int type = 0; +// GList *li; + + for( type = 1; type < EVENT_COUNT; type++ ) { + if( gtk_toggle_button_get_active( (GtkToggleButton*)eventWidget[type] ) ) + break; + } + + // Add the event + GetCurrentCam()->GetCam()->addEvent( static_cast(type), str, (long)(g_pTimeLine->value) ); + + // Refresh event list + RefreshEventList(); + } else { + dialogError = TRUE; + } + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return TRUE; +} + +static gint ci_del( GtkWidget *widget, gpointer data ) +{ + // TODO: add support to splines lib + if( GetCurrentCam() && GTK_CLIST(g_pEventsList)->focus_row >= 0 ) { + GetCurrentCam()->GetCam()->removeEvent( GTK_CLIST(g_pEventsList)->focus_row ); + // Refresh event list + RefreshEventList(); + } + + return TRUE; +} + +static gint ci_timeline_changed( GtkAdjustment *adjustment ) +{ + char buf[128]; + + sprintf( buf, "%.2f", adjustment->value / 1000.f ); + gtk_label_set_text( g_pCurrentTime, buf ); + + // FIXME: this will never work completely perfect. Startcamera calls buildcamera, which sets all events to 'nottriggered'. + // So if you have a wait at the end of the path, this will go to nontriggered immediately when you go over it and the camera + // will have no idea where on the track it should be. + if( GetCurrentCam() && gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(g_pTrackCamera) ) ) { + float fov; + vec3_t origin = { 0.0f, 0.0f, 0.0f }, dir = { 0.0f, 0.0f, 0.0f}, angles; + + GetCurrentCam()->GetCam()->startCamera( 0 ); + + GetCurrentCam()->GetCam()->getCameraInfo( (long)(adjustment->value), &origin[0], &dir[0], &fov ); + VectorSet( angles, asin (dir[2])*180/3.14159, atan2 (dir[1], dir[0])*180/3.14159, 0 ); + g_CameraTable.m_pfnSetCamera( origin, angles ); + } + + return TRUE; +} + +GtkWidget *CreateCameraInspectorDialog( void ) +{ + GtkWidget *window, *w, *vbox, *hbox, *table, *frame; + + // create the window + window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_title( GTK_WINDOW (window), "Camera Inspector" ); + gtk_signal_connect( GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC( ci_close ), NULL ); + gtk_signal_connect( GTK_OBJECT (window), "expose_event", GTK_SIGNAL_FUNC( ci_expose ), NULL ); + // gtk_signal_connect( GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL ); + gtk_window_set_transient_for( GTK_WINDOW( window ), GTK_WINDOW( g_pRadiantWnd ) ); + + // don't use show, as you don't want to have it displayed on startup ;-) + gtk_widget_realize( window ); + + // fill the window + + // the table + // -------------------------- // + + table = gtk_table_new( 3, 2, FALSE ); + gtk_widget_show( table ); + gtk_container_add( GTK_CONTAINER( window ), table ); + gtk_container_set_border_width( GTK_CONTAINER( table ), 5 ); + gtk_table_set_row_spacings( GTK_TABLE( table ), 5 ); + gtk_table_set_col_spacings( GTK_TABLE( table ), 5 ); + + // the properties column + // -------------------------- // + + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_widget_show( vbox ); + gtk_table_attach( GTK_TABLE( table ), vbox, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0 ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "File:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + g_pCamListCombo = gtk_combo_new(); + gtk_box_pack_start (GTK_BOX( hbox ), g_pCamListCombo, TRUE, TRUE, 0); + gtk_widget_show( g_pCamListCombo ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Name:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + g_pCamName = gtk_entry_new(); + gtk_box_pack_start( GTK_BOX( hbox ), g_pCamName, FALSE, FALSE, 0 ); + gtk_widget_show( g_pCamName ); + + w = gtk_label_new( "Type: " ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + w = gtk_label_new( "" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + g_pCamType = GTK_LABEL( w ); + + RefreshCamListCombo(); + + gtk_entry_set_editable( GTK_ENTRY( GTK_COMBO(g_pCamListCombo)->entry ), FALSE ); + gtk_signal_connect( GTK_OBJECT(GTK_COMBO(g_pCamListCombo)->entry), "changed", GTK_SIGNAL_FUNC( ci_camlist_changed ), NULL ); + + // -------------------------- // + + frame = gtk_frame_new( "Path and Target editing" ); + gtk_widget_show( frame ); + gtk_table_attach( GTK_TABLE( table ), frame, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0 ); + + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_container_add( GTK_CONTAINER( frame ), vbox ); + gtk_container_set_border_width( GTK_CONTAINER (vbox), 5 ); + gtk_widget_show( vbox ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Edit:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + g_pPathListCombo = gtk_combo_new(); + gtk_box_pack_start (GTK_BOX( hbox ), g_pPathListCombo, TRUE, TRUE, 0); + gtk_widget_show( g_pPathListCombo ); + + RefreshPathListCombo(); + + gtk_entry_set_editable( GTK_ENTRY( GTK_COMBO(g_pPathListCombo)->entry ), FALSE ); + gtk_signal_connect( GTK_OBJECT(GTK_COMBO(g_pPathListCombo)->entry), "changed", GTK_SIGNAL_FUNC( ci_pathlist_changed ), NULL ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + g_pEditModeEditRadioButton = gtk_radio_button_new_with_label( g_pEditTypeRadio, "Edit Points" ); + gtk_box_pack_start( GTK_BOX( hbox ), g_pEditModeEditRadioButton, FALSE, FALSE, 3 ); + gtk_widget_show( g_pEditModeEditRadioButton ); + g_pEditTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( g_pEditModeEditRadioButton ) ); + + gtk_signal_connect( GTK_OBJECT( g_pEditModeEditRadioButton ), "clicked", GTK_SIGNAL_FUNC( ci_editmode_edit ), NULL ); + + g_pEditModeAddRadioButton = gtk_radio_button_new_with_label( g_pEditTypeRadio, "Add Points" ); + gtk_box_pack_start( GTK_BOX( hbox ), g_pEditModeAddRadioButton, FALSE, FALSE, 3 ); + gtk_widget_show( g_pEditModeAddRadioButton ); + g_pEditTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( g_pEditModeAddRadioButton ) ); + + gtk_signal_connect( GTK_OBJECT( g_pEditModeAddRadioButton ), "clicked", GTK_SIGNAL_FUNC( ci_editmode_add ), NULL ); + + // see if we should use a different default + if( g_iEditMode == 1 ) { + // Go to editmode Add + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(g_pEditModeAddRadioButton), TRUE ); + } + + w = gtk_label_new( "Type: " ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + w = gtk_label_new( "" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + g_pPathType = GTK_LABEL( w ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label( "Rename..." ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_rename ), NULL ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Add Target..." ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_add_target ), NULL ); + gtk_widget_show( w ); + + // not available in splines library + /*w = gtk_button_new_with_label( "Delete Selected" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_delete_selected ), NULL ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Select All" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_select_all ), NULL ); + gtk_widget_show( w );*/ + + // -------------------------- // + + frame = gtk_frame_new( "Time" ); + gtk_widget_show( frame ); + gtk_table_attach( GTK_TABLE( table ), frame, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0 ); + + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_container_add( GTK_CONTAINER( frame ), vbox ); + gtk_container_set_border_width( GTK_CONTAINER (vbox), 5 ); + gtk_widget_show( vbox ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Length (seconds):" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + g_pSecondsEntry = gtk_entry_new(); + gtk_box_pack_start( GTK_BOX( hbox ), g_pSecondsEntry, FALSE, FALSE, 0 ); + gtk_widget_show( g_pSecondsEntry ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Current Time: " ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + w = gtk_label_new( "0.00" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + g_pCurrentTime = GTK_LABEL( w ); + + w = gtk_label_new( " of " ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + w = gtk_label_new( "0.00" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + g_pTotalTime = GTK_LABEL( w ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + g_pTimeLine = GTK_ADJUSTMENT( gtk_adjustment_new( 0, 0, 30000, 100, 250, 0 ) ); + gtk_signal_connect( GTK_OBJECT(g_pTimeLine), "value_changed", GTK_SIGNAL_FUNC( ci_timeline_changed ), NULL ); + w = gtk_hscale_new( g_pTimeLine ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); + gtk_widget_show( w ); + gtk_scale_set_draw_value( GTK_SCALE( w ), FALSE ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + g_pTrackCamera = gtk_check_button_new_with_label( "Track Camera" ); + gtk_box_pack_start( GTK_BOX( hbox ), g_pTrackCamera, FALSE, FALSE, 0 ); + gtk_widget_show( g_pTrackCamera ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Events:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_scrolled_window_new( NULL, NULL ); + gtk_widget_set_usize( w, 0, 150 ); + gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( w ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); + gtk_widget_show( w ); + + g_pEventsList = gtk_clist_new( 3 ); + gtk_container_add( GTK_CONTAINER(w), g_pEventsList); + //gtk_signal_connect( GTK_OBJECT(g_pEventsList), "select_row", GTK_SIGNAL_FUNC (proplist_select_row), NULL); + gtk_clist_set_selection_mode( GTK_CLIST(g_pEventsList), GTK_SELECTION_BROWSE ); + gtk_clist_column_titles_hide( GTK_CLIST(g_pEventsList) ); + gtk_clist_set_column_auto_resize( GTK_CLIST(g_pEventsList), 0, TRUE ); + gtk_clist_set_column_auto_resize( GTK_CLIST(g_pEventsList), 1, TRUE ); + gtk_clist_set_column_auto_resize( GTK_CLIST(g_pEventsList), 2, TRUE ); + gtk_widget_show( g_pEventsList ); + + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( hbox ), vbox, FALSE, FALSE, 0 ); + gtk_widget_show( vbox ); + + w = gtk_button_new_with_label( "Add..." ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_add ), NULL ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Del" ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_del ), NULL ); + gtk_widget_show( w ); + + // -------------------------- // + + /*/ + | + | + | + */ + + // the buttons column + // -------------------------- // + + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_widget_show( vbox ); + gtk_table_attach( GTK_TABLE( table ), vbox, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0 ); + + w = gtk_button_new_with_label( "New..." ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_new ), NULL ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Load..." ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_load ), NULL ); + gtk_widget_show( w ); + + // -------------------------- // + + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_widget_show( vbox ); + gtk_table_attach( GTK_TABLE( table ), vbox, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0 ); + + w = gtk_button_new_with_label( "Save..." ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_save ), NULL ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Unload" ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_unload ), NULL ); + gtk_widget_show( w ); + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, TRUE, TRUE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label( "Apply" ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_apply ), NULL ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Preview" ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_preview ), NULL ); + gtk_widget_show( w ); + + // -------------------------- // + + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_widget_show( vbox ); + gtk_table_attach( GTK_TABLE( table ), vbox, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0 ); + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, TRUE, TRUE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label( "Close" ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_close ), NULL ); + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + gtk_widget_show( w ); + + // -------------------------- // + + return window; +} diff --git a/contrib/camera/dialogs_common.cpp b/contrib/camera/dialogs_common.cpp index bebf5976..ed21f5b4 100644 --- a/contrib/camera/dialogs_common.cpp +++ b/contrib/camera/dialogs_common.cpp @@ -1,51 +1,51 @@ -/* -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 -*/ - -/* -Camera plugin for GtkRadiant -Copyright (C) 2002 Splash Damage Ltd. -*/ - -#include "camera.h" - -void dialog_button_callback (GtkWidget *widget, gpointer data) -{ - GtkWidget *parent; - int *loop, *ret; - - parent = gtk_widget_get_toplevel (widget); - loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); - ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); - - *loop = 0; - *ret = (int)data; -} - -gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) -{ - int *loop; - - gtk_widget_hide (widget); - loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); - *loop = 0; - - return TRUE; -} +/* +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 +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#include "camera.h" + +void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} diff --git a/contrib/camera/funchandlers.cpp b/contrib/camera/funchandlers.cpp index 97e861eb..30f11b5f 100644 --- a/contrib/camera/funchandlers.cpp +++ b/contrib/camera/funchandlers.cpp @@ -1,272 +1,272 @@ -/* -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 -*/ - -/* -Camera plugin for GtkRadiant -Copyright (C) 2002 Splash Damage Ltd. -*/ - -#include "camera.h" - -extern GtkWidget *g_pEditModeAddRadioButton; - -char* Q_realpath(const char *path, char *resolved_path, size_t size) -{ -#if defined (__linux__) || defined (__APPLE__) - return realpath(path, resolved_path); -#else - return _fullpath(resolved_path, path, size); -#endif -} - -static void DoNewCamera( idCameraPosition::positionType type ) -{ - CCamera *cam = AllocCam(); - - if( cam ) { - char buf[128]; - sprintf( buf, "camera%i", cam->GetCamNum() ); - - cam->GetCam()->startNewCamera( type ); - cam->GetCam()->setName( buf ); - cam->GetCam()->buildCamera(); - - sprintf( buf, "Unsaved Camera %i", cam->GetCamNum() ); - cam->SetFileName( buf, false ); - - SetCurrentCam( cam ); - RefreshCamListCombo(); - - // Go to editmode Add - gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(g_pEditModeAddRadioButton), TRUE ); - - // Show the camera inspector - DoCameraInspector(); - - // Start edit mode (if not initiated by DoCameraInspector) - if( !g_bEditOn ) - DoStartEdit( GetCurrentCam() ); - } else { - g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, "No free cameras available.", "Create Camera Error", MB_OK, NULL ); - } -} - -void DoNewFixedCamera() -{ - DoNewCamera( idCameraPosition::FIXED ); -} - -void DoNewInterpolatedCamera() -{ - DoNewCamera( idCameraPosition::INTERPOLATED ); -} - -void DoNewSplineCamera() -{ - DoNewCamera( idCameraPosition::SPLINE ); -} - -void DoCameraInspector() -{ - gtk_widget_show( g_pCameraInspectorWnd ); -} - -void DoPreviewCamera() -{ - if( GetCurrentCam() ) { - g_iPreviewRunning = 1; - g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); - } -} - -void DoLoadCamera() -{ - char basepath[PATH_MAX]; - - if( firstCam && firstCam->HasBeenSaved() ) - ExtractFilePath( firstCam->GetFileName(), basepath ); - else - strcpy( basepath, g_FuncTable.m_pfnGetGamePath() ); - - const gchar *filename = g_FuncTable.m_pfnFileDialog( (GtkWidget *)g_pRadiantWnd, TRUE, "Open Camera File", basepath, "camera"); - - if( filename ) - { - CCamera *cam = AllocCam(); - char fullpathtofile[PATH_MAX]; - - if( cam ) { - Q_realpath(filename, fullpathtofile, PATH_MAX); - - // see if this camera file was already loaded - CCamera *checkCam = firstCam->GetNext(); // not the first one as we just allocated it - while( checkCam ) { - if( !strcmp( fullpathtofile, checkCam->GetFileName() ) ) { - char error[PATH_MAX+64]; - FreeCam( cam ); - sprintf( error, "Camera file \'%s\' is already loaded", fullpathtofile ); - g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, error, "Load error", MB_OK, NULL ); - //g_free( filename ); - return; - } - checkCam = checkCam->GetNext(); - } - - if( loadCamera( cam->GetCamNum(), fullpathtofile ) ) { - cam->GetCam()->buildCamera(); - cam->SetFileName( filename, true ); - SetCurrentCam( cam ); - RefreshCamListCombo(); - g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); - } else { - char error[PATH_MAX+64]; - FreeCam( cam ); - sprintf( error, "An error occured during the loading of \'%s\'", fullpathtofile ); - g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, error, "Load error", MB_OK, NULL ); - } - - //g_free( filename ); - } else { - g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, "No free camera slots available", "Load error", MB_OK, NULL ); - } - } -} - -void DoSaveCamera() { - char basepath[PATH_MAX]; - - if( !GetCurrentCam() ) - return; - - if( GetCurrentCam()->GetFileName()[0] ) - ExtractFilePath( GetCurrentCam()->GetFileName(), basepath ); - else - strcpy( basepath, g_FuncTable.m_pfnGetGamePath() ); - - const gchar *filename = g_FuncTable.m_pfnFileDialog( (void *)g_pRadiantWnd, FALSE, "Save Camera File", basepath, "camera"); - - if( filename ) { - char fullpathtofile[PATH_MAX + 8]; - - Q_realpath(filename, fullpathtofile, PATH_MAX); - - // File dialog from windows (and maybe the gtk one from radiant) doesn't handle default extensions properly. - // Add extension and check again if file exists - if( strcmp( fullpathtofile + (strlen(fullpathtofile) - 7), ".camera" ) ) { - strcat( fullpathtofile, ".camera" ); - - if( FileExists( fullpathtofile ) ) { - if ( g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, "File already exists.\nOverwrite?", "Save Camera File", MB_YESNO, NULL ) == IDNO ) { - return; - } - } - } - - // see if this camera file was already loaded - CCamera *checkCam = firstCam; - while( checkCam ) { - if( checkCam == GetCurrentCam() ) { - checkCam = checkCam->GetNext(); - if( !checkCam ) // we only have one camera file opened so no need to check further - break; - } else if( !strcmp( fullpathtofile, checkCam->GetFileName() ) ) { - char error[PATH_MAX+64]; - sprintf( error, "Camera file \'%s\' is currently loaded by GtkRadiant.\nPlease select a different filename.", fullpathtofile ); - g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, error, "Save error", MB_OK, NULL ); - return; - } - checkCam = checkCam->GetNext(); - } - - // FIXME: check for existing directory - - GetCurrentCam()->GetCam()->save( fullpathtofile ); - GetCurrentCam()->SetFileName( fullpathtofile, true ); - RefreshCamListCombo(); - } -} - -void DoUnloadCamera() { - if( !GetCurrentCam() ) - return; - - if( !GetCurrentCam()->HasBeenSaved() ) { - char buf[PATH_MAX+64]; - sprintf( buf, "Do you want to save the changes for camera '%s'?", GetCurrentCam()->GetCam()->getName() ); - if ( g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, buf, "Warning", MB_YESNO, NULL ) == IDYES ) { - DoSaveCamera(); - } - } else if( GetCurrentCam()->HasBeenSaved() == 2 ) { - char buf[PATH_MAX+64]; - sprintf( buf, "Do you want to save the changes made to camera file '%s'?", GetCurrentCam()->GetFileName() ); - if( g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, buf, "Warning", MB_YESNO, NULL ) == IDYES ) { - DoSaveCamera(); - } - } - - if( g_pCurrentEditCam ) { - DoStopEdit(); - g_pCurrentEditCam = NULL; - } - - FreeCam( GetCurrentCam() ); - SetCurrentCam( NULL ); - RefreshCamListCombo(); -} - -CCamera *g_pCurrentEditCam = NULL; - -void DoStartEdit( CCamera *cam ) { - if( g_pCurrentEditCam ) { - DoStopEdit(); - g_pCurrentEditCam = NULL; - } - - if( cam ) { - g_bEditOn = true; - - if( !Listener ) - Listener = new CListener; - - cam->GetCam()->startEdit( g_iActiveTarget < 0 ? true : false ); - - g_pCurrentEditCam = cam; - - g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); - } -} - -void DoStopEdit( void ) { - g_bEditOn = false; - - if( Listener ) { - delete Listener; - Listener = NULL; - } - - if( g_pCurrentEditCam ) { - // stop editing on the current cam - g_pCurrentEditCam->GetCam()->stopEdit(); - g_pCurrentEditCam = NULL; - - g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); - } -} +/* +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 +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#include "camera.h" + +extern GtkWidget *g_pEditModeAddRadioButton; + +char* Q_realpath(const char *path, char *resolved_path, size_t size) +{ +#if defined (__linux__) || defined (__APPLE__) + return realpath(path, resolved_path); +#else + return _fullpath(resolved_path, path, size); +#endif +} + +static void DoNewCamera( idCameraPosition::positionType type ) +{ + CCamera *cam = AllocCam(); + + if( cam ) { + char buf[128]; + sprintf( buf, "camera%i", cam->GetCamNum() ); + + cam->GetCam()->startNewCamera( type ); + cam->GetCam()->setName( buf ); + cam->GetCam()->buildCamera(); + + sprintf( buf, "Unsaved Camera %i", cam->GetCamNum() ); + cam->SetFileName( buf, false ); + + SetCurrentCam( cam ); + RefreshCamListCombo(); + + // Go to editmode Add + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(g_pEditModeAddRadioButton), TRUE ); + + // Show the camera inspector + DoCameraInspector(); + + // Start edit mode (if not initiated by DoCameraInspector) + if( !g_bEditOn ) + DoStartEdit( GetCurrentCam() ); + } else { + g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, "No free cameras available.", "Create Camera Error", MB_OK, NULL ); + } +} + +void DoNewFixedCamera() +{ + DoNewCamera( idCameraPosition::FIXED ); +} + +void DoNewInterpolatedCamera() +{ + DoNewCamera( idCameraPosition::INTERPOLATED ); +} + +void DoNewSplineCamera() +{ + DoNewCamera( idCameraPosition::SPLINE ); +} + +void DoCameraInspector() +{ + gtk_widget_show( g_pCameraInspectorWnd ); +} + +void DoPreviewCamera() +{ + if( GetCurrentCam() ) { + g_iPreviewRunning = 1; + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + } +} + +void DoLoadCamera() +{ + char basepath[PATH_MAX]; + + if( firstCam && firstCam->HasBeenSaved() ) + ExtractFilePath( firstCam->GetFileName(), basepath ); + else + strcpy( basepath, g_FuncTable.m_pfnGetGamePath() ); + + const gchar *filename = g_FuncTable.m_pfnFileDialog( (GtkWidget *)g_pRadiantWnd, TRUE, "Open Camera File", basepath, "camera"); + + if( filename ) + { + CCamera *cam = AllocCam(); + char fullpathtofile[PATH_MAX]; + + if( cam ) { + Q_realpath(filename, fullpathtofile, PATH_MAX); + + // see if this camera file was already loaded + CCamera *checkCam = firstCam->GetNext(); // not the first one as we just allocated it + while( checkCam ) { + if( !strcmp( fullpathtofile, checkCam->GetFileName() ) ) { + char error[PATH_MAX+64]; + FreeCam( cam ); + sprintf( error, "Camera file \'%s\' is already loaded", fullpathtofile ); + g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, error, "Load error", MB_OK, NULL ); + //g_free( filename ); + return; + } + checkCam = checkCam->GetNext(); + } + + if( loadCamera( cam->GetCamNum(), fullpathtofile ) ) { + cam->GetCam()->buildCamera(); + cam->SetFileName( filename, true ); + SetCurrentCam( cam ); + RefreshCamListCombo(); + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + } else { + char error[PATH_MAX+64]; + FreeCam( cam ); + sprintf( error, "An error occured during the loading of \'%s\'", fullpathtofile ); + g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, error, "Load error", MB_OK, NULL ); + } + + //g_free( filename ); + } else { + g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, "No free camera slots available", "Load error", MB_OK, NULL ); + } + } +} + +void DoSaveCamera() { + char basepath[PATH_MAX]; + + if( !GetCurrentCam() ) + return; + + if( GetCurrentCam()->GetFileName()[0] ) + ExtractFilePath( GetCurrentCam()->GetFileName(), basepath ); + else + strcpy( basepath, g_FuncTable.m_pfnGetGamePath() ); + + const gchar *filename = g_FuncTable.m_pfnFileDialog( (void *)g_pRadiantWnd, FALSE, "Save Camera File", basepath, "camera"); + + if( filename ) { + char fullpathtofile[PATH_MAX + 8]; + + Q_realpath(filename, fullpathtofile, PATH_MAX); + + // File dialog from windows (and maybe the gtk one from radiant) doesn't handle default extensions properly. + // Add extension and check again if file exists + if( strcmp( fullpathtofile + (strlen(fullpathtofile) - 7), ".camera" ) ) { + strcat( fullpathtofile, ".camera" ); + + if( FileExists( fullpathtofile ) ) { + if ( g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, "File already exists.\nOverwrite?", "Save Camera File", MB_YESNO, NULL ) == IDNO ) { + return; + } + } + } + + // see if this camera file was already loaded + CCamera *checkCam = firstCam; + while( checkCam ) { + if( checkCam == GetCurrentCam() ) { + checkCam = checkCam->GetNext(); + if( !checkCam ) // we only have one camera file opened so no need to check further + break; + } else if( !strcmp( fullpathtofile, checkCam->GetFileName() ) ) { + char error[PATH_MAX+64]; + sprintf( error, "Camera file \'%s\' is currently loaded by GtkRadiant.\nPlease select a different filename.", fullpathtofile ); + g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, error, "Save error", MB_OK, NULL ); + return; + } + checkCam = checkCam->GetNext(); + } + + // FIXME: check for existing directory + + GetCurrentCam()->GetCam()->save( fullpathtofile ); + GetCurrentCam()->SetFileName( fullpathtofile, true ); + RefreshCamListCombo(); + } +} + +void DoUnloadCamera() { + if( !GetCurrentCam() ) + return; + + if( !GetCurrentCam()->HasBeenSaved() ) { + char buf[PATH_MAX+64]; + sprintf( buf, "Do you want to save the changes for camera '%s'?", GetCurrentCam()->GetCam()->getName() ); + if ( g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, buf, "Warning", MB_YESNO, NULL ) == IDYES ) { + DoSaveCamera(); + } + } else if( GetCurrentCam()->HasBeenSaved() == 2 ) { + char buf[PATH_MAX+64]; + sprintf( buf, "Do you want to save the changes made to camera file '%s'?", GetCurrentCam()->GetFileName() ); + if( g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, buf, "Warning", MB_YESNO, NULL ) == IDYES ) { + DoSaveCamera(); + } + } + + if( g_pCurrentEditCam ) { + DoStopEdit(); + g_pCurrentEditCam = NULL; + } + + FreeCam( GetCurrentCam() ); + SetCurrentCam( NULL ); + RefreshCamListCombo(); +} + +CCamera *g_pCurrentEditCam = NULL; + +void DoStartEdit( CCamera *cam ) { + if( g_pCurrentEditCam ) { + DoStopEdit(); + g_pCurrentEditCam = NULL; + } + + if( cam ) { + g_bEditOn = true; + + if( !Listener ) + Listener = new CListener; + + cam->GetCam()->startEdit( g_iActiveTarget < 0 ? true : false ); + + g_pCurrentEditCam = cam; + + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + } +} + +void DoStopEdit( void ) { + g_bEditOn = false; + + if( Listener ) { + delete Listener; + Listener = NULL; + } + + if( g_pCurrentEditCam ) { + // stop editing on the current cam + g_pCurrentEditCam->GetCam()->stopEdit(); + g_pCurrentEditCam = NULL; + + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + } +} diff --git a/contrib/camera/listener.cpp b/contrib/camera/listener.cpp index c21e8715..7e3d1b66 100644 --- a/contrib/camera/listener.cpp +++ b/contrib/camera/listener.cpp @@ -1,234 +1,234 @@ -/* -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 -*/ - -/* -Camera plugin for GtkRadiant -Copyright (C) 2002 Splash Damage Ltd. -*/ - -#include "camera.h" - -CListener::CListener() -{ - refCount = 1; - - m_bHooked = FALSE; - - m_bLeftMBPressed = m_bRightMBPressed = m_bMiddleMBPressed = false; - - oldValid = false; - - Register(); -} - -CListener::~CListener() -{ - UnRegister(); -} - -void CListener::Register() -{ - g_UITable.m_pfnHookWindow( this ); - g_pXYWndWrapper = g_UITable.m_pfnGetXYWndWrapper(); - m_bHooked = TRUE; -} - -void CListener::UnRegister() -{ - if(m_bHooked) - { - g_UITable.m_pfnUnHookWindow( this ); - g_pXYWndWrapper= NULL; - m_bHooked = FALSE; - } -} - -bool CListener::OnMouseMove( guint32 nFlags, gdouble x, gdouble y ) -{ - SetViewType( g_pXYWndWrapper->GetViewType() ); - - if( m_bLeftMBPressed && oldValid && g_iEditMode == 0 ) { - vec3_t click, delta; - - g_pXYWndWrapper->SnapToGrid( (int)x, (int)y, click ); - - switch( m_vt ) { - case XY: - VectorSet( delta, click[0] - old_x, click[1] - old_y, 0 ); - old_x = click[0]; old_y = click[1]; - break; - case XZ: - VectorSet( delta, click[0] - old_x, 0, click[2] - old_y ); - old_x = click[0]; old_y = click[2]; - break; - case YZ: - VectorSet( delta, 0, click[1] - old_x, click[2] - old_y ); - old_x = click[1]; old_y = click[2]; - break; - } - - if( g_iActiveTarget < 0 ) - GetCurrentCam()->GetCam()->getPositionObj()->updateSelection( delta[0], delta[1], delta[2] ); - else - GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->updateSelection( delta[0], delta[1], delta[2] ); - - GetCurrentCam()->HasBeenModified(); - - g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); - - return true; - } - - return false; -} - -bool CListener::OnLButtonDown( guint32 nFlags, gdouble x, gdouble y ) -{ - SetViewType( g_pXYWndWrapper->GetViewType() ); - - m_bLeftMBPressed = true; - oldValid = true; - - vec3_t org, delta; - - g_pXYWndWrapper->SnapToGrid( (int)x, (int)y, org ); - - switch( m_vt ) { - case XY: - old_x = org[0]; old_y = org[1]; org[2] = 64*1024; - VectorSet( delta, 0, 0, -1 ); - break; - case XZ: - old_x = org[0]; old_y = org[2]; org[1] = 64*1024; - VectorSet( delta, 0, -1, 0 ); - break; - case YZ: - old_x = org[1]; old_y = org[2]; org[0] = 64*1024; - VectorSet( delta, -1, 0, 0 ); - break; - } - - if( g_iEditMode == 0 ) { - if( g_iActiveTarget < 0 ) - GetCurrentCam()->GetCam()->getPositionObj()->selectPointByRay( org[0], org[1], org[2], delta[0], delta[1], delta[2], true ); - else - GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->selectPointByRay( org[0], org[1], org[2], delta[0], delta[1], delta[2], true ); - } else if( g_iEditMode == 1 ) { - idVec3 *lastcoord; - idCameraPosition *camera; - - if( g_iActiveTarget < 0 ) { - camera = GetCurrentCam()->GetCam()->getPositionObj(); - } else { - camera = GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget); - } - - if( camera->numPoints() ) { - lastcoord = camera->getPoint( camera->numPoints() -1 ); - switch( m_vt ) { - case XY: - camera->addPoint( org[0], org[1], lastcoord->z ); - break; - case XZ: - camera->addPoint( org[0], lastcoord->y, org[2] ); - break; - case YZ: - camera->addPoint( lastcoord->x, org[1], org[2] ); - break; - } - } else { - switch( m_vt ) { - case XY: - camera->addPoint( org[0], org[1], 0 ); - break; - case XZ: - camera->addPoint( org[0], 0, org[2] ); - break; - case YZ: - camera->addPoint( 0, org[1], org[2] ); - break; - } - } - - GetCurrentCam()->HasBeenModified(); - } - - g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); - - return true; - - //return false; -} - -bool CListener::OnLButtonUp( guint32 nFlags, gdouble x, gdouble y ) -{ - SetViewType( g_pXYWndWrapper->GetViewType() ); - - m_bLeftMBPressed = false; - oldValid = false; - - if( g_iEditMode == 0 ) { - if( g_iActiveTarget < 0 ) - GetCurrentCam()->GetCam()->getPositionObj()->deselectAll(); - else - GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->deselectAll(); - - g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); - } - - return false; -} - -bool CListener::OnRButtonDown( guint32 nFlags, gdouble x, gdouble y ) -{ - SetViewType( g_pXYWndWrapper->GetViewType() ); - - m_bRightMBPressed = true; - - return false; -} - -bool CListener::OnRButtonUp( guint32 nFlags, gdouble x, gdouble y ) -{ - SetViewType( g_pXYWndWrapper->GetViewType() ); - - m_bRightMBPressed = false; - - return false; -} - -bool CListener::OnMButtonDown( guint32 nFlags, gdouble x, gdouble y ) -{ - SetViewType( g_pXYWndWrapper->GetViewType() ); - - m_bMiddleMBPressed = true; - - return false; -} - -bool CListener::OnMButtonUp( guint32 nFlags, gdouble x, gdouble y ) -{ - SetViewType( g_pXYWndWrapper->GetViewType() ); - - m_bMiddleMBPressed = false; - - return false; -} +/* +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 +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#include "camera.h" + +CListener::CListener() +{ + refCount = 1; + + m_bHooked = FALSE; + + m_bLeftMBPressed = m_bRightMBPressed = m_bMiddleMBPressed = false; + + oldValid = false; + + Register(); +} + +CListener::~CListener() +{ + UnRegister(); +} + +void CListener::Register() +{ + g_UITable.m_pfnHookWindow( this ); + g_pXYWndWrapper = g_UITable.m_pfnGetXYWndWrapper(); + m_bHooked = TRUE; +} + +void CListener::UnRegister() +{ + if(m_bHooked) + { + g_UITable.m_pfnUnHookWindow( this ); + g_pXYWndWrapper= NULL; + m_bHooked = FALSE; + } +} + +bool CListener::OnMouseMove( guint32 nFlags, gdouble x, gdouble y ) +{ + SetViewType( g_pXYWndWrapper->GetViewType() ); + + if( m_bLeftMBPressed && oldValid && g_iEditMode == 0 ) { + vec3_t click, delta; + + g_pXYWndWrapper->SnapToGrid( (int)x, (int)y, click ); + + switch( m_vt ) { + case XY: + VectorSet( delta, click[0] - old_x, click[1] - old_y, 0 ); + old_x = click[0]; old_y = click[1]; + break; + case XZ: + VectorSet( delta, click[0] - old_x, 0, click[2] - old_y ); + old_x = click[0]; old_y = click[2]; + break; + case YZ: + VectorSet( delta, 0, click[1] - old_x, click[2] - old_y ); + old_x = click[1]; old_y = click[2]; + break; + } + + if( g_iActiveTarget < 0 ) + GetCurrentCam()->GetCam()->getPositionObj()->updateSelection( delta[0], delta[1], delta[2] ); + else + GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->updateSelection( delta[0], delta[1], delta[2] ); + + GetCurrentCam()->HasBeenModified(); + + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + + return true; + } + + return false; +} + +bool CListener::OnLButtonDown( guint32 nFlags, gdouble x, gdouble y ) +{ + SetViewType( g_pXYWndWrapper->GetViewType() ); + + m_bLeftMBPressed = true; + oldValid = true; + + vec3_t org, delta; + + g_pXYWndWrapper->SnapToGrid( (int)x, (int)y, org ); + + switch( m_vt ) { + case XY: + old_x = org[0]; old_y = org[1]; org[2] = 64*1024; + VectorSet( delta, 0, 0, -1 ); + break; + case XZ: + old_x = org[0]; old_y = org[2]; org[1] = 64*1024; + VectorSet( delta, 0, -1, 0 ); + break; + case YZ: + old_x = org[1]; old_y = org[2]; org[0] = 64*1024; + VectorSet( delta, -1, 0, 0 ); + break; + } + + if( g_iEditMode == 0 ) { + if( g_iActiveTarget < 0 ) + GetCurrentCam()->GetCam()->getPositionObj()->selectPointByRay( org[0], org[1], org[2], delta[0], delta[1], delta[2], true ); + else + GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->selectPointByRay( org[0], org[1], org[2], delta[0], delta[1], delta[2], true ); + } else if( g_iEditMode == 1 ) { + idVec3 *lastcoord; + idCameraPosition *camera; + + if( g_iActiveTarget < 0 ) { + camera = GetCurrentCam()->GetCam()->getPositionObj(); + } else { + camera = GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget); + } + + if( camera->numPoints() ) { + lastcoord = camera->getPoint( camera->numPoints() -1 ); + switch( m_vt ) { + case XY: + camera->addPoint( org[0], org[1], lastcoord->z ); + break; + case XZ: + camera->addPoint( org[0], lastcoord->y, org[2] ); + break; + case YZ: + camera->addPoint( lastcoord->x, org[1], org[2] ); + break; + } + } else { + switch( m_vt ) { + case XY: + camera->addPoint( org[0], org[1], 0 ); + break; + case XZ: + camera->addPoint( org[0], 0, org[2] ); + break; + case YZ: + camera->addPoint( 0, org[1], org[2] ); + break; + } + } + + GetCurrentCam()->HasBeenModified(); + } + + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + + return true; + + //return false; +} + +bool CListener::OnLButtonUp( guint32 nFlags, gdouble x, gdouble y ) +{ + SetViewType( g_pXYWndWrapper->GetViewType() ); + + m_bLeftMBPressed = false; + oldValid = false; + + if( g_iEditMode == 0 ) { + if( g_iActiveTarget < 0 ) + GetCurrentCam()->GetCam()->getPositionObj()->deselectAll(); + else + GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->deselectAll(); + + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + } + + return false; +} + +bool CListener::OnRButtonDown( guint32 nFlags, gdouble x, gdouble y ) +{ + SetViewType( g_pXYWndWrapper->GetViewType() ); + + m_bRightMBPressed = true; + + return false; +} + +bool CListener::OnRButtonUp( guint32 nFlags, gdouble x, gdouble y ) +{ + SetViewType( g_pXYWndWrapper->GetViewType() ); + + m_bRightMBPressed = false; + + return false; +} + +bool CListener::OnMButtonDown( guint32 nFlags, gdouble x, gdouble y ) +{ + SetViewType( g_pXYWndWrapper->GetViewType() ); + + m_bMiddleMBPressed = true; + + return false; +} + +bool CListener::OnMButtonUp( guint32 nFlags, gdouble x, gdouble y ) +{ + SetViewType( g_pXYWndWrapper->GetViewType() ); + + m_bMiddleMBPressed = false; + + return false; +} diff --git a/contrib/camera/misc.cpp b/contrib/camera/misc.cpp index 8f45d9b3..60f0bcc8 100644 --- a/contrib/camera/misc.cpp +++ b/contrib/camera/misc.cpp @@ -1,243 +1,243 @@ -/* -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 -*/ - -/* -Camera plugin for GtkRadiant -Copyright (C) 2002 Splash Damage Ltd. -*/ - -#include "camera.h" - -void Sys_ERROR( char* text, ... ) -{ - va_list argptr; - char buf[32768]; - - va_start (argptr,text); - vsprintf (buf, text,argptr); - va_end (argptr); - - Sys_Printf("Camera::ERROR->%s", buf); -} - -char* UnixToDosPath( char* path ) -{ -#ifndef _WIN32 - return path; -#else - for(char* p = path; *p; p++) - { - if(*p == '/') - *p = '\\'; - } - return path; -#endif -} - -void ExtractFilePath( const char *path, char *dest ) -{ - const char *src; - - src = path + strlen(path) - 1; - -// -// back up until a \ or the start -// - while (src != path && *(src-1) != '/' && *(src-1) != '\\') - src--; - - memcpy (dest, path, src-path); - dest[src-path] = 0; -} - -const char* ExtractFilename( const char* path ) -{ - char* p = (char *)strrchr(path, '/'); - if(!p) - { - p = (char *)strrchr(path, '\\'); - - if(!p) - return path; - } - return ++p; -} - -int Q_stricmp (const char *s1, const char *s2) { - return stricmp( s1, s2 ); -} - -/* -============== -FileExists -============== -*/ -bool FileExists (const char *filename) -{ - FILE *f; - - f = fopen( filename, "r" ); - if( !f ) - return false; - fclose( f ); - return true; -} - -// -// command buffer -// empty wrappers, don't really use them here -// -void Cbuf_AddText( const char *text ) {}; -void Cbuf_Execute (void) {}; - -// -// Common -// - -void CDECL Com_Error( int level, const char *error, ... ) -{ - va_list argptr; - char buf[32768]; - - va_start (argptr,error); - vsprintf (buf, error,argptr); - va_end (argptr); - - Sys_Printf("Camera::ERROR->%s", buf); -} - -void CDECL Com_Printf( const char* msg, ... ) -{ - va_list argptr; - char buf[32768]; - - va_start (argptr,msg); - vsprintf (buf, msg,argptr); - va_end (argptr); - - Sys_Printf("Camera::%s", buf); -} - -void CDECL Com_DPrintf( const char* msg, ... ) -{ -#ifdef _DEBUG - va_list argptr; - char buf[32768]; - - va_start (argptr,msg); - vsprintf (buf, msg,argptr); - va_end (argptr); - - Sys_Printf("Camera::%s", buf); -#endif -} - -void *Com_Allocate( int bytes ) { - return( malloc( bytes ) ); -} - -void Com_Dealloc( void *ptr ) { - free( ptr ); -} - -// -// Filesystem -// - -#ifdef _WIN32 - #pragma warning(disable : 4311) - #pragma warning(disable : 4312) -#endif - -int FS_Read( void *buffer, int len, fileHandle_t f ) { - return fread( buffer, len, 1, (FILE *)f ); -} - -int FS_Write( const void *buffer, int len, fileHandle_t h ) { - return fwrite( buffer, len, 1, (FILE *)h ); -} - -int FS_ReadFile( const char *qpath, void **buffer ) { - fileHandle_t h; - byte* buf; - int len; - - buf = NULL; - - len = FS_FOpenFileRead( qpath, &h, qfalse ); - - if( h == 0 ) { - if ( buffer ) { - *buffer = NULL; - } - - return -1; - } - - buf = (byte *)Com_Allocate( len + 1 ); - - *buffer = buf; - - FS_Read (buf, len, h); - - buf[len] = 0; - FS_FCloseFile( h ); - - return len; -} - -void FS_FreeFile( void *buffer ) { - Com_Dealloc( buffer ); -} - -int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueFILE ) { - FILE *fh; - long len; - - fh = fopen( filename, "rb" ); - *file = *(fileHandle_t *)&fh; - - if( file ) - { - fseek (fh, 0, SEEK_END); - len = ftell (fh); - rewind (fh); - return len; - } - else - return -1; -} - -fileHandle_t FS_FOpenFileWrite( const char *filename ) { - FILE *fh; - fileHandle_t f; - - memset( &f, 0, sizeof(f) ); - - fh = fopen( filename, "wb" ); - - f = (fileHandle_t)fh; - return f; -} - -void FS_FCloseFile( fileHandle_t f ) { - fclose( (FILE *)f ); -} +/* +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 +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#include "camera.h" + +void Sys_ERROR( char* text, ... ) +{ + va_list argptr; + char buf[32768]; + + va_start (argptr,text); + vsprintf (buf, text,argptr); + va_end (argptr); + + Sys_Printf("Camera::ERROR->%s", buf); +} + +char* UnixToDosPath( char* path ) +{ +#ifndef _WIN32 + return path; +#else + for(char* p = path; *p; p++) + { + if(*p == '/') + *p = '\\'; + } + return path; +#endif +} + +void ExtractFilePath( const char *path, char *dest ) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' && *(src-1) != '\\') + src--; + + memcpy (dest, path, src-path); + dest[src-path] = 0; +} + +const char* ExtractFilename( const char* path ) +{ + char* p = (char *)strrchr(path, '/'); + if(!p) + { + p = (char *)strrchr(path, '\\'); + + if(!p) + return path; + } + return ++p; +} + +int Q_stricmp (const char *s1, const char *s2) { + return stricmp( s1, s2 ); +} + +/* +============== +FileExists +============== +*/ +bool FileExists (const char *filename) +{ + FILE *f; + + f = fopen( filename, "r" ); + if( !f ) + return false; + fclose( f ); + return true; +} + +// +// command buffer +// empty wrappers, don't really use them here +// +void Cbuf_AddText( const char *text ) {}; +void Cbuf_Execute (void) {}; + +// +// Common +// + +void CDECL Com_Error( int level, const char *error, ... ) +{ + va_list argptr; + char buf[32768]; + + va_start (argptr,error); + vsprintf (buf, error,argptr); + va_end (argptr); + + Sys_Printf("Camera::ERROR->%s", buf); +} + +void CDECL Com_Printf( const char* msg, ... ) +{ + va_list argptr; + char buf[32768]; + + va_start (argptr,msg); + vsprintf (buf, msg,argptr); + va_end (argptr); + + Sys_Printf("Camera::%s", buf); +} + +void CDECL Com_DPrintf( const char* msg, ... ) +{ +#ifdef _DEBUG + va_list argptr; + char buf[32768]; + + va_start (argptr,msg); + vsprintf (buf, msg,argptr); + va_end (argptr); + + Sys_Printf("Camera::%s", buf); +#endif +} + +void *Com_Allocate( int bytes ) { + return( malloc( bytes ) ); +} + +void Com_Dealloc( void *ptr ) { + free( ptr ); +} + +// +// Filesystem +// + +#ifdef _WIN32 + #pragma warning(disable : 4311) + #pragma warning(disable : 4312) +#endif + +int FS_Read( void *buffer, int len, fileHandle_t f ) { + return fread( buffer, len, 1, (FILE *)f ); +} + +int FS_Write( const void *buffer, int len, fileHandle_t h ) { + return fwrite( buffer, len, 1, (FILE *)h ); +} + +int FS_ReadFile( const char *qpath, void **buffer ) { + fileHandle_t h; + byte* buf; + int len; + + buf = NULL; + + len = FS_FOpenFileRead( qpath, &h, qfalse ); + + if( h == 0 ) { + if ( buffer ) { + *buffer = NULL; + } + + return -1; + } + + buf = (byte *)Com_Allocate( len + 1 ); + + *buffer = buf; + + FS_Read (buf, len, h); + + buf[len] = 0; + FS_FCloseFile( h ); + + return len; +} + +void FS_FreeFile( void *buffer ) { + Com_Dealloc( buffer ); +} + +int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueFILE ) { + FILE *fh; + long len; + + fh = fopen( filename, "rb" ); + *file = *(fileHandle_t *)&fh; + + if( file ) + { + fseek (fh, 0, SEEK_END); + len = ftell (fh); + rewind (fh); + return len; + } + else + return -1; +} + +fileHandle_t FS_FOpenFileWrite( const char *filename ) { + FILE *fh; + fileHandle_t f; + + memset( &f, 0, sizeof(f) ); + + fh = fopen( filename, "wb" ); + + f = (fileHandle_t)fh; + return f; +} + +void FS_FCloseFile( fileHandle_t f ) { + fclose( (FILE *)f ); +} diff --git a/contrib/camera/renderer.cpp b/contrib/camera/renderer.cpp index 9f44a37d..e4b9e38f 100644 --- a/contrib/camera/renderer.cpp +++ b/contrib/camera/renderer.cpp @@ -1,183 +1,183 @@ -/* -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 -*/ - -/* -Camera plugin for GtkRadiant -Copyright (C) 2002 Splash Damage Ltd. -*/ - -#include "camera.h" - -CRenderer::CRenderer() { - - refCount = 1; - - m_bHooked = FALSE; - - Register(); - Initialize(); -} - -CRenderer::~CRenderer() { - if( m_bHooked ) - UnRegister(); -} - -void CRenderer::Register() { - g_QglTable.m_pfnHookGL2DWindow( this ); - g_QglTable.m_pfnHookGL3DWindow( this ); - m_bHooked = TRUE; -} - -void CRenderer::UnRegister() { - if( g_QglTable.m_nSize ) { - g_QglTable.m_pfnUnHookGL2DWindow( this ); - g_QglTable.m_pfnUnHookGL3DWindow( this ); - } - m_bHooked = FALSE; -} - -void CRenderer::Initialize() { - -} - -void CRenderer::Draw2D( VIEWTYPE vt ) { - - g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); - 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; - } - - CCamera *cam = firstCam; - while( cam ) { - cam->GetCam()->draw( ((Listener && cam == g_pCurrentEditCam) ? true : false) ); - cam = cam->GetNext(); - } - - g_QglTable.m_pfn_qglPopMatrix(); - g_QglTable.m_pfn_qglPopAttrib(); -} - -void CRenderer::Draw3D() { - // FIXME: really need a mainloop callback from the editor core - static long start; - static float cycle; - static long msecs; - static long current; - - if( g_iPreviewRunning ) { - if( g_iPreviewRunning == 1 ) { - start = g_FuncTable.m_pfnQGetTickCount(); - GetCurrentCam()->GetCam()->startCamera( start ); - cycle = GetCurrentCam()->GetCam()->getTotalTime(); - msecs = (long)(cycle * 1000); - current = start; - g_iPreviewRunning = 2; - } - - if( current < start + msecs ) { - float fov; - vec3_t origin = {0.0f, 0.0f, 0.0f}, dir = {0.0f, 0.0f, 0.0f}, angles; - - GetCurrentCam()->GetCam()->getCameraInfo( current, &origin[0], &dir[0], &fov ); - VectorSet( angles, asin (dir[2])*180/3.14159, atan2 (dir[1], dir[0])*180/3.14159, 0 ); - g_CameraTable.m_pfnSetCamera( origin, angles ); - current = g_FuncTable.m_pfnQGetTickCount(); - } else { - g_iPreviewRunning = 0; - GetCurrentCam()->GetCam()->setRunning( false ); - g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); - } - } - - g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); - - CCamera *cam = firstCam; - while( cam ) { - cam->GetCam()->draw( ((Listener && cam == g_pCurrentEditCam) ? true : false) ); - cam = cam->GetNext(); - } - - if( g_iPreviewRunning ) { - int x, y, width, height, i; - float degInRad; - - g_CameraTable.m_pfnGetCamWindowExtents( &x, &y, &width, &height ); - - // setup orthographic projection mode - g_QglTable.m_pfn_qglMatrixMode(GL_PROJECTION); - g_QglTable.m_pfn_qglLoadIdentity(); - g_QglTable.m_pfn_qglDisable( GL_DEPTH_TEST ); - g_QglTable.m_pfn_qglOrtho( 0, (float)width, 0, (float)height, -100, 100 ); - g_QglTable.m_pfn_qglMatrixMode( GL_MODELVIEW ); - - g_QglTable.m_pfn_qglLoadIdentity(); - g_QglTable.m_pfn_qglColor3f( 1.f, 1.f, 1.f ); - g_QglTable.m_pfn_qglBegin( GL_LINE_LOOP ); - g_QglTable.m_pfn_qglVertex2f( 10, 10 ); - g_QglTable.m_pfn_qglVertex2f( 40, 10 ); - g_QglTable.m_pfn_qglVertex2f( 40, 25 ); - g_QglTable.m_pfn_qglVertex2f( 10, 25 ); - g_QglTable.m_pfn_qglEnd(); - - g_QglTable.m_pfn_qglBegin( GL_LINE_LOOP ); - for( i = 0; i < 360; i += 60 ) { - degInRad = i * (3.14159265358979323846/180.f); - g_QglTable.m_pfn_qglVertex2f( 18 + cos(degInRad) * 5, 18 + sin(degInRad) * 5 ); - } - g_QglTable.m_pfn_qglEnd(); - - degInRad = (360-((current - start) % 360)) * (3.14159265358979323846/180.f); - g_QglTable.m_pfn_qglBegin( GL_LINES ); - g_QglTable.m_pfn_qglVertex2f( 18, 18 ); - g_QglTable.m_pfn_qglVertex2f( 18 + cos(degInRad) * 5, 18 + sin(degInRad) * 5 ); - g_QglTable.m_pfn_qglVertex2f( 32, 18 ); - g_QglTable.m_pfn_qglVertex2f( 32 + cos(degInRad) * 5, 18 + sin(degInRad) * 5 ); - g_QglTable.m_pfn_qglEnd(); - - g_QglTable.m_pfn_qglBegin( GL_LINE_LOOP ); - for( i = 0; i < 360; i += 60 ) { - degInRad = i * (3.14159265358979323846/180.f); - g_QglTable.m_pfn_qglVertex2f( 32 + cos(degInRad) * 5, 18 + sin(degInRad) * 5 ); - } - g_QglTable.m_pfn_qglEnd(); - - g_QglTable.m_pfn_qglBegin( GL_LINES ); - g_QglTable.m_pfn_qglVertex2f( 40, 22 ); - g_QglTable.m_pfn_qglVertex2f( 52, 31 ); - g_QglTable.m_pfn_qglVertex2f( 40, 13 ); - g_QglTable.m_pfn_qglVertex2f( 52, 4 ); - g_QglTable.m_pfn_qglEnd(); - } - - g_QglTable.m_pfn_qglPopAttrib(); -} +/* +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 +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#include "camera.h" + +CRenderer::CRenderer() { + + refCount = 1; + + m_bHooked = FALSE; + + Register(); + Initialize(); +} + +CRenderer::~CRenderer() { + if( m_bHooked ) + UnRegister(); +} + +void CRenderer::Register() { + g_QglTable.m_pfnHookGL2DWindow( this ); + g_QglTable.m_pfnHookGL3DWindow( this ); + m_bHooked = TRUE; +} + +void CRenderer::UnRegister() { + if( g_QglTable.m_nSize ) { + g_QglTable.m_pfnUnHookGL2DWindow( this ); + g_QglTable.m_pfnUnHookGL3DWindow( this ); + } + m_bHooked = FALSE; +} + +void CRenderer::Initialize() { + +} + +void CRenderer::Draw2D( VIEWTYPE vt ) { + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + 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; + } + + CCamera *cam = firstCam; + while( cam ) { + cam->GetCam()->draw( ((Listener && cam == g_pCurrentEditCam) ? true : false) ); + cam = cam->GetNext(); + } + + g_QglTable.m_pfn_qglPopMatrix(); + g_QglTable.m_pfn_qglPopAttrib(); +} + +void CRenderer::Draw3D() { + // FIXME: really need a mainloop callback from the editor core + static long start; + static float cycle; + static long msecs; + static long current; + + if( g_iPreviewRunning ) { + if( g_iPreviewRunning == 1 ) { + start = g_FuncTable.m_pfnQGetTickCount(); + GetCurrentCam()->GetCam()->startCamera( start ); + cycle = GetCurrentCam()->GetCam()->getTotalTime(); + msecs = (long)(cycle * 1000); + current = start; + g_iPreviewRunning = 2; + } + + if( current < start + msecs ) { + float fov; + vec3_t origin = {0.0f, 0.0f, 0.0f}, dir = {0.0f, 0.0f, 0.0f}, angles; + + GetCurrentCam()->GetCam()->getCameraInfo( current, &origin[0], &dir[0], &fov ); + VectorSet( angles, asin (dir[2])*180/3.14159, atan2 (dir[1], dir[0])*180/3.14159, 0 ); + g_CameraTable.m_pfnSetCamera( origin, angles ); + current = g_FuncTable.m_pfnQGetTickCount(); + } else { + g_iPreviewRunning = 0; + GetCurrentCam()->GetCam()->setRunning( false ); + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + } + } + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + CCamera *cam = firstCam; + while( cam ) { + cam->GetCam()->draw( ((Listener && cam == g_pCurrentEditCam) ? true : false) ); + cam = cam->GetNext(); + } + + if( g_iPreviewRunning ) { + int x, y, width, height, i; + float degInRad; + + g_CameraTable.m_pfnGetCamWindowExtents( &x, &y, &width, &height ); + + // setup orthographic projection mode + g_QglTable.m_pfn_qglMatrixMode(GL_PROJECTION); + g_QglTable.m_pfn_qglLoadIdentity(); + g_QglTable.m_pfn_qglDisable( GL_DEPTH_TEST ); + g_QglTable.m_pfn_qglOrtho( 0, (float)width, 0, (float)height, -100, 100 ); + g_QglTable.m_pfn_qglMatrixMode( GL_MODELVIEW ); + + g_QglTable.m_pfn_qglLoadIdentity(); + g_QglTable.m_pfn_qglColor3f( 1.f, 1.f, 1.f ); + g_QglTable.m_pfn_qglBegin( GL_LINE_LOOP ); + g_QglTable.m_pfn_qglVertex2f( 10, 10 ); + g_QglTable.m_pfn_qglVertex2f( 40, 10 ); + g_QglTable.m_pfn_qglVertex2f( 40, 25 ); + g_QglTable.m_pfn_qglVertex2f( 10, 25 ); + g_QglTable.m_pfn_qglEnd(); + + g_QglTable.m_pfn_qglBegin( GL_LINE_LOOP ); + for( i = 0; i < 360; i += 60 ) { + degInRad = i * (3.14159265358979323846/180.f); + g_QglTable.m_pfn_qglVertex2f( 18 + cos(degInRad) * 5, 18 + sin(degInRad) * 5 ); + } + g_QglTable.m_pfn_qglEnd(); + + degInRad = (360-((current - start) % 360)) * (3.14159265358979323846/180.f); + g_QglTable.m_pfn_qglBegin( GL_LINES ); + g_QglTable.m_pfn_qglVertex2f( 18, 18 ); + g_QglTable.m_pfn_qglVertex2f( 18 + cos(degInRad) * 5, 18 + sin(degInRad) * 5 ); + g_QglTable.m_pfn_qglVertex2f( 32, 18 ); + g_QglTable.m_pfn_qglVertex2f( 32 + cos(degInRad) * 5, 18 + sin(degInRad) * 5 ); + g_QglTable.m_pfn_qglEnd(); + + g_QglTable.m_pfn_qglBegin( GL_LINE_LOOP ); + for( i = 0; i < 360; i += 60 ) { + degInRad = i * (3.14159265358979323846/180.f); + g_QglTable.m_pfn_qglVertex2f( 32 + cos(degInRad) * 5, 18 + sin(degInRad) * 5 ); + } + g_QglTable.m_pfn_qglEnd(); + + g_QglTable.m_pfn_qglBegin( GL_LINES ); + g_QglTable.m_pfn_qglVertex2f( 40, 22 ); + g_QglTable.m_pfn_qglVertex2f( 52, 31 ); + g_QglTable.m_pfn_qglVertex2f( 40, 13 ); + g_QglTable.m_pfn_qglVertex2f( 52, 4 ); + g_QglTable.m_pfn_qglEnd(); + } + + g_QglTable.m_pfn_qglPopAttrib(); +} diff --git a/contrib/gtkgensurf/bitmap.cpp b/contrib/gtkgensurf/bitmap.cpp index 93dcd282..bd5f6172 100644 --- a/contrib/gtkgensurf/bitmap.cpp +++ b/contrib/gtkgensurf/bitmap.cpp @@ -1,434 +1,434 @@ -/* -GenSurf plugin for GtkRadiant -Copyright (C) 2001 David Hyde, Loki software and qeradiant.com - -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 -*/ - -#include -#include -#include -#include "gensurf.h" - -void GenerateBitmapMapping () -{ - double value; - double C0, C1; - double x, y; - int i, j; - int O00,O01,O10,O11; - int r0, r1, c0, c1; - int color; - unsigned char *colors; - - if (!gbmp.colors) - return; - - colors = gbmp.colors; - - for (j=0; j<=NV; j++) - { - y = (double)(j*(gbmp.height-1))/(double)NV; - r0 = (int)floor(y); - r1 = (int)ceil(y); - for (i=0; i<=NH; i++) - { - x = (double)(i*(gbmp.width-1))/(double)NH; - c0 = (int)floor(x); - c1 = (int)ceil(x); - O00 = r0*gbmp.width + c0; - O01 = r0*gbmp.width + c1; - O10 = r1*gbmp.width + c0; - O11 = r1*gbmp.width + c1; - C0 = (double)colors[O00] + (double)(colors[O01]-colors[O00])*(x-(double)c0); - C1 = (double)colors[O10] + (double)(colors[O11]-colors[O10])*(x-(double)c0); - color = (int)(C0 + (C1-C0)*(y-r0)); - - value = CalculateSnapValue(gbmp.black_value + color*((gbmp.white_value-gbmp.black_value)/255.)); - - switch(Plane) - { - case PLANE_XZ0: - case PLANE_XZ1: - xyz[i][j].p[1] = value; - break; - case PLANE_YZ0: - case PLANE_YZ1: - xyz[i][j].p[0] = value; - break; - default: - xyz[i][j].p[2] = value; - } - } - } -} - -static unsigned char* OpenBitmapFile () -{ - int bmWidth; - int bmHeight; - unsigned char bmPlanes; - unsigned char bmBitsPixel; - unsigned char m1,m2; - unsigned long sizeimage; - short res1,res2; - long filesize, pixoff; - long bmisize, compression; - long xscale, yscale; - long colors, impcol; - unsigned long m_bytesRead = 0; - unsigned char *image; - FILE *fp; - - fp = fopen (gbmp.name, "rb"); - if (fp == NULL) - return NULL; - - long rc; - rc = fread(&m1, 1, 1, fp); - m_bytesRead++; - if (rc == -1) - { - fclose(fp); - return NULL; - } - - rc = fread(&m2, 1, 1, fp); - m_bytesRead++; - if ((m1 != 'B') || (m2 != 'M')) - { - fclose(fp); - return NULL; - } - - rc = fread((long*)&(filesize),4,1,fp); m_bytesRead+=4; - if (rc != 1) { fclose(fp); return NULL; } - - rc = fread((int*)&(res1),2,1,fp); m_bytesRead+=2; - if (rc != 1) { fclose(fp); return NULL; } - - rc = fread((int*)&(res2),2,1,fp); m_bytesRead+=2; - if (rc != 1) { fclose(fp); return NULL; } - - rc = fread((long*)&(pixoff),4,1,fp); m_bytesRead+=4; - if (rc != 1) { fclose(fp); return NULL; } - - rc = fread((long*)&(bmisize),4,1,fp); m_bytesRead+=4; - if (rc != 1) { fclose(fp); return NULL; } - - rc = fread((long *)&(bmWidth),4,1,fp); m_bytesRead+=4; - if (rc != 1) { fclose(fp); return NULL; } - - rc = fread((long*)&(bmHeight),4,1,fp); m_bytesRead+=4; - if (rc != 1) { fclose(fp); return NULL; } - - rc = fread((int*)&(bmPlanes),2,1,fp); m_bytesRead+=2; - if (rc != 1) { fclose(fp); return NULL; } - - rc = fread((int*)&(bmBitsPixel),2,1,fp); m_bytesRead+=2; - if (rc != 1) { fclose(fp); return NULL; } - - rc = fread((long*)&(compression),4,1,fp); m_bytesRead+=4; - if (rc != 1) { fclose(fp); return NULL; } - - rc = fread((long*)&(sizeimage),4,1,fp); m_bytesRead+=4; - if (rc != 1) {fclose(fp); return NULL; } - - rc = fread((long*)&(xscale),4,1,fp); m_bytesRead+=4; - if (rc != 1) { fclose(fp); return NULL; } - - rc = fread((long*)&(yscale),4,1,fp); m_bytesRead+=4; - if (rc != 1) { fclose(fp); return NULL; } - - rc = fread((long*)&(colors),4,1,fp); m_bytesRead+=4; - if (rc != 1) { fclose(fp); return NULL; } - - rc = fread((long*)&(impcol),4,1,fp); m_bytesRead+=4; - if (rc != 1) { fclose(fp); return NULL; } - - if (bmBitsPixel != 8) - { - g_FuncTable.m_pfnMessageBox (g_pWnd, "This is not an 8-bit image. GenSurf can't use it.", - "Bitmap", MB_ICONEXCLAMATION); - fclose(fp); - return NULL; - } - - if (colors == 0) - colors = 1 << bmBitsPixel; - - if (bmBitsPixel != 24) - { - int i; - for (i = 0; i < colors; i++) - { - unsigned char r ,g, b, dummy; - - rc = fread(&b, 1, 1, fp); - m_bytesRead++; - if (rc!=1) - { - fclose(fp); - return NULL; - } - - rc = fread(&g, 1, 1, fp); - m_bytesRead++; - if (rc!=1) - { - fclose(fp); - return NULL; - } - - rc = fread(&r, 1, 1, fp); - m_bytesRead++; - if (rc != 1) - { - fclose(fp); - return NULL; - } - - rc = fread(&dummy, 1, 1, fp); - m_bytesRead++; - if (rc != 1) - { - fclose(fp); - return NULL; - } - } - } - - if ((long)m_bytesRead > pixoff) - { - fclose(fp); - return NULL; - } - - while ((long)m_bytesRead < pixoff) - { - char dummy; - fread(&dummy,1,1,fp); - m_bytesRead++; - } - - int w = bmWidth; - int h = bmHeight; - - // set the output params - image = (unsigned char*)malloc(w*h); - - if (image != NULL) - { - gbmp.width = w; - gbmp.height = h; - unsigned char* outbuf = image; - long row = 0; - long rowOffset = 0; - - if (compression == 0) // BI_RGB - { - for (row = 0; row < bmHeight; row++) - { - // which row are we working on? - rowOffset = (long unsigned)row*w; - - { - // pixels are packed as 1 , 4 or 8 bit vals. need to unpack them - int bit_count = 0; - unsigned long mask = (1 << bmBitsPixel) - 1; - unsigned char inbyte = 0; - - for (int col=0;col> bit_count) & mask; - - // lookup the color from the colormap - stuff it in our buffer - // swap red and blue - *(outbuf + rowOffset + col) = pix; - } - - // read DWORD padding - while ((m_bytesRead-pixoff)&3) - { - char dummy; - if (fread(&dummy,1,1,fp)!=1) - { - free(image); - fclose(fp); - return NULL; - } - m_bytesRead++; - } - } - } - } - else // compression != 0 - { - int i, x = 0; - unsigned char c, c1 = 0, *pp; - row = 0; - pp = outbuf; - - if (bmBitsPixel == 8) - { - while (row < bmHeight) - { - c = getc(fp); - - if (c) - { - // encoded mode - c1 = getc(fp); - for (i = 0; i < c; x++, i++) - { - *pp = c1; pp++; - } - } - else - { - // c==0x00, escape codes - c = getc(fp); - - if (c == 0x00) // end of line - { - row++; - x = 0; - pp = outbuf + row*bmWidth; - } - else if (c == 0x01) - break; // end of pic - else if (c == 0x02) // delta - { - c = getc(fp); - x += c; - c = getc(fp); - row += c; - pp = outbuf + x + row*bmWidth; - } - else // absolute mode - { - for (i = 0; i < c; x++, i++) - { - c1 = getc(fp); - *pp = c1; pp++; - } - - if (c & 1) - getc(fp); // odd length run: read an extra pad byte - } - } - } - } - else if (bmBitsPixel == 4) - { - while (row < bmHeight) - { - c = getc(fp); - - if (c) - { - // encoded mode - c1 = getc(fp); - for (i = 0; i < c; x++, i++) - { - *pp = (i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f); pp++; - } - } - else - { - // c==0x00, escape codes - c = getc(fp); - - if (c == 0x00) // end of line - { - row++; - x = 0; - pp = outbuf + bmHeight*bmWidth; - } - else if (c == 0x01) - break; // end of pic - else if (c == 0x02) // delta - { - c = getc(fp); - x += c; - c = getc(fp); - row += c; - pp = outbuf + x + row*bmWidth; - } - else // absolute mode - { - for (i = 0; i < c; x++, i++) - { - if ((i&1) == 0) - c1 = getc(fp); - *pp = (i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f); pp++; - } - - if (((c&3) == 1) || ((c&3) == 2)) - getc(fp); // odd length run: read an extra pad byte - } - } - } - } - } - } - fclose(fp); - return image; -} - -bool OpenBitmap () -{ - if (gbmp.colors) - free (gbmp.colors); - - gbmp.colors = OpenBitmapFile (); - - if (!gbmp.colors) - { - char Text[256]; - - sprintf (Text, "Error opening %s", gbmp.name); - g_FuncTable.m_pfnMessageBox (g_pWnd, Text, "Bitmap", MB_ICONEXCLAMATION); - strcpy (gbmp.name, ""); - } - - if (g_pWnd) - { - gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "bmp_file")), gbmp.name); - gtk_widget_set_sensitive (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_reload")), - strlen (gbmp.name) ? TRUE : FALSE); - - UpdatePreview (true); - } - - return (gbmp.colors != NULL); -} +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +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 +*/ + +#include +#include +#include +#include "gensurf.h" + +void GenerateBitmapMapping () +{ + double value; + double C0, C1; + double x, y; + int i, j; + int O00,O01,O10,O11; + int r0, r1, c0, c1; + int color; + unsigned char *colors; + + if (!gbmp.colors) + return; + + colors = gbmp.colors; + + for (j=0; j<=NV; j++) + { + y = (double)(j*(gbmp.height-1))/(double)NV; + r0 = (int)floor(y); + r1 = (int)ceil(y); + for (i=0; i<=NH; i++) + { + x = (double)(i*(gbmp.width-1))/(double)NH; + c0 = (int)floor(x); + c1 = (int)ceil(x); + O00 = r0*gbmp.width + c0; + O01 = r0*gbmp.width + c1; + O10 = r1*gbmp.width + c0; + O11 = r1*gbmp.width + c1; + C0 = (double)colors[O00] + (double)(colors[O01]-colors[O00])*(x-(double)c0); + C1 = (double)colors[O10] + (double)(colors[O11]-colors[O10])*(x-(double)c0); + color = (int)(C0 + (C1-C0)*(y-r0)); + + value = CalculateSnapValue(gbmp.black_value + color*((gbmp.white_value-gbmp.black_value)/255.)); + + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + xyz[i][j].p[1] = value; + break; + case PLANE_YZ0: + case PLANE_YZ1: + xyz[i][j].p[0] = value; + break; + default: + xyz[i][j].p[2] = value; + } + } + } +} + +static unsigned char* OpenBitmapFile () +{ + int bmWidth; + int bmHeight; + unsigned char bmPlanes; + unsigned char bmBitsPixel; + unsigned char m1,m2; + unsigned long sizeimage; + short res1,res2; + long filesize, pixoff; + long bmisize, compression; + long xscale, yscale; + long colors, impcol; + unsigned long m_bytesRead = 0; + unsigned char *image; + FILE *fp; + + fp = fopen (gbmp.name, "rb"); + if (fp == NULL) + return NULL; + + long rc; + rc = fread(&m1, 1, 1, fp); + m_bytesRead++; + if (rc == -1) + { + fclose(fp); + return NULL; + } + + rc = fread(&m2, 1, 1, fp); + m_bytesRead++; + if ((m1 != 'B') || (m2 != 'M')) + { + fclose(fp); + return NULL; + } + + rc = fread((long*)&(filesize),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((int*)&(res1),2,1,fp); m_bytesRead+=2; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((int*)&(res2),2,1,fp); m_bytesRead+=2; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(pixoff),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(bmisize),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long *)&(bmWidth),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(bmHeight),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((int*)&(bmPlanes),2,1,fp); m_bytesRead+=2; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((int*)&(bmBitsPixel),2,1,fp); m_bytesRead+=2; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(compression),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(sizeimage),4,1,fp); m_bytesRead+=4; + if (rc != 1) {fclose(fp); return NULL; } + + rc = fread((long*)&(xscale),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(yscale),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(colors),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(impcol),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + if (bmBitsPixel != 8) + { + g_FuncTable.m_pfnMessageBox (g_pWnd, "This is not an 8-bit image. GenSurf can't use it.", + "Bitmap", MB_ICONEXCLAMATION); + fclose(fp); + return NULL; + } + + if (colors == 0) + colors = 1 << bmBitsPixel; + + if (bmBitsPixel != 24) + { + int i; + for (i = 0; i < colors; i++) + { + unsigned char r ,g, b, dummy; + + rc = fread(&b, 1, 1, fp); + m_bytesRead++; + if (rc!=1) + { + fclose(fp); + return NULL; + } + + rc = fread(&g, 1, 1, fp); + m_bytesRead++; + if (rc!=1) + { + fclose(fp); + return NULL; + } + + rc = fread(&r, 1, 1, fp); + m_bytesRead++; + if (rc != 1) + { + fclose(fp); + return NULL; + } + + rc = fread(&dummy, 1, 1, fp); + m_bytesRead++; + if (rc != 1) + { + fclose(fp); + return NULL; + } + } + } + + if ((long)m_bytesRead > pixoff) + { + fclose(fp); + return NULL; + } + + while ((long)m_bytesRead < pixoff) + { + char dummy; + fread(&dummy,1,1,fp); + m_bytesRead++; + } + + int w = bmWidth; + int h = bmHeight; + + // set the output params + image = (unsigned char*)malloc(w*h); + + if (image != NULL) + { + gbmp.width = w; + gbmp.height = h; + unsigned char* outbuf = image; + long row = 0; + long rowOffset = 0; + + if (compression == 0) // BI_RGB + { + for (row = 0; row < bmHeight; row++) + { + // which row are we working on? + rowOffset = (long unsigned)row*w; + + { + // pixels are packed as 1 , 4 or 8 bit vals. need to unpack them + int bit_count = 0; + unsigned long mask = (1 << bmBitsPixel) - 1; + unsigned char inbyte = 0; + + for (int col=0;col> bit_count) & mask; + + // lookup the color from the colormap - stuff it in our buffer + // swap red and blue + *(outbuf + rowOffset + col) = pix; + } + + // read DWORD padding + while ((m_bytesRead-pixoff)&3) + { + char dummy; + if (fread(&dummy,1,1,fp)!=1) + { + free(image); + fclose(fp); + return NULL; + } + m_bytesRead++; + } + } + } + } + else // compression != 0 + { + int i, x = 0; + unsigned char c, c1 = 0, *pp; + row = 0; + pp = outbuf; + + if (bmBitsPixel == 8) + { + while (row < bmHeight) + { + c = getc(fp); + + if (c) + { + // encoded mode + c1 = getc(fp); + for (i = 0; i < c; x++, i++) + { + *pp = c1; pp++; + } + } + else + { + // c==0x00, escape codes + c = getc(fp); + + if (c == 0x00) // end of line + { + row++; + x = 0; + pp = outbuf + row*bmWidth; + } + else if (c == 0x01) + break; // end of pic + else if (c == 0x02) // delta + { + c = getc(fp); + x += c; + c = getc(fp); + row += c; + pp = outbuf + x + row*bmWidth; + } + else // absolute mode + { + for (i = 0; i < c; x++, i++) + { + c1 = getc(fp); + *pp = c1; pp++; + } + + if (c & 1) + getc(fp); // odd length run: read an extra pad byte + } + } + } + } + else if (bmBitsPixel == 4) + { + while (row < bmHeight) + { + c = getc(fp); + + if (c) + { + // encoded mode + c1 = getc(fp); + for (i = 0; i < c; x++, i++) + { + *pp = (i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f); pp++; + } + } + else + { + // c==0x00, escape codes + c = getc(fp); + + if (c == 0x00) // end of line + { + row++; + x = 0; + pp = outbuf + bmHeight*bmWidth; + } + else if (c == 0x01) + break; // end of pic + else if (c == 0x02) // delta + { + c = getc(fp); + x += c; + c = getc(fp); + row += c; + pp = outbuf + x + row*bmWidth; + } + else // absolute mode + { + for (i = 0; i < c; x++, i++) + { + if ((i&1) == 0) + c1 = getc(fp); + *pp = (i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f); pp++; + } + + if (((c&3) == 1) || ((c&3) == 2)) + getc(fp); // odd length run: read an extra pad byte + } + } + } + } + } + } + fclose(fp); + return image; +} + +bool OpenBitmap () +{ + if (gbmp.colors) + free (gbmp.colors); + + gbmp.colors = OpenBitmapFile (); + + if (!gbmp.colors) + { + char Text[256]; + + sprintf (Text, "Error opening %s", gbmp.name); + g_FuncTable.m_pfnMessageBox (g_pWnd, Text, "Bitmap", MB_ICONEXCLAMATION); + strcpy (gbmp.name, ""); + } + + if (g_pWnd) + { + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "bmp_file")), gbmp.name); + gtk_widget_set_sensitive (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_reload")), + strlen (gbmp.name) ? TRUE : FALSE); + + UpdatePreview (true); + } + + return (gbmp.colors != NULL); +} diff --git a/contrib/gtkgensurf/dec.cpp b/contrib/gtkgensurf/dec.cpp index 4dbedf8c..c8569a6e 100644 --- a/contrib/gtkgensurf/dec.cpp +++ b/contrib/gtkgensurf/dec.cpp @@ -1,1328 +1,1328 @@ -/* -GenSurf plugin for GtkRadiant -Copyright (C) 2001 David Hyde, Loki software and qeradiant.com - -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 -*/ - -#define SINGLE -#ifdef SINGLE -#define REAL float -#else /* not SINGLE */ -#define REAL double -#endif /* not SINGLE */ - -#include -#include -#include -#include "gensurf.h" -#include "triangle.h" - -typedef struct -{ - float error; - int node; -} TRITABLE; - -double dh, dv; -int NVP1; - -#define Absolute(a) ((a) >= 0.0 ? (a) : -(a)) - -void MakeDecimatedMap(int *NumNodes, int *NumTris, NODE **pNode, TRI **pTri) -{ - int compare(TRITABLE *, TRITABLE *); - int Bisect(NODE *, int, int, int); - void CalcAngles(NODE *, int *, float *); - void EdgeOnSide(int *, int *, int *); - int tricall(int, NODE *, int *, TRI **, TRI **, char *); - int CheckBorders(int *,int,NODE *,int *,TRI **); - - float biggesterror; - int i, j, N; - int j0, j1, j2; - int NumNodesToSave; - int NumNodesUsed; - NODE *Node; - TRI *Tri; - TRITABLE *TriTable; - - if(Decimate <= 0) return; - /* - ghCursorCurrent = LoadCursor(NULL,IDC_WAIT); - SetCursor(ghCursorCurrent); - */ - dh = (Hur-Hll)/NH; - dv = (Vur-Vll)/NV; - NVP1 = NV+1; - - NumNodes[0] = (NH+1)*(NVP1); - *pNode = (NODE *) malloc(NumNodes[0] * sizeof(NODE)); - Node = *pNode; - memset(Node,0,NumNodes[0]*sizeof(NODE)); - - // Copy [NH][NV] vertex array to our working node array - for(i=0,N=0; i<=NH; i++) - { - for(j=0; j<=NV; j++, N++) - { - Node[N].p[0] = (float)xyz[i][j].p[0]; - Node[N].p[1] = (float)xyz[i][j].p[1]; - Node[N].p[2] = (float)xyz[i][j].p[2]; - Node[N].fixed = xyz[i][j].fixed; - } - } - // Start things off with the corner values - Node[ 0].used = 1; - Node[NV].used = 1; - Node[NH*NVP1].used = 1; - Node[NH*NVP1+NV].used = 1; - NumNodesUsed = 4; - tricall(NumNodes[0], Node, NumTris, NULL, pTri, "cnzBNPY"); - Tri = *pTri; - - // Which coordinates are we triangulating on? - switch(Plane) - { - case PLANE_XZ0: - case PLANE_XZ1: - j0 = 1; - j1 = 0; - j2 = 2; - break; - case PLANE_YZ0: - case PLANE_YZ1: - j0 = 0; - j1 = 1; - j2 = 2; - break; - default: - j0 = 2; - j1 = 0; - j2 = 1; - } - - // TriTable stores the largest error in a triangle and the node where that - // error occurs - TriTable = (TRITABLE *) malloc(NH*NV*2 * sizeof(TRITABLE)); - NumNodesToSave = min(NumNodes[0], (int)(0.01*(100-Decimate)*(NumNodes[0]-NumNodesUsed)+NumNodesUsed)); - - while(NumNodesUsed < NumNodesToSave) - { - for(i=0; i TriTable[Node[i].tri].error) - { - TriTable[Node[i].tri].error = (float)(Absolute(Node[i].error)); - TriTable[Node[i].tri].node = i; - } - } - qsort( (void *)TriTable, (size_t)(NumTris[0]), sizeof(TRITABLE), (int (*)(const void *, const void *))compare ); - for(i=0; i 0.5*biggesterror; i++) - { - if(Node[TriTable[i].node].used) continue; // shouldn't happen - NumNodesUsed++; - Node[TriTable[i].node].used++; - } - free(Tri); - tricall(NumNodes[0], Node, NumTris, NULL, pTri, "cnzBNPY"); - Tri = *pTri; - // Sliver-check along borders. Since borders are often linear, the errors - // along borders will often be zero, so no new points will be added. This - // tends to produce long, thin brushes. For all border triangles, check - // that minimum angle isn't less than SLIVER_ANGLE. If it is, add another - // vertex. - while(CheckBorders(&NumNodesUsed,NumNodes[0],Node,NumTris,pTri) > 0) - { - } - Tri = *pTri; - } - } - free(TriTable); - // One last time (because we're pessimistic), check border triangles -// CheckBorders(&NumNodesUsed,NumNodes[0],Node,NumTris,pTri); -// Tri = *pTri; - - // Check that all fixed points are exact. If not, add them to the mix. - // First check to see if we have any fixed points that aren't already used. - for(i=0, N=0; i 0.5) - { - NumNodesUsed++; - Node[i].used++; - free(Tri); - tricall(NumNodes[0], Node, NumTris, NULL, pTri, "cnzBNPY"); - Tri = *pTri; - } - } - } - - // Swap node orders for surfaces facing down, north or west so that - // they are counterclockwise when facing the surface - - if((Plane == PLANE_XY1) || (Plane == PLANE_XZ0) || (Plane == PLANE_YZ1) ) - { - for(i=0; i= R) && (v[1] >= R) ) - { - edge[0] = 0; - border[0] = 1; - } - if( (v[1] >= R) && (v[2] >= R) ) - { - edge[0] = 1; - border[0] = 1; - } - if( (v[2] >= R) && (v[0] >= R) ) - { - edge[0] = 2; - border[0] = 1; - } - - if(border[0] >= 0) - { - k0 = edge[0]; - k1 = (k0+1) % 3; - N = Absolute(v[k0] - v[k1]); - Ndv = (float)(N*dv); - } - if( ((v[0] % NVP1) == 0) && ((v[1] % NVP1) == 0) ) - { - if(border[0] >= 0) - if( Ndv > (Absolute(v[0] - v[1])*dh)) return; - edge[0] = 0; - border[0] = 2; - return; - } - if( ((v[1] % NVP1) == 0) && ((v[2] % NVP1) == 0) ) - { - if(border[0] >= 0) - if( Ndv > (Absolute(v[1] - v[2])*dh)) return; - edge[0] = 1; - border[0] = 2; - return; - } - if( ((v[2] % NVP1) == 0) && ((v[0] % NVP1) == 0) ) - { - if(border[0] >= 0) - if( Ndv > (Absolute(v[2] - v[0])*dh)) return; - edge[0] = 2; - border[0] = 2; - return; - } - - if( ((v[0] % NVP1) == NV) && ((v[1] % NVP1) == NV) ) - { - if(border[0] >= 0) - if( Ndv > (Absolute(v[0] - v[1])*dh)) return; - edge[0] = 0; - border[0] = 3; - return; - } - if( ((v[1] % NVP1) == NV) && ((v[2] % NVP1) == NV) ) - { - if(border[0] >= 0) - if( Ndv > (Absolute(v[1] - v[2])*dh)) return; - edge[0] = 1; - border[0] = 3; - return; - } - if( ((v[2] % NVP1) == NV) && ((v[0] % NVP1) == NV) ) - { - if(border[0] >= 0) - if( Ndv > (Absolute(v[2] - v[0])*dh)) return; - edge[0] = 2; - border[0] = 3; - return; - } - return; -} - -void CalcAngles(NODE *node, int *v, float *angle) -{ - int i, j, k; - vec l; - vec x0, x1, x2, y0, y1, y2; - vec2 vv[3]; - vec dot; - - switch(Plane) - { - case PLANE_XZ0: - case PLANE_XZ1: - i = 0; - j = 2; - break; - case PLANE_YZ0: - case PLANE_YZ1: - i = 1; - j = 2; - break; - default: - i = 0; - j = 1; - } - x0 = node[v[0]].p[i]; - x1 = node[v[1]].p[i]; - x2 = node[v[2]].p[i]; - y0 = node[v[0]].p[j]; - y1 = node[v[1]].p[j]; - y2 = node[v[2]].p[j]; - - vv[0][0] = x1-x0; - vv[0][1] = y1-y0; - vv[1][0] = x2-x1; - vv[1][1] = y2-y1; - vv[2][0] = x0-x2; - vv[2][1] = y0-y2; - - for(k=0; k<3; k++) - { - l = (vec)(sqrt( vv[k][0]*vv[k][0] + vv[k][1]*vv[k][1] )); - if(l > 0.) - { - vv[k][0] /= l; - vv[k][1] /= l; - } - } - - dot = -(vv[0][0]*vv[2][0] + vv[0][1]*vv[2][1]); - angle[0] = (float)(acos(dot)); - dot = -(vv[1][0]*vv[0][0] + vv[1][1]*vv[0][1]); - angle[1] = (float)(acos(dot)); - dot = -(vv[2][0]*vv[1][0] + vv[2][1]*vv[1][1]); - angle[2] = (float)(acos(dot)); -} -//================================================================= -int Bisect(NODE *node, int border, int j0, int j1) -{ - int k; - - switch(border) - { - case 0: - k = (j0+j1)/2; - break; - case 1: - k = (j0+j1)/2; - break; - case 2: - k = (int)((j0+j1)/(2*NVP1)) * NVP1; - break; - case 3: - k = (int)((j0+j1+2)/(2*NVP1)) * NVP1 - 1; - break; - } - return( ((k != j0) && (k != j1)) ? k : 0 ); -} -//================================================================= -int compare(TRITABLE *t1, TRITABLE *t2) -{ - if(t1->error > t2->error) return -1; - if(t1->error < t2->error) return 1; - return 0; -} - -void MakeBrushes(int NumTris, NODE *Node, TRI *Tri,bool surf, - int offset,char *texture0, char *texture1, char *texture2) -{ - extern double backface; - BRUSH brush; - int contents; - int i, j; - float Steep; - vec3_t PlaneNormal,SurfNormal; - bool CheckAngle; - vec3_t t[2]; - - // if texture2 is identical to texture0, there's no need to - // check surface angle - if(!g_strcasecmp(texture0,texture2) || !strlen(texture2)) - CheckAngle = FALSE; - else - { - CheckAngle = TRUE; - Steep = (float)cos((double)SlantAngle/57.2957795); - switch(Plane) - { - case PLANE_XY0: PlaneNormal[0]= 0.;PlaneNormal[1]= 0.;PlaneNormal[2]= 1.;break; - case PLANE_XY1: PlaneNormal[0]= 0.;PlaneNormal[1]= 0.;PlaneNormal[2]=-1.;break; - case PLANE_XZ0: PlaneNormal[0]= 0.;PlaneNormal[1]= 1.;PlaneNormal[2]= 1.;break; - case PLANE_XZ1: PlaneNormal[0]= 0.;PlaneNormal[1]=-1.;PlaneNormal[2]= 1.;break; - case PLANE_YZ0: PlaneNormal[0]= 1.;PlaneNormal[1]= 0.;PlaneNormal[2]= 1.;break; - case PLANE_YZ1: PlaneNormal[0]=-1.;PlaneNormal[1]= 0.;PlaneNormal[2]= 1.;break; - } - } - - contents = 0; - if(surf) - { - if(UseDetail) contents += CONTENTS_DETAIL; - if(UseLadder) contents += CONTENTS_LADDER; - } - - OpenFuncGroup(); - for(i=0; i= max(Node[q[0]].p[j1],Node[q[2]].p[j1])) continue; - if(Tri[k].min[j2] >= max(Node[q[0]].p[j2],Node[q[2]].p[j2])) continue; - if(Tri[k].max[j1] <= min(Node[q[0]].p[j1],Node[q[2]].p[j1])) continue; - if(Tri[k].max[j2] <= min(Node[q[0]].p[j2],Node[q[2]].p[j2])) continue; - - for(h0=0; h0<4 && OK; h0++) - { - h1 = (h0+1)%4; - for(t=0; t<3 && OK; t++) - { - s[t] = side(Node[q[h0]].p[j1],Node[q[h0]].p[j2], - Node[q[h1]].p[j1],Node[q[h1]].p[j2], - Node[Tri[k].v[t]].p[j1],Node[Tri[k].v[t]].p[j2]); - } - if((s[1] > 0 || s[2] > 0) && s[0] < 0) OK=0; - if((s[2] > 0 || s[0] > 0) && s[1] < 0) OK=0; - if((s[0] > 0 || s[1] > 0) && s[2] < 0) OK=0; - } - } - if(!OK) continue; - switch(Plane) - { - case PLANE_XZ0: - case PLANE_XZ1: - // front - brush.face[0].v[0][0] = Node[q[2]].p[0]; - brush.face[0].v[0][1] = (float)front; - brush.face[0].v[0][2] = Node[q[2]].p[2]; - - brush.face[0].v[1][0] = Node[q[1]].p[0]; - brush.face[0].v[1][1] = (float)front; - brush.face[0].v[1][2] = Node[q[1]].p[2]; - - brush.face[0].v[2][0] = Node[q[0]].p[0]; - brush.face[0].v[2][1] = (float)front; - brush.face[0].v[2][2] = Node[q[0]].p[2]; - - // back - brush.face[1].v[0][0] = Node[q[0]].p[0]; - brush.face[1].v[0][1] = (float)backface; - brush.face[1].v[0][2] = Node[q[0]].p[2]; - - brush.face[1].v[1][0] = Node[q[1]].p[0]; - brush.face[1].v[1][1] = (float)backface; - brush.face[1].v[1][2] = Node[q[1]].p[2]; - - brush.face[1].v[2][0] = Node[q[2]].p[0]; - brush.face[1].v[2][1] = (float)backface; - brush.face[1].v[2][2] = Node[q[2]].p[2]; - - for(k0=0; k0= 0) - { - if(!Node[j].used) // Shouldn't be used, but... - { - NumNodesUsed[0]++; - Node[j].used++; - } - } - } - } - if(NumNodesUsed[0] > N) - { - free(*pTri); - tricall(NumNodes, Node, NumTris, NULL, pTri, "cnzBNPY"); - Tri = *pTri; - } - return (NumNodesUsed[0] - N); -} +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +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 +*/ + +#define SINGLE +#ifdef SINGLE +#define REAL float +#else /* not SINGLE */ +#define REAL double +#endif /* not SINGLE */ + +#include +#include +#include +#include "gensurf.h" +#include "triangle.h" + +typedef struct +{ + float error; + int node; +} TRITABLE; + +double dh, dv; +int NVP1; + +#define Absolute(a) ((a) >= 0.0 ? (a) : -(a)) + +void MakeDecimatedMap(int *NumNodes, int *NumTris, NODE **pNode, TRI **pTri) +{ + int compare(TRITABLE *, TRITABLE *); + int Bisect(NODE *, int, int, int); + void CalcAngles(NODE *, int *, float *); + void EdgeOnSide(int *, int *, int *); + int tricall(int, NODE *, int *, TRI **, TRI **, char *); + int CheckBorders(int *,int,NODE *,int *,TRI **); + + float biggesterror; + int i, j, N; + int j0, j1, j2; + int NumNodesToSave; + int NumNodesUsed; + NODE *Node; + TRI *Tri; + TRITABLE *TriTable; + + if(Decimate <= 0) return; + /* + ghCursorCurrent = LoadCursor(NULL,IDC_WAIT); + SetCursor(ghCursorCurrent); + */ + dh = (Hur-Hll)/NH; + dv = (Vur-Vll)/NV; + NVP1 = NV+1; + + NumNodes[0] = (NH+1)*(NVP1); + *pNode = (NODE *) malloc(NumNodes[0] * sizeof(NODE)); + Node = *pNode; + memset(Node,0,NumNodes[0]*sizeof(NODE)); + + // Copy [NH][NV] vertex array to our working node array + for(i=0,N=0; i<=NH; i++) + { + for(j=0; j<=NV; j++, N++) + { + Node[N].p[0] = (float)xyz[i][j].p[0]; + Node[N].p[1] = (float)xyz[i][j].p[1]; + Node[N].p[2] = (float)xyz[i][j].p[2]; + Node[N].fixed = xyz[i][j].fixed; + } + } + // Start things off with the corner values + Node[ 0].used = 1; + Node[NV].used = 1; + Node[NH*NVP1].used = 1; + Node[NH*NVP1+NV].used = 1; + NumNodesUsed = 4; + tricall(NumNodes[0], Node, NumTris, NULL, pTri, "cnzBNPY"); + Tri = *pTri; + + // Which coordinates are we triangulating on? + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + j0 = 1; + j1 = 0; + j2 = 2; + break; + case PLANE_YZ0: + case PLANE_YZ1: + j0 = 0; + j1 = 1; + j2 = 2; + break; + default: + j0 = 2; + j1 = 0; + j2 = 1; + } + + // TriTable stores the largest error in a triangle and the node where that + // error occurs + TriTable = (TRITABLE *) malloc(NH*NV*2 * sizeof(TRITABLE)); + NumNodesToSave = min(NumNodes[0], (int)(0.01*(100-Decimate)*(NumNodes[0]-NumNodesUsed)+NumNodesUsed)); + + while(NumNodesUsed < NumNodesToSave) + { + for(i=0; i TriTable[Node[i].tri].error) + { + TriTable[Node[i].tri].error = (float)(Absolute(Node[i].error)); + TriTable[Node[i].tri].node = i; + } + } + qsort( (void *)TriTable, (size_t)(NumTris[0]), sizeof(TRITABLE), (int (*)(const void *, const void *))compare ); + for(i=0; i 0.5*biggesterror; i++) + { + if(Node[TriTable[i].node].used) continue; // shouldn't happen + NumNodesUsed++; + Node[TriTable[i].node].used++; + } + free(Tri); + tricall(NumNodes[0], Node, NumTris, NULL, pTri, "cnzBNPY"); + Tri = *pTri; + // Sliver-check along borders. Since borders are often linear, the errors + // along borders will often be zero, so no new points will be added. This + // tends to produce long, thin brushes. For all border triangles, check + // that minimum angle isn't less than SLIVER_ANGLE. If it is, add another + // vertex. + while(CheckBorders(&NumNodesUsed,NumNodes[0],Node,NumTris,pTri) > 0) + { + } + Tri = *pTri; + } + } + free(TriTable); + // One last time (because we're pessimistic), check border triangles +// CheckBorders(&NumNodesUsed,NumNodes[0],Node,NumTris,pTri); +// Tri = *pTri; + + // Check that all fixed points are exact. If not, add them to the mix. + // First check to see if we have any fixed points that aren't already used. + for(i=0, N=0; i 0.5) + { + NumNodesUsed++; + Node[i].used++; + free(Tri); + tricall(NumNodes[0], Node, NumTris, NULL, pTri, "cnzBNPY"); + Tri = *pTri; + } + } + } + + // Swap node orders for surfaces facing down, north or west so that + // they are counterclockwise when facing the surface + + if((Plane == PLANE_XY1) || (Plane == PLANE_XZ0) || (Plane == PLANE_YZ1) ) + { + for(i=0; i= R) && (v[1] >= R) ) + { + edge[0] = 0; + border[0] = 1; + } + if( (v[1] >= R) && (v[2] >= R) ) + { + edge[0] = 1; + border[0] = 1; + } + if( (v[2] >= R) && (v[0] >= R) ) + { + edge[0] = 2; + border[0] = 1; + } + + if(border[0] >= 0) + { + k0 = edge[0]; + k1 = (k0+1) % 3; + N = Absolute(v[k0] - v[k1]); + Ndv = (float)(N*dv); + } + if( ((v[0] % NVP1) == 0) && ((v[1] % NVP1) == 0) ) + { + if(border[0] >= 0) + if( Ndv > (Absolute(v[0] - v[1])*dh)) return; + edge[0] = 0; + border[0] = 2; + return; + } + if( ((v[1] % NVP1) == 0) && ((v[2] % NVP1) == 0) ) + { + if(border[0] >= 0) + if( Ndv > (Absolute(v[1] - v[2])*dh)) return; + edge[0] = 1; + border[0] = 2; + return; + } + if( ((v[2] % NVP1) == 0) && ((v[0] % NVP1) == 0) ) + { + if(border[0] >= 0) + if( Ndv > (Absolute(v[2] - v[0])*dh)) return; + edge[0] = 2; + border[0] = 2; + return; + } + + if( ((v[0] % NVP1) == NV) && ((v[1] % NVP1) == NV) ) + { + if(border[0] >= 0) + if( Ndv > (Absolute(v[0] - v[1])*dh)) return; + edge[0] = 0; + border[0] = 3; + return; + } + if( ((v[1] % NVP1) == NV) && ((v[2] % NVP1) == NV) ) + { + if(border[0] >= 0) + if( Ndv > (Absolute(v[1] - v[2])*dh)) return; + edge[0] = 1; + border[0] = 3; + return; + } + if( ((v[2] % NVP1) == NV) && ((v[0] % NVP1) == NV) ) + { + if(border[0] >= 0) + if( Ndv > (Absolute(v[2] - v[0])*dh)) return; + edge[0] = 2; + border[0] = 3; + return; + } + return; +} + +void CalcAngles(NODE *node, int *v, float *angle) +{ + int i, j, k; + vec l; + vec x0, x1, x2, y0, y1, y2; + vec2 vv[3]; + vec dot; + + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + i = 0; + j = 2; + break; + case PLANE_YZ0: + case PLANE_YZ1: + i = 1; + j = 2; + break; + default: + i = 0; + j = 1; + } + x0 = node[v[0]].p[i]; + x1 = node[v[1]].p[i]; + x2 = node[v[2]].p[i]; + y0 = node[v[0]].p[j]; + y1 = node[v[1]].p[j]; + y2 = node[v[2]].p[j]; + + vv[0][0] = x1-x0; + vv[0][1] = y1-y0; + vv[1][0] = x2-x1; + vv[1][1] = y2-y1; + vv[2][0] = x0-x2; + vv[2][1] = y0-y2; + + for(k=0; k<3; k++) + { + l = (vec)(sqrt( vv[k][0]*vv[k][0] + vv[k][1]*vv[k][1] )); + if(l > 0.) + { + vv[k][0] /= l; + vv[k][1] /= l; + } + } + + dot = -(vv[0][0]*vv[2][0] + vv[0][1]*vv[2][1]); + angle[0] = (float)(acos(dot)); + dot = -(vv[1][0]*vv[0][0] + vv[1][1]*vv[0][1]); + angle[1] = (float)(acos(dot)); + dot = -(vv[2][0]*vv[1][0] + vv[2][1]*vv[1][1]); + angle[2] = (float)(acos(dot)); +} +//================================================================= +int Bisect(NODE *node, int border, int j0, int j1) +{ + int k; + + switch(border) + { + case 0: + k = (j0+j1)/2; + break; + case 1: + k = (j0+j1)/2; + break; + case 2: + k = (int)((j0+j1)/(2*NVP1)) * NVP1; + break; + case 3: + k = (int)((j0+j1+2)/(2*NVP1)) * NVP1 - 1; + break; + } + return( ((k != j0) && (k != j1)) ? k : 0 ); +} +//================================================================= +int compare(TRITABLE *t1, TRITABLE *t2) +{ + if(t1->error > t2->error) return -1; + if(t1->error < t2->error) return 1; + return 0; +} + +void MakeBrushes(int NumTris, NODE *Node, TRI *Tri,bool surf, + int offset,char *texture0, char *texture1, char *texture2) +{ + extern double backface; + BRUSH brush; + int contents; + int i, j; + float Steep; + vec3_t PlaneNormal,SurfNormal; + bool CheckAngle; + vec3_t t[2]; + + // if texture2 is identical to texture0, there's no need to + // check surface angle + if(!g_strcasecmp(texture0,texture2) || !strlen(texture2)) + CheckAngle = FALSE; + else + { + CheckAngle = TRUE; + Steep = (float)cos((double)SlantAngle/57.2957795); + switch(Plane) + { + case PLANE_XY0: PlaneNormal[0]= 0.;PlaneNormal[1]= 0.;PlaneNormal[2]= 1.;break; + case PLANE_XY1: PlaneNormal[0]= 0.;PlaneNormal[1]= 0.;PlaneNormal[2]=-1.;break; + case PLANE_XZ0: PlaneNormal[0]= 0.;PlaneNormal[1]= 1.;PlaneNormal[2]= 1.;break; + case PLANE_XZ1: PlaneNormal[0]= 0.;PlaneNormal[1]=-1.;PlaneNormal[2]= 1.;break; + case PLANE_YZ0: PlaneNormal[0]= 1.;PlaneNormal[1]= 0.;PlaneNormal[2]= 1.;break; + case PLANE_YZ1: PlaneNormal[0]=-1.;PlaneNormal[1]= 0.;PlaneNormal[2]= 1.;break; + } + } + + contents = 0; + if(surf) + { + if(UseDetail) contents += CONTENTS_DETAIL; + if(UseLadder) contents += CONTENTS_LADDER; + } + + OpenFuncGroup(); + for(i=0; i= max(Node[q[0]].p[j1],Node[q[2]].p[j1])) continue; + if(Tri[k].min[j2] >= max(Node[q[0]].p[j2],Node[q[2]].p[j2])) continue; + if(Tri[k].max[j1] <= min(Node[q[0]].p[j1],Node[q[2]].p[j1])) continue; + if(Tri[k].max[j2] <= min(Node[q[0]].p[j2],Node[q[2]].p[j2])) continue; + + for(h0=0; h0<4 && OK; h0++) + { + h1 = (h0+1)%4; + for(t=0; t<3 && OK; t++) + { + s[t] = side(Node[q[h0]].p[j1],Node[q[h0]].p[j2], + Node[q[h1]].p[j1],Node[q[h1]].p[j2], + Node[Tri[k].v[t]].p[j1],Node[Tri[k].v[t]].p[j2]); + } + if((s[1] > 0 || s[2] > 0) && s[0] < 0) OK=0; + if((s[2] > 0 || s[0] > 0) && s[1] < 0) OK=0; + if((s[0] > 0 || s[1] > 0) && s[2] < 0) OK=0; + } + } + if(!OK) continue; + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + // front + brush.face[0].v[0][0] = Node[q[2]].p[0]; + brush.face[0].v[0][1] = (float)front; + brush.face[0].v[0][2] = Node[q[2]].p[2]; + + brush.face[0].v[1][0] = Node[q[1]].p[0]; + brush.face[0].v[1][1] = (float)front; + brush.face[0].v[1][2] = Node[q[1]].p[2]; + + brush.face[0].v[2][0] = Node[q[0]].p[0]; + brush.face[0].v[2][1] = (float)front; + brush.face[0].v[2][2] = Node[q[0]].p[2]; + + // back + brush.face[1].v[0][0] = Node[q[0]].p[0]; + brush.face[1].v[0][1] = (float)backface; + brush.face[1].v[0][2] = Node[q[0]].p[2]; + + brush.face[1].v[1][0] = Node[q[1]].p[0]; + brush.face[1].v[1][1] = (float)backface; + brush.face[1].v[1][2] = Node[q[1]].p[2]; + + brush.face[1].v[2][0] = Node[q[2]].p[0]; + brush.face[1].v[2][1] = (float)backface; + brush.face[1].v[2][2] = Node[q[2]].p[2]; + + for(k0=0; k0= 0) + { + if(!Node[j].used) // Shouldn't be used, but... + { + NumNodesUsed[0]++; + Node[j].used++; + } + } + } + } + if(NumNodesUsed[0] > N) + { + free(*pTri); + tricall(NumNodes, Node, NumTris, NULL, pTri, "cnzBNPY"); + Tri = *pTri; + } + return (NumNodesUsed[0] - N); +} diff --git a/contrib/gtkgensurf/face.cpp b/contrib/gtkgensurf/face.cpp index 6c43c677..8a5aa822 100644 --- a/contrib/gtkgensurf/face.cpp +++ b/contrib/gtkgensurf/face.cpp @@ -1,450 +1,450 @@ -/* -GenSurf plugin for GtkRadiant -Copyright (C) 2001 David Hyde, Loki software and qeradiant.com - -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 -*/ - -#include -#include -#include "gensurf.h" - -#define MAX_FACES 128 // Maximum number of faces on a brush -#define MAX_POINTS_ON_WINDING 64 -#define SIDE_FRONT 0 -#define SIDE_ON 2 -#define SIDE_BACK 1 -#define SIDE_CROSS -2 - -vec3 vec3_origin = {0,0,0}; - -void PlaneFromPoints (float *p0, float *p1, float *p2, PLANE *plane) -{ - vec3 t1, t2; - vec length; - - VectorSubtract (p0, p1, t1); - VectorSubtract (p2, p1, t2); - plane->normal[0] = t1[1]*t2[2] - t1[2]*t2[1]; - plane->normal[1] = t1[2]*t2[0] - t1[0]*t2[2]; - plane->normal[2] = t1[0]*t2[1] - t1[1]*t2[0]; - - length = (vec)(sqrt(plane->normal[0]*plane->normal[0] + - plane->normal[1]*plane->normal[1] + - plane->normal[2]*plane->normal[2] )); - if (length == 0) - { - VectorClear(plane->normal); - } - else - { - plane->normal[0] /= length; - plane->normal[1] /= length; - plane->normal[2] /= length; - } - plane->dist = DotProduct (p0, plane->normal); -} - -void VectorMA (vec3 va, vec scale, vec3 vb, vec3 vc) -{ - vc[0] = va[0] + scale*vb[0]; - vc[1] = va[1] + scale*vb[1]; - vc[2] = va[2] + scale*vb[2]; -} - -void CrossProduct (vec3 v1, vec3 v2, vec3 cross) -{ - cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; - cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; - cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; -} - -/* -============= -AllocWinding -============= -*/ -MY_WINDING *AllocWinding (int points) -{ - MY_WINDING *w; - int s; - - s = sizeof(vec)*3*points + sizeof(int); - w = (MY_WINDING*)malloc (s); - memset (w, 0, s); - return w; -} - -vec VectorNormalize (vec3 in, vec3 out) -{ - vec length, ilength; - - length = (vec)(sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2])); - if (length == 0) - { - VectorClear (out); - return 0; - } - - ilength = (vec)1.0/length; - out[0] = in[0]*ilength; - out[1] = in[1]*ilength; - out[2] = in[2]*ilength; - - return length; -} - -/* -================= -BaseWindingForPlane -================= -*/ -MY_WINDING *BaseWindingForPlane (vec3 normal, vec dist) -{ - int i, x; - vec max, v; - vec3 org, vright, vup; - MY_WINDING *w; - -// find the major axis - - max = -BOGUS_RANGE; - x = -1; - for (i=0 ; i<3; i++) - { - v = (vec)(fabs(normal[i])); - if (v > max) - { - x = i; - max = v; - } - } - if (x==-1) x = 2; - - VectorCopy(vec3_origin,vup); - switch (x) - { - case 0: - case 1: - vup[2] = 1; - break; - case 2: - vup[0] = 1; - break; - } - - v = DotProduct (vup, normal); - VectorMA (vup, -v, normal, vup); - VectorNormalize (vup, vup); - - VectorScale (normal, dist, org); - - CrossProduct (vup, normal, vright); - - VectorScale (vup, 65536, vup); - VectorScale (vright, 65536, vright); - -// project a really big axis aligned box onto the plane - w = AllocWinding (4); - - VectorSubtract (org, vright, w->p[0]); - VectorAdd (w->p[0], vup, w->p[0]); - - VectorAdd (org, vright, w->p[1]); - VectorAdd (w->p[1], vup, w->p[1]); - - VectorAdd (org, vright, w->p[2]); - VectorSubtract (w->p[2], vup, w->p[2]); - - VectorSubtract (org, vright, w->p[3]); - VectorSubtract (w->p[3], vup, w->p[3]); - - w->numpoints = 4; - - return w; -} - -void FreeWinding (MY_WINDING *w) -{ - if (*(unsigned *)w == 0xdeaddead) -// Error ("FreeWinding: freed a freed winding"); - return; - *(unsigned *)w = 0xdeaddead; - - free (w); -} - -/* -============= -ChopWindingInPlace -============= -*/ -void ChopWindingInPlace (MY_WINDING **inout, vec3 normal, vec dist, vec epsilon) -{ - MY_WINDING *in; - vec dists[MAX_POINTS_ON_WINDING+4]; - int sides[MAX_POINTS_ON_WINDING+4]; - int counts[3]; - static vec dot; // VC 4.2 optimizer bug if not static - int i, j; - vec *p1, *p2; - vec3 mid; - MY_WINDING *f; - int maxpts; - - in = *inout; - counts[0] = counts[1] = counts[2] = 0; - -// determine sides for each point - for (i=0 ; inumpoints ; i++) - { - dot = DotProduct (in->p[i], normal); - dot -= dist; - dists[i] = dot; - if (dot > epsilon) - sides[i] = SIDE_FRONT; - else if (dot < -epsilon) - sides[i] = SIDE_BACK; - else - { - sides[i] = SIDE_ON; - } - counts[sides[i]]++; - } - sides[i] = sides[0]; - dists[i] = dists[0]; - - if (!counts[0]) - { - FreeWinding(in); - *inout = NULL; - return; - } - if (!counts[1]) - return; // inout stays the same - - maxpts = in->numpoints+4; // cant use counts[0]+2 because - // of fp grouping errors - - f = AllocWinding (maxpts); - - for (i=0 ; inumpoints ; i++) - { - p1 = in->p[i]; - - if (sides[i] == SIDE_ON) - { - VectorCopy (p1, f->p[f->numpoints]); - f->numpoints++; - continue; - } - - if (sides[i] == SIDE_FRONT) - { - VectorCopy (p1, f->p[f->numpoints]); - f->numpoints++; - } - - if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) - continue; - - // generate a split point - p2 = in->p[(i+1)%in->numpoints]; - - dot = dists[i] / (dists[i]-dists[i+1]); - for (j=0 ; j<3 ; j++) - { // avoid round off error when possible - if (normal[j] == 1) - mid[j] = dist; - else if (normal[j] == -1) - mid[j] = -dist; - else - mid[j] = p1[j] + dot*(p2[j]-p1[j]); - } - - VectorCopy (mid, f->p[f->numpoints]); - f->numpoints++; - } - -// if (f->numpoints > maxpts) -// Error ("ClipWinding: points exceeded estimate"); -// if (f->numpoints > MAX_POINTS_ON_WINDING) -// Error ("ClipWinding: MAX_POINTS_ON_WINDING"); - - FreeWinding(in); - *inout = f; -} - -void UseFaceBounds() -{ - LPVOID vp; - float Dot, BestDot; - float planepts[3][3]; - int BestFace; - int i, j; - int NumFaces; - vec3 SurfNormal; - vec3 vmin,vmax; - _QERFaceData *QERFaceData; - PLANE plane[MAX_FACES*2]; - PLANE pface; - MY_WINDING *w; - - switch(Plane) - { - case PLANE_XY1: - SurfNormal[0] = 0.0; - SurfNormal[1] = 0.0; - SurfNormal[2] =-1.0; - break; - case PLANE_XZ0: - SurfNormal[0] = 0.0; - SurfNormal[1] = 1.0; - SurfNormal[2] = 0.0; - break; - case PLANE_XZ1: - SurfNormal[0] = 0.0; - SurfNormal[1] =-1.0; - SurfNormal[2] = 0.0; - break; - case PLANE_YZ0: - SurfNormal[0] = 1.0; - SurfNormal[1] = 0.0; - SurfNormal[2] = 0.0; - break; - case PLANE_YZ1: - SurfNormal[0] =-1.0; - SurfNormal[1] = 0.0; - SurfNormal[2] = 0.0; - break; - default: - SurfNormal[0] = 0.0; - SurfNormal[1] = 0.0; - SurfNormal[2] = 1.0; - } - - i = g_FuncTable.m_pfnAllocateSelectedBrushHandles(); - vp = g_FuncTable.m_pfnGetSelectedBrushHandle(0); - NumFaces = g_FuncTable.m_pfnGetFaceCount(vp); - - BestFace = -1; - BestDot = 0.0; - - for(i=0; im_v1[0]; - planepts[0][1] = QERFaceData->m_v1[1]; - planepts[0][2] = QERFaceData->m_v1[2]; - planepts[1][0] = QERFaceData->m_v2[0]; - planepts[1][1] = QERFaceData->m_v2[1]; - planepts[1][2] = QERFaceData->m_v2[2]; - planepts[2][0] = QERFaceData->m_v3[0]; - planepts[2][1] = QERFaceData->m_v3[1]; - planepts[2][2] = QERFaceData->m_v3[2]; - - PlaneFromPoints (planepts[0], planepts[1], planepts[2], &plane[2*i]); - VectorSubtract (vec3_origin, plane[2*i].normal, plane[2*i+1].normal); - plane[2*i+1].dist = -plane[2*i].dist; - - Dot = DotProduct(plane[2*i].normal,SurfNormal); - if(Dot > BestDot) - { - BestDot = Dot; - BestFace = i; - if(strlen(QERFaceData->m_TextureName)) - strcpy(Texture[Game][0],QERFaceData->m_TextureName); - } - } - for(i=0; im_TextureName)) - { - if(strcmp(Texture[Game][0],QERFaceData->m_TextureName)) - strcpy(Texture[Game][1],QERFaceData->m_TextureName); - } - } - - - g_FuncTable.m_pfnReleaseSelectedBrushHandles(); - - w = BaseWindingForPlane (plane[BestFace*2].normal, plane[BestFace*2].dist); - - for (i=0 ; ip[0][0]; - vmin[1] = vmax[1] = w->p[0][1]; - vmin[2] = vmax[2] = w->p[0][2]; - for(j=1; jnumpoints; j++) - { - vmin[0] = min(vmin[0],w->p[j][0]); - vmin[1] = min(vmin[1],w->p[j][1]); - vmin[2] = min(vmin[2],w->p[j][2]); - vmax[0] = max(vmax[0],w->p[j][0]); - vmax[1] = max(vmax[1],w->p[j][1]); - vmax[2] = max(vmax[2],w->p[j][2]); - } - - FreeWinding(w); - - VectorCopy(plane[BestFace*2].normal,pface.normal); - pface.dist = plane[BestFace*2].dist; - switch(Plane) - { - case PLANE_XZ0: - case PLANE_XZ1: - if(pface.normal[1] == 0.) return; - Hll = vmin[0]; - Hur = vmax[0]; - Vll = vmin[2]; - Vur = vmax[2]; - Z00 = (pface.dist - pface.normal[0]*Hll - pface.normal[2]*Vll)/pface.normal[1]; - Z01 = (pface.dist - pface.normal[0]*Hll - pface.normal[2]*Vur)/pface.normal[1]; - Z10 = (pface.dist - pface.normal[0]*Hur - pface.normal[2]*Vll)/pface.normal[1]; - Z11 = (pface.dist - pface.normal[0]*Hur - pface.normal[2]*Vur)/pface.normal[1]; - break; - case PLANE_YZ0: - case PLANE_YZ1: - if(pface.normal[0] == 0.) return; - Hll = vmin[1]; - Hur = vmax[1]; - Vll = vmin[2]; - Vur = vmax[2]; - Z00 = (pface.dist - pface.normal[1]*Hll - pface.normal[2]*Vll)/pface.normal[0]; - Z01 = (pface.dist - pface.normal[1]*Hll - pface.normal[2]*Vur)/pface.normal[0]; - Z10 = (pface.dist - pface.normal[1]*Hur - pface.normal[2]*Vll)/pface.normal[0]; - Z11 = (pface.dist - pface.normal[1]*Hur - pface.normal[2]*Vur)/pface.normal[0]; - break; - default: - if(pface.normal[2] == 0.) return; - Hll = vmin[0]; - Hur = vmax[0]; - Vll = vmin[1]; - Vur = vmax[1]; - Z00 = (pface.dist - pface.normal[0]*Hll - pface.normal[1]*Vll)/pface.normal[2]; - Z01 = (pface.dist - pface.normal[0]*Hll - pface.normal[1]*Vur)/pface.normal[2]; - Z10 = (pface.dist - pface.normal[0]*Hur - pface.normal[1]*Vll)/pface.normal[2]; - Z11 = (pface.dist - pface.normal[0]*Hur - pface.normal[1]*Vur)/pface.normal[2]; - } -} +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +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 +*/ + +#include +#include +#include "gensurf.h" + +#define MAX_FACES 128 // Maximum number of faces on a brush +#define MAX_POINTS_ON_WINDING 64 +#define SIDE_FRONT 0 +#define SIDE_ON 2 +#define SIDE_BACK 1 +#define SIDE_CROSS -2 + +vec3 vec3_origin = {0,0,0}; + +void PlaneFromPoints (float *p0, float *p1, float *p2, PLANE *plane) +{ + vec3 t1, t2; + vec length; + + VectorSubtract (p0, p1, t1); + VectorSubtract (p2, p1, t2); + plane->normal[0] = t1[1]*t2[2] - t1[2]*t2[1]; + plane->normal[1] = t1[2]*t2[0] - t1[0]*t2[2]; + plane->normal[2] = t1[0]*t2[1] - t1[1]*t2[0]; + + length = (vec)(sqrt(plane->normal[0]*plane->normal[0] + + plane->normal[1]*plane->normal[1] + + plane->normal[2]*plane->normal[2] )); + if (length == 0) + { + VectorClear(plane->normal); + } + else + { + plane->normal[0] /= length; + plane->normal[1] /= length; + plane->normal[2] /= length; + } + plane->dist = DotProduct (p0, plane->normal); +} + +void VectorMA (vec3 va, vec scale, vec3 vb, vec3 vc) +{ + vc[0] = va[0] + scale*vb[0]; + vc[1] = va[1] + scale*vb[1]; + vc[2] = va[2] + scale*vb[2]; +} + +void CrossProduct (vec3 v1, vec3 v2, vec3 cross) +{ + cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; + cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; + cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; +} + +/* +============= +AllocWinding +============= +*/ +MY_WINDING *AllocWinding (int points) +{ + MY_WINDING *w; + int s; + + s = sizeof(vec)*3*points + sizeof(int); + w = (MY_WINDING*)malloc (s); + memset (w, 0, s); + return w; +} + +vec VectorNormalize (vec3 in, vec3 out) +{ + vec length, ilength; + + length = (vec)(sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2])); + if (length == 0) + { + VectorClear (out); + return 0; + } + + ilength = (vec)1.0/length; + out[0] = in[0]*ilength; + out[1] = in[1]*ilength; + out[2] = in[2]*ilength; + + return length; +} + +/* +================= +BaseWindingForPlane +================= +*/ +MY_WINDING *BaseWindingForPlane (vec3 normal, vec dist) +{ + int i, x; + vec max, v; + vec3 org, vright, vup; + MY_WINDING *w; + +// find the major axis + + max = -BOGUS_RANGE; + x = -1; + for (i=0 ; i<3; i++) + { + v = (vec)(fabs(normal[i])); + if (v > max) + { + x = i; + max = v; + } + } + if (x==-1) x = 2; + + VectorCopy(vec3_origin,vup); + switch (x) + { + case 0: + case 1: + vup[2] = 1; + break; + case 2: + vup[0] = 1; + break; + } + + v = DotProduct (vup, normal); + VectorMA (vup, -v, normal, vup); + VectorNormalize (vup, vup); + + VectorScale (normal, dist, org); + + CrossProduct (vup, normal, vright); + + VectorScale (vup, 65536, vup); + VectorScale (vright, 65536, vright); + +// project a really big axis aligned box onto the plane + w = AllocWinding (4); + + VectorSubtract (org, vright, w->p[0]); + VectorAdd (w->p[0], vup, w->p[0]); + + VectorAdd (org, vright, w->p[1]); + VectorAdd (w->p[1], vup, w->p[1]); + + VectorAdd (org, vright, w->p[2]); + VectorSubtract (w->p[2], vup, w->p[2]); + + VectorSubtract (org, vright, w->p[3]); + VectorSubtract (w->p[3], vup, w->p[3]); + + w->numpoints = 4; + + return w; +} + +void FreeWinding (MY_WINDING *w) +{ + if (*(unsigned *)w == 0xdeaddead) +// Error ("FreeWinding: freed a freed winding"); + return; + *(unsigned *)w = 0xdeaddead; + + free (w); +} + +/* +============= +ChopWindingInPlace +============= +*/ +void ChopWindingInPlace (MY_WINDING **inout, vec3 normal, vec dist, vec epsilon) +{ + MY_WINDING *in; + vec dists[MAX_POINTS_ON_WINDING+4]; + int sides[MAX_POINTS_ON_WINDING+4]; + int counts[3]; + static vec dot; // VC 4.2 optimizer bug if not static + int i, j; + vec *p1, *p2; + vec3 mid; + MY_WINDING *f; + int maxpts; + + in = *inout; + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + for (i=0 ; inumpoints ; i++) + { + dot = DotProduct (in->p[i], normal); + dot -= dist; + dists[i] = dot; + if (dot > epsilon) + sides[i] = SIDE_FRONT; + else if (dot < -epsilon) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + if (!counts[0]) + { + FreeWinding(in); + *inout = NULL; + return; + } + if (!counts[1]) + return; // inout stays the same + + maxpts = in->numpoints+4; // cant use counts[0]+2 because + // of fp grouping errors + + f = AllocWinding (maxpts); + + for (i=0 ; inumpoints ; i++) + { + p1 = in->p[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = in->p[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible + if (normal[j] == 1) + mid[j] = dist; + else if (normal[j] == -1) + mid[j] = -dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, f->p[f->numpoints]); + f->numpoints++; + } + +// if (f->numpoints > maxpts) +// Error ("ClipWinding: points exceeded estimate"); +// if (f->numpoints > MAX_POINTS_ON_WINDING) +// Error ("ClipWinding: MAX_POINTS_ON_WINDING"); + + FreeWinding(in); + *inout = f; +} + +void UseFaceBounds() +{ + LPVOID vp; + float Dot, BestDot; + float planepts[3][3]; + int BestFace; + int i, j; + int NumFaces; + vec3 SurfNormal; + vec3 vmin,vmax; + _QERFaceData *QERFaceData; + PLANE plane[MAX_FACES*2]; + PLANE pface; + MY_WINDING *w; + + switch(Plane) + { + case PLANE_XY1: + SurfNormal[0] = 0.0; + SurfNormal[1] = 0.0; + SurfNormal[2] =-1.0; + break; + case PLANE_XZ0: + SurfNormal[0] = 0.0; + SurfNormal[1] = 1.0; + SurfNormal[2] = 0.0; + break; + case PLANE_XZ1: + SurfNormal[0] = 0.0; + SurfNormal[1] =-1.0; + SurfNormal[2] = 0.0; + break; + case PLANE_YZ0: + SurfNormal[0] = 1.0; + SurfNormal[1] = 0.0; + SurfNormal[2] = 0.0; + break; + case PLANE_YZ1: + SurfNormal[0] =-1.0; + SurfNormal[1] = 0.0; + SurfNormal[2] = 0.0; + break; + default: + SurfNormal[0] = 0.0; + SurfNormal[1] = 0.0; + SurfNormal[2] = 1.0; + } + + i = g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + vp = g_FuncTable.m_pfnGetSelectedBrushHandle(0); + NumFaces = g_FuncTable.m_pfnGetFaceCount(vp); + + BestFace = -1; + BestDot = 0.0; + + for(i=0; im_v1[0]; + planepts[0][1] = QERFaceData->m_v1[1]; + planepts[0][2] = QERFaceData->m_v1[2]; + planepts[1][0] = QERFaceData->m_v2[0]; + planepts[1][1] = QERFaceData->m_v2[1]; + planepts[1][2] = QERFaceData->m_v2[2]; + planepts[2][0] = QERFaceData->m_v3[0]; + planepts[2][1] = QERFaceData->m_v3[1]; + planepts[2][2] = QERFaceData->m_v3[2]; + + PlaneFromPoints (planepts[0], planepts[1], planepts[2], &plane[2*i]); + VectorSubtract (vec3_origin, plane[2*i].normal, plane[2*i+1].normal); + plane[2*i+1].dist = -plane[2*i].dist; + + Dot = DotProduct(plane[2*i].normal,SurfNormal); + if(Dot > BestDot) + { + BestDot = Dot; + BestFace = i; + if(strlen(QERFaceData->m_TextureName)) + strcpy(Texture[Game][0],QERFaceData->m_TextureName); + } + } + for(i=0; im_TextureName)) + { + if(strcmp(Texture[Game][0],QERFaceData->m_TextureName)) + strcpy(Texture[Game][1],QERFaceData->m_TextureName); + } + } + + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); + + w = BaseWindingForPlane (plane[BestFace*2].normal, plane[BestFace*2].dist); + + for (i=0 ; ip[0][0]; + vmin[1] = vmax[1] = w->p[0][1]; + vmin[2] = vmax[2] = w->p[0][2]; + for(j=1; jnumpoints; j++) + { + vmin[0] = min(vmin[0],w->p[j][0]); + vmin[1] = min(vmin[1],w->p[j][1]); + vmin[2] = min(vmin[2],w->p[j][2]); + vmax[0] = max(vmax[0],w->p[j][0]); + vmax[1] = max(vmax[1],w->p[j][1]); + vmax[2] = max(vmax[2],w->p[j][2]); + } + + FreeWinding(w); + + VectorCopy(plane[BestFace*2].normal,pface.normal); + pface.dist = plane[BestFace*2].dist; + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + if(pface.normal[1] == 0.) return; + Hll = vmin[0]; + Hur = vmax[0]; + Vll = vmin[2]; + Vur = vmax[2]; + Z00 = (pface.dist - pface.normal[0]*Hll - pface.normal[2]*Vll)/pface.normal[1]; + Z01 = (pface.dist - pface.normal[0]*Hll - pface.normal[2]*Vur)/pface.normal[1]; + Z10 = (pface.dist - pface.normal[0]*Hur - pface.normal[2]*Vll)/pface.normal[1]; + Z11 = (pface.dist - pface.normal[0]*Hur - pface.normal[2]*Vur)/pface.normal[1]; + break; + case PLANE_YZ0: + case PLANE_YZ1: + if(pface.normal[0] == 0.) return; + Hll = vmin[1]; + Hur = vmax[1]; + Vll = vmin[2]; + Vur = vmax[2]; + Z00 = (pface.dist - pface.normal[1]*Hll - pface.normal[2]*Vll)/pface.normal[0]; + Z01 = (pface.dist - pface.normal[1]*Hll - pface.normal[2]*Vur)/pface.normal[0]; + Z10 = (pface.dist - pface.normal[1]*Hur - pface.normal[2]*Vll)/pface.normal[0]; + Z11 = (pface.dist - pface.normal[1]*Hur - pface.normal[2]*Vur)/pface.normal[0]; + break; + default: + if(pface.normal[2] == 0.) return; + Hll = vmin[0]; + Hur = vmax[0]; + Vll = vmin[1]; + Vur = vmax[1]; + Z00 = (pface.dist - pface.normal[0]*Hll - pface.normal[1]*Vll)/pface.normal[2]; + Z01 = (pface.dist - pface.normal[0]*Hll - pface.normal[1]*Vur)/pface.normal[2]; + Z10 = (pface.dist - pface.normal[0]*Hur - pface.normal[1]*Vll)/pface.normal[2]; + Z11 = (pface.dist - pface.normal[0]*Hur - pface.normal[1]*Vur)/pface.normal[2]; + } +} diff --git a/contrib/gtkgensurf/font.cpp b/contrib/gtkgensurf/font.cpp index bb3753f1..081a83d4 100644 --- a/contrib/gtkgensurf/font.cpp +++ b/contrib/gtkgensurf/font.cpp @@ -1,270 +1,270 @@ -/* -GenSurf plugin for GtkRadiant -Copyright (C) 2001 David Hyde, Loki software and qeradiant.com - -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 -*/ - -// -// Texture Font -// -// Taken from LeoCAD (www.leocad.org) and used in GtkGenSurf -// with permission from the author. -// -// Leonardo Zide (leo@lokigames.com) -// - -#include -#include "gensurf.h" - -static const unsigned char data[2048] = { - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 207, 255, 255, 159, 255, 31, 255, 231, 159, 153, 63, 255, 255, 255, 255, - 255, 207, 255, 255, 159, 255, 207, 255, 231, 159, 153, 63, 255, 255, 255, 255, - 255, 207, 255, 255, 159, 255, 207, 255, 231, 255, 159, 63, 255, 255, 255, 255, - 7, 78, 252, 240, 145, 135, 3, 71, 38, 158, 153, 51, 19, 227, 196, 255, - 243, 140, 121, 230, 140, 51, 207, 51, 198, 156, 153, 57, 99, 204, 152, 255, - 255, 204, 51, 111, 158, 121, 206, 121, 230, 153, 153, 60, 115, 206, 60, 255, - 31, 204, 51, 127, 158, 121, 206, 121, 230, 153, 25, 62, 115, 206, 60, 255, - 199, 204, 51, 127, 158, 1, 206, 121, 230, 153, 25, 62, 115, 206, 60, 255, - 243, 204, 51, 127, 158, 249, 207, 121, 230, 153, 153, 60, 115, 206, 60, 255, - 243, 204, 51, 111, 158, 249, 207, 121, 230, 153, 153, 57, 115, 206, 60, 255, - 243, 140, 121, 230, 140, 115, 206, 51, 230, 153, 153, 51, 115, 206, 60, 255, - 7, 73, 252, 240, 145, 7, 207, 71, 230, 153, 153, 39, 115, 206, 60, 255, - 255, 255, 255, 255, 255, 255, 255, 127, 254, 255, 249, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 127, 254, 255, 249, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 57, 255, 255, 249, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 131, 255, 255, 252, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 249, 255, 255, 255, 255, 255, 255, 255, 227, 255, - 255, 255, 255, 255, 255, 255, 249, 255, 255, 255, 255, 255, 255, 255, 201, 255, - 255, 255, 255, 255, 255, 255, 249, 255, 255, 255, 255, 255, 255, 255, 156, 255, - 15, 79, 252, 200, 196, 96, 32, 79, 62, 252, 15, 15, 159, 192, 156, 255, - 103, 142, 121, 198, 112, 206, 57, 79, 62, 60, 15, 15, 159, 207, 156, 255, - 243, 204, 51, 207, 120, 254, 57, 207, 156, 57, 103, 102, 206, 231, 156, 255, - 243, 204, 51, 207, 124, 252, 57, 207, 156, 25, 230, 112, 206, 231, 156, 255, - 243, 204, 51, 207, 252, 224, 57, 207, 156, 25, 230, 121, 206, 243, 156, 255, - 243, 204, 51, 207, 252, 199, 57, 207, 201, 211, 242, 240, 228, 249, 156, 255, - 243, 204, 51, 207, 252, 207, 57, 207, 201, 195, 112, 230, 228, 249, 156, 255, - 103, 142, 121, 198, 124, 206, 121, 198, 227, 231, 57, 207, 241, 252, 201, 255, - 15, 79, 252, 200, 252, 224, 227, 200, 227, 231, 57, 207, 241, 192, 227, 255, - 255, 207, 255, 207, 255, 255, 255, 255, 255, 255, 255, 255, 249, 255, 255, 255, - 255, 207, 255, 207, 255, 255, 255, 255, 255, 255, 255, 255, 249, 255, 255, 255, - 255, 207, 255, 207, 255, 255, 255, 255, 255, 255, 255, 255, 252, 255, 255, 255, - 255, 207, 255, 207, 255, 255, 255, 255, 255, 255, 255, 127, 254, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 159, 15, 30, 252, 57, 224, 225, 128, 131, 7, 255, 254, 128, 127, 240, 255, - 135, 231, 204, 249, 57, 255, 252, 159, 57, 115, 126, 252, 60, 63, 231, 255, - 159, 247, 236, 249, 56, 127, 254, 159, 57, 115, 126, 252, 124, 158, 207, 255, - 159, 255, 252, 249, 56, 127, 254, 207, 57, 115, 62, 249, 124, 158, 207, 255, - 159, 255, 252, 121, 56, 112, 254, 207, 57, 115, 62, 249, 60, 207, 255, 255, - 159, 127, 62, 60, 57, 103, 224, 231, 131, 115, 158, 243, 128, 207, 255, 255, - 159, 63, 255, 57, 249, 103, 206, 231, 57, 7, 158, 243, 60, 207, 255, 255, - 159, 159, 255, 153, 249, 103, 206, 231, 57, 127, 206, 231, 124, 206, 255, 255, - 159, 207, 255, 25, 240, 103, 206, 243, 57, 127, 14, 224, 124, 158, 207, 255, - 159, 231, 239, 249, 185, 103, 206, 243, 57, 127, 230, 207, 124, 158, 207, 255, - 159, 231, 207, 249, 57, 103, 206, 243, 57, 63, 231, 207, 60, 63, 231, 255, - 159, 7, 28, 252, 121, 240, 224, 243, 131, 135, 231, 207, 128, 127, 240, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 7, 126, 128, 3, 124, 240, 249, 156, 63, 231, 57, 255, 252, 57, 159, 255, - 231, 124, 254, 243, 63, 231, 249, 156, 63, 231, 60, 255, 252, 57, 159, 255, - 231, 121, 254, 243, 159, 207, 249, 156, 63, 103, 62, 255, 248, 56, 158, 255, - 231, 121, 254, 243, 159, 207, 249, 156, 63, 39, 63, 255, 248, 56, 156, 255, - 231, 115, 254, 243, 207, 255, 249, 156, 63, 135, 63, 255, 112, 56, 152, 255, - 231, 115, 192, 3, 206, 255, 1, 156, 63, 199, 63, 255, 112, 56, 153, 255, - 231, 115, 254, 243, 207, 193, 249, 156, 63, 135, 63, 255, 36, 57, 147, 255, - 231, 115, 254, 243, 207, 207, 249, 156, 63, 39, 63, 255, 36, 57, 131, 255, - 231, 121, 254, 243, 159, 207, 249, 156, 57, 103, 62, 255, 140, 57, 135, 255, - 231, 121, 254, 243, 159, 199, 249, 156, 57, 231, 60, 255, 140, 57, 143, 255, - 231, 124, 254, 243, 63, 199, 249, 156, 147, 231, 57, 255, 220, 57, 159, 255, - 7, 126, 128, 243, 127, 208, 249, 156, 199, 231, 51, 192, 220, 57, 159, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 63, 252, 128, 63, 252, 128, 63, 28, 128, 249, 204, 79, 254, 39, 63, 255, - 159, 249, 60, 159, 249, 60, 159, 249, 249, 249, 204, 79, 158, 39, 63, 255, - 207, 243, 124, 206, 243, 124, 206, 243, 249, 249, 156, 103, 158, 103, 158, 255, - 207, 243, 124, 206, 243, 124, 206, 255, 249, 249, 156, 231, 156, 243, 204, 255, - 231, 231, 124, 230, 231, 124, 158, 255, 249, 249, 156, 231, 12, 243, 225, 255, - 231, 231, 60, 231, 231, 60, 63, 252, 249, 249, 60, 243, 12, 243, 243, 255, - 231, 231, 128, 231, 231, 128, 255, 249, 249, 249, 60, 243, 105, 249, 243, 255, - 231, 231, 252, 103, 230, 60, 255, 243, 249, 249, 124, 251, 97, 248, 225, 255, - 207, 243, 252, 207, 240, 124, 254, 243, 249, 249, 124, 248, 97, 248, 204, 255, - 207, 243, 252, 207, 241, 124, 206, 243, 249, 249, 124, 248, 243, 124, 158, 255, - 159, 249, 252, 159, 241, 124, 158, 249, 249, 115, 254, 252, 243, 60, 63, 255, - 63, 252, 252, 63, 228, 252, 60, 252, 249, 7, 255, 252, 243, 60, 63, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 243, 19, 192, 255, 252, 255, 255, 127, 14, 127, 248, 15, 252, 247, 227, 231, - 243, 243, 207, 255, 252, 255, 153, 127, 102, 62, 243, 227, 241, 193, 201, 243, - 231, 249, 231, 255, 252, 255, 60, 127, 242, 156, 231, 249, 231, 148, 201, 249, - 207, 252, 243, 255, 204, 124, 126, 126, 254, 156, 231, 57, 230, 148, 201, 252, - 207, 252, 243, 255, 204, 60, 255, 60, 255, 156, 231, 156, 204, 244, 99, 254, - 31, 254, 249, 255, 252, 159, 255, 57, 127, 158, 231, 204, 204, 244, 63, 255, - 31, 254, 252, 255, 252, 207, 255, 51, 63, 159, 231, 204, 204, 193, 159, 255, - 63, 127, 254, 255, 252, 159, 255, 57, 159, 207, 207, 204, 204, 151, 207, 248, - 63, 127, 254, 255, 252, 63, 255, 156, 159, 159, 231, 204, 228, 151, 103, 242, - 63, 63, 255, 255, 255, 127, 126, 158, 255, 159, 231, 25, 241, 148, 115, 242, - 63, 159, 127, 230, 204, 252, 60, 159, 159, 159, 231, 249, 255, 148, 121, 242, - 63, 31, 64, 230, 204, 252, 153, 159, 159, 159, 231, 227, 255, 193, 252, 248, - 255, 255, 63, 255, 231, 255, 255, 255, 255, 159, 231, 15, 252, 247, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 63, 243, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, 248, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 63, 254, 255, 195, 255, 255, 255, 255, 3, 252, 147, 255, 255, 255, 255, 255, - 159, 252, 255, 153, 255, 255, 255, 255, 243, 252, 147, 255, 255, 255, 255, 255, - 159, 252, 255, 153, 255, 243, 255, 255, 243, 252, 147, 255, 255, 255, 255, 255, - 159, 252, 204, 60, 255, 243, 255, 255, 243, 252, 0, 255, 255, 255, 255, 255, - 63, 254, 204, 60, 255, 243, 128, 255, 243, 252, 201, 255, 255, 255, 255, 255, - 63, 254, 225, 60, 255, 243, 255, 255, 243, 252, 201, 255, 255, 255, 255, 255, - 31, 126, 128, 60, 127, 128, 255, 255, 243, 252, 201, 255, 255, 255, 255, 255, - 159, 228, 225, 60, 193, 243, 128, 255, 243, 252, 201, 255, 255, 255, 255, 255, - 207, 240, 204, 60, 255, 243, 255, 255, 243, 124, 128, 255, 255, 255, 255, 255, - 207, 249, 204, 60, 255, 243, 255, 255, 243, 252, 228, 255, 255, 255, 255, 255, - 207, 240, 255, 60, 255, 243, 255, 255, 243, 252, 228, 255, 255, 255, 255, 255, - 31, 242, 255, 60, 255, 255, 255, 255, 243, 252, 228, 255, 255, 255, 255, 255, - 255, 255, 255, 60, 255, 255, 255, 255, 243, 252, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 153, 255, 255, 255, 0, 242, 252, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 153, 255, 255, 255, 255, 243, 252, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 195, 255, 255, 255, 255, 3, 252, 255, 255, 255, 255, 255, 255 -}; - -typedef struct -{ - unsigned char width; - float left, right, top, bottom; -} LC_TXFVERT; - -static LC_TXFVERT glyphs[93]; -static GLuint texture; - -void texfont_init () -{ - if (texture != 0) - return; - - int i, j, x, y; - float inv = 1.0f/128; - char *charlines[16] = { - "abcdefghijklmn", "opqrstuvwxyz0", "123456789ABC", "DEFGHIJKLMN", - "OPQRSTUVWX", "YZ,.!;:<>/?{}@$%", "&*()-+=_[] #" }; - unsigned char lefts[7][17] = { - { 1, 11, 21, 30, 40, 50, 56, 66, 76, 80, 84, 93, 97, 111, 121 }, - { 1, 11, 21, 31, 38, 47, 53, 63, 72, 86, 94, 103, 111, 120 }, - { 1, 10, 19, 28, 37, 46, 55, 64, 73, 82, 94, 106, 118, }, - { 1, 13, 24, 34, 47, 59, 64, 73, 84, 94, 108, 120 }, - { 1, 14, 25, 38, 50, 61, 71, 83, 94, 109, 120 }, - { 1, 12, 22, 26, 30, 35, 39, 43, 52, 61, 65, 75, 81, 87, 103, 112, 125 }, - { 3, 14, 23, 28, 33, 38, 47, 56, 65, 70, 75, 79, 88 } }; - // tops = 1 20 39 58 77 96 112 (+16) - memset(glyphs, 0, sizeof(glyphs)); - - // ASCII 32-125 - for (i = 32; i < 126; i++) - for (x = 0; x < 7; x++) - for (y = 0; charlines[x][y]; y++) - if (charlines[x][y] == i) - { - glyphs[i-32].width = lefts[x][y+1] - lefts[x][y]; - glyphs[i-32].left = (float)lefts[x][y]*inv; - glyphs[i-32].right = (float)(lefts[x][y+1])*inv; - - if (x != 6) - glyphs[i-32].top = (float)(1 + 19*x); - else - glyphs[i-32].top = 112; - glyphs[i-32].bottom = glyphs[i-32].top + 16; - glyphs[i-32].top *= inv; - glyphs[i-32].bottom *= inv; - } - - g_GLTable.m_pfn_qglGenTextures (1, &texture); - g_GLTable.m_pfn_qglBindTexture (GL_TEXTURE_2D, texture); - g_GLTable.m_pfn_qglDisable (GL_TEXTURE_GEN_S); - g_GLTable.m_pfn_qglDisable (GL_TEXTURE_GEN_T); - g_GLTable.m_pfn_qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - g_GLTable.m_pfn_qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - g_GLTable.m_pfn_qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - g_GLTable.m_pfn_qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - // g_GLTable.m_pfn_qglPixelStorei (GL_UNPACK_ALIGNMENT, 1); - - unsigned char *buf = (unsigned char*)malloc (128*128); - memset (buf, 255, 128*128); - - for (i = 0; i < 2048; i++) - for (j = 0; j < 8; j++) - if ((data[i] & (1 << j)) != 0) - buf[i*8+j] = 0; - - g_GLTable.m_pfn_qglTexImage2D (GL_TEXTURE_2D, 0, GL_INTENSITY4, 128, 128, 0, - GL_LUMINANCE, GL_UNSIGNED_BYTE, buf); - free (buf); -} - -void texfont_write (const char *text, float l, float t) -{ - if (texture == 0) - return; - - g_GLTable.m_pfn_qglColor3f (0, 1, 0); - g_GLTable.m_pfn_qglBindTexture (GL_TEXTURE_2D, texture); - g_GLTable.m_pfn_qglEnable (GL_TEXTURE_2D); - // g_GLTable.m_pfn_qglTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - g_GLTable.m_pfn_qglAlphaFunc (GL_GREATER, 0.0625); - g_GLTable.m_pfn_qglEnable (GL_ALPHA_TEST); - - g_GLTable.m_pfn_qglBegin (GL_QUADS); - for (const char* p = text; *p; p++) - { - if (*p < 32 || *p > 125) - continue; - if (glyphs[*p-32].width == 0) - continue; - - g_GLTable.m_pfn_qglTexCoord2f (glyphs[*p-32].left, glyphs[*p-32].top); - g_GLTable.m_pfn_qglVertex2f (l, t); - g_GLTable.m_pfn_qglTexCoord2f (glyphs[*p-32].left, glyphs[*p-32].bottom); - g_GLTable.m_pfn_qglVertex2f (l, t-16); - g_GLTable.m_pfn_qglTexCoord2f (glyphs[*p-32].right, glyphs[*p-32].bottom); - g_GLTable.m_pfn_qglVertex2f (l + glyphs[*p-32].width, t-16); - g_GLTable.m_pfn_qglTexCoord2f (glyphs[*p-32].right, glyphs[*p-32].top); - g_GLTable.m_pfn_qglVertex2f (l + glyphs[*p-32].width, t); - l += glyphs[*p-32].width; - } - g_GLTable.m_pfn_qglEnd (); - - g_GLTable.m_pfn_qglDisable (GL_ALPHA_TEST); - g_GLTable.m_pfn_qglDisable (GL_TEXTURE_2D); - g_GLTable.m_pfn_qglBindTexture (GL_TEXTURE_2D, 0); -} +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +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 +*/ + +// +// Texture Font +// +// Taken from LeoCAD (www.leocad.org) and used in GtkGenSurf +// with permission from the author. +// +// Leonardo Zide (leo@lokigames.com) +// + +#include +#include "gensurf.h" + +static const unsigned char data[2048] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 207, 255, 255, 159, 255, 31, 255, 231, 159, 153, 63, 255, 255, 255, 255, + 255, 207, 255, 255, 159, 255, 207, 255, 231, 159, 153, 63, 255, 255, 255, 255, + 255, 207, 255, 255, 159, 255, 207, 255, 231, 255, 159, 63, 255, 255, 255, 255, + 7, 78, 252, 240, 145, 135, 3, 71, 38, 158, 153, 51, 19, 227, 196, 255, + 243, 140, 121, 230, 140, 51, 207, 51, 198, 156, 153, 57, 99, 204, 152, 255, + 255, 204, 51, 111, 158, 121, 206, 121, 230, 153, 153, 60, 115, 206, 60, 255, + 31, 204, 51, 127, 158, 121, 206, 121, 230, 153, 25, 62, 115, 206, 60, 255, + 199, 204, 51, 127, 158, 1, 206, 121, 230, 153, 25, 62, 115, 206, 60, 255, + 243, 204, 51, 127, 158, 249, 207, 121, 230, 153, 153, 60, 115, 206, 60, 255, + 243, 204, 51, 111, 158, 249, 207, 121, 230, 153, 153, 57, 115, 206, 60, 255, + 243, 140, 121, 230, 140, 115, 206, 51, 230, 153, 153, 51, 115, 206, 60, 255, + 7, 73, 252, 240, 145, 7, 207, 71, 230, 153, 153, 39, 115, 206, 60, 255, + 255, 255, 255, 255, 255, 255, 255, 127, 254, 255, 249, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 127, 254, 255, 249, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 57, 255, 255, 249, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 131, 255, 255, 252, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 249, 255, 255, 255, 255, 255, 255, 255, 227, 255, + 255, 255, 255, 255, 255, 255, 249, 255, 255, 255, 255, 255, 255, 255, 201, 255, + 255, 255, 255, 255, 255, 255, 249, 255, 255, 255, 255, 255, 255, 255, 156, 255, + 15, 79, 252, 200, 196, 96, 32, 79, 62, 252, 15, 15, 159, 192, 156, 255, + 103, 142, 121, 198, 112, 206, 57, 79, 62, 60, 15, 15, 159, 207, 156, 255, + 243, 204, 51, 207, 120, 254, 57, 207, 156, 57, 103, 102, 206, 231, 156, 255, + 243, 204, 51, 207, 124, 252, 57, 207, 156, 25, 230, 112, 206, 231, 156, 255, + 243, 204, 51, 207, 252, 224, 57, 207, 156, 25, 230, 121, 206, 243, 156, 255, + 243, 204, 51, 207, 252, 199, 57, 207, 201, 211, 242, 240, 228, 249, 156, 255, + 243, 204, 51, 207, 252, 207, 57, 207, 201, 195, 112, 230, 228, 249, 156, 255, + 103, 142, 121, 198, 124, 206, 121, 198, 227, 231, 57, 207, 241, 252, 201, 255, + 15, 79, 252, 200, 252, 224, 227, 200, 227, 231, 57, 207, 241, 192, 227, 255, + 255, 207, 255, 207, 255, 255, 255, 255, 255, 255, 255, 255, 249, 255, 255, 255, + 255, 207, 255, 207, 255, 255, 255, 255, 255, 255, 255, 255, 249, 255, 255, 255, + 255, 207, 255, 207, 255, 255, 255, 255, 255, 255, 255, 255, 252, 255, 255, 255, + 255, 207, 255, 207, 255, 255, 255, 255, 255, 255, 255, 127, 254, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 159, 15, 30, 252, 57, 224, 225, 128, 131, 7, 255, 254, 128, 127, 240, 255, + 135, 231, 204, 249, 57, 255, 252, 159, 57, 115, 126, 252, 60, 63, 231, 255, + 159, 247, 236, 249, 56, 127, 254, 159, 57, 115, 126, 252, 124, 158, 207, 255, + 159, 255, 252, 249, 56, 127, 254, 207, 57, 115, 62, 249, 124, 158, 207, 255, + 159, 255, 252, 121, 56, 112, 254, 207, 57, 115, 62, 249, 60, 207, 255, 255, + 159, 127, 62, 60, 57, 103, 224, 231, 131, 115, 158, 243, 128, 207, 255, 255, + 159, 63, 255, 57, 249, 103, 206, 231, 57, 7, 158, 243, 60, 207, 255, 255, + 159, 159, 255, 153, 249, 103, 206, 231, 57, 127, 206, 231, 124, 206, 255, 255, + 159, 207, 255, 25, 240, 103, 206, 243, 57, 127, 14, 224, 124, 158, 207, 255, + 159, 231, 239, 249, 185, 103, 206, 243, 57, 127, 230, 207, 124, 158, 207, 255, + 159, 231, 207, 249, 57, 103, 206, 243, 57, 63, 231, 207, 60, 63, 231, 255, + 159, 7, 28, 252, 121, 240, 224, 243, 131, 135, 231, 207, 128, 127, 240, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 7, 126, 128, 3, 124, 240, 249, 156, 63, 231, 57, 255, 252, 57, 159, 255, + 231, 124, 254, 243, 63, 231, 249, 156, 63, 231, 60, 255, 252, 57, 159, 255, + 231, 121, 254, 243, 159, 207, 249, 156, 63, 103, 62, 255, 248, 56, 158, 255, + 231, 121, 254, 243, 159, 207, 249, 156, 63, 39, 63, 255, 248, 56, 156, 255, + 231, 115, 254, 243, 207, 255, 249, 156, 63, 135, 63, 255, 112, 56, 152, 255, + 231, 115, 192, 3, 206, 255, 1, 156, 63, 199, 63, 255, 112, 56, 153, 255, + 231, 115, 254, 243, 207, 193, 249, 156, 63, 135, 63, 255, 36, 57, 147, 255, + 231, 115, 254, 243, 207, 207, 249, 156, 63, 39, 63, 255, 36, 57, 131, 255, + 231, 121, 254, 243, 159, 207, 249, 156, 57, 103, 62, 255, 140, 57, 135, 255, + 231, 121, 254, 243, 159, 199, 249, 156, 57, 231, 60, 255, 140, 57, 143, 255, + 231, 124, 254, 243, 63, 199, 249, 156, 147, 231, 57, 255, 220, 57, 159, 255, + 7, 126, 128, 243, 127, 208, 249, 156, 199, 231, 51, 192, 220, 57, 159, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 63, 252, 128, 63, 252, 128, 63, 28, 128, 249, 204, 79, 254, 39, 63, 255, + 159, 249, 60, 159, 249, 60, 159, 249, 249, 249, 204, 79, 158, 39, 63, 255, + 207, 243, 124, 206, 243, 124, 206, 243, 249, 249, 156, 103, 158, 103, 158, 255, + 207, 243, 124, 206, 243, 124, 206, 255, 249, 249, 156, 231, 156, 243, 204, 255, + 231, 231, 124, 230, 231, 124, 158, 255, 249, 249, 156, 231, 12, 243, 225, 255, + 231, 231, 60, 231, 231, 60, 63, 252, 249, 249, 60, 243, 12, 243, 243, 255, + 231, 231, 128, 231, 231, 128, 255, 249, 249, 249, 60, 243, 105, 249, 243, 255, + 231, 231, 252, 103, 230, 60, 255, 243, 249, 249, 124, 251, 97, 248, 225, 255, + 207, 243, 252, 207, 240, 124, 254, 243, 249, 249, 124, 248, 97, 248, 204, 255, + 207, 243, 252, 207, 241, 124, 206, 243, 249, 249, 124, 248, 243, 124, 158, 255, + 159, 249, 252, 159, 241, 124, 158, 249, 249, 115, 254, 252, 243, 60, 63, 255, + 63, 252, 252, 63, 228, 252, 60, 252, 249, 7, 255, 252, 243, 60, 63, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 243, 19, 192, 255, 252, 255, 255, 127, 14, 127, 248, 15, 252, 247, 227, 231, + 243, 243, 207, 255, 252, 255, 153, 127, 102, 62, 243, 227, 241, 193, 201, 243, + 231, 249, 231, 255, 252, 255, 60, 127, 242, 156, 231, 249, 231, 148, 201, 249, + 207, 252, 243, 255, 204, 124, 126, 126, 254, 156, 231, 57, 230, 148, 201, 252, + 207, 252, 243, 255, 204, 60, 255, 60, 255, 156, 231, 156, 204, 244, 99, 254, + 31, 254, 249, 255, 252, 159, 255, 57, 127, 158, 231, 204, 204, 244, 63, 255, + 31, 254, 252, 255, 252, 207, 255, 51, 63, 159, 231, 204, 204, 193, 159, 255, + 63, 127, 254, 255, 252, 159, 255, 57, 159, 207, 207, 204, 204, 151, 207, 248, + 63, 127, 254, 255, 252, 63, 255, 156, 159, 159, 231, 204, 228, 151, 103, 242, + 63, 63, 255, 255, 255, 127, 126, 158, 255, 159, 231, 25, 241, 148, 115, 242, + 63, 159, 127, 230, 204, 252, 60, 159, 159, 159, 231, 249, 255, 148, 121, 242, + 63, 31, 64, 230, 204, 252, 153, 159, 159, 159, 231, 227, 255, 193, 252, 248, + 255, 255, 63, 255, 231, 255, 255, 255, 255, 159, 231, 15, 252, 247, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 63, 243, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, 248, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 63, 254, 255, 195, 255, 255, 255, 255, 3, 252, 147, 255, 255, 255, 255, 255, + 159, 252, 255, 153, 255, 255, 255, 255, 243, 252, 147, 255, 255, 255, 255, 255, + 159, 252, 255, 153, 255, 243, 255, 255, 243, 252, 147, 255, 255, 255, 255, 255, + 159, 252, 204, 60, 255, 243, 255, 255, 243, 252, 0, 255, 255, 255, 255, 255, + 63, 254, 204, 60, 255, 243, 128, 255, 243, 252, 201, 255, 255, 255, 255, 255, + 63, 254, 225, 60, 255, 243, 255, 255, 243, 252, 201, 255, 255, 255, 255, 255, + 31, 126, 128, 60, 127, 128, 255, 255, 243, 252, 201, 255, 255, 255, 255, 255, + 159, 228, 225, 60, 193, 243, 128, 255, 243, 252, 201, 255, 255, 255, 255, 255, + 207, 240, 204, 60, 255, 243, 255, 255, 243, 124, 128, 255, 255, 255, 255, 255, + 207, 249, 204, 60, 255, 243, 255, 255, 243, 252, 228, 255, 255, 255, 255, 255, + 207, 240, 255, 60, 255, 243, 255, 255, 243, 252, 228, 255, 255, 255, 255, 255, + 31, 242, 255, 60, 255, 255, 255, 255, 243, 252, 228, 255, 255, 255, 255, 255, + 255, 255, 255, 60, 255, 255, 255, 255, 243, 252, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 153, 255, 255, 255, 0, 242, 252, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 153, 255, 255, 255, 255, 243, 252, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 195, 255, 255, 255, 255, 3, 252, 255, 255, 255, 255, 255, 255 +}; + +typedef struct +{ + unsigned char width; + float left, right, top, bottom; +} LC_TXFVERT; + +static LC_TXFVERT glyphs[93]; +static GLuint texture; + +void texfont_init () +{ + if (texture != 0) + return; + + int i, j, x, y; + float inv = 1.0f/128; + char *charlines[16] = { + "abcdefghijklmn", "opqrstuvwxyz0", "123456789ABC", "DEFGHIJKLMN", + "OPQRSTUVWX", "YZ,.!;:<>/?{}@$%", "&*()-+=_[] #" }; + unsigned char lefts[7][17] = { + { 1, 11, 21, 30, 40, 50, 56, 66, 76, 80, 84, 93, 97, 111, 121 }, + { 1, 11, 21, 31, 38, 47, 53, 63, 72, 86, 94, 103, 111, 120 }, + { 1, 10, 19, 28, 37, 46, 55, 64, 73, 82, 94, 106, 118, }, + { 1, 13, 24, 34, 47, 59, 64, 73, 84, 94, 108, 120 }, + { 1, 14, 25, 38, 50, 61, 71, 83, 94, 109, 120 }, + { 1, 12, 22, 26, 30, 35, 39, 43, 52, 61, 65, 75, 81, 87, 103, 112, 125 }, + { 3, 14, 23, 28, 33, 38, 47, 56, 65, 70, 75, 79, 88 } }; + // tops = 1 20 39 58 77 96 112 (+16) + memset(glyphs, 0, sizeof(glyphs)); + + // ASCII 32-125 + for (i = 32; i < 126; i++) + for (x = 0; x < 7; x++) + for (y = 0; charlines[x][y]; y++) + if (charlines[x][y] == i) + { + glyphs[i-32].width = lefts[x][y+1] - lefts[x][y]; + glyphs[i-32].left = (float)lefts[x][y]*inv; + glyphs[i-32].right = (float)(lefts[x][y+1])*inv; + + if (x != 6) + glyphs[i-32].top = (float)(1 + 19*x); + else + glyphs[i-32].top = 112; + glyphs[i-32].bottom = glyphs[i-32].top + 16; + glyphs[i-32].top *= inv; + glyphs[i-32].bottom *= inv; + } + + g_GLTable.m_pfn_qglGenTextures (1, &texture); + g_GLTable.m_pfn_qglBindTexture (GL_TEXTURE_2D, texture); + g_GLTable.m_pfn_qglDisable (GL_TEXTURE_GEN_S); + g_GLTable.m_pfn_qglDisable (GL_TEXTURE_GEN_T); + g_GLTable.m_pfn_qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + g_GLTable.m_pfn_qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + g_GLTable.m_pfn_qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + g_GLTable.m_pfn_qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + // g_GLTable.m_pfn_qglPixelStorei (GL_UNPACK_ALIGNMENT, 1); + + unsigned char *buf = (unsigned char*)malloc (128*128); + memset (buf, 255, 128*128); + + for (i = 0; i < 2048; i++) + for (j = 0; j < 8; j++) + if ((data[i] & (1 << j)) != 0) + buf[i*8+j] = 0; + + g_GLTable.m_pfn_qglTexImage2D (GL_TEXTURE_2D, 0, GL_INTENSITY4, 128, 128, 0, + GL_LUMINANCE, GL_UNSIGNED_BYTE, buf); + free (buf); +} + +void texfont_write (const char *text, float l, float t) +{ + if (texture == 0) + return; + + g_GLTable.m_pfn_qglColor3f (0, 1, 0); + g_GLTable.m_pfn_qglBindTexture (GL_TEXTURE_2D, texture); + g_GLTable.m_pfn_qglEnable (GL_TEXTURE_2D); + // g_GLTable.m_pfn_qglTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + g_GLTable.m_pfn_qglAlphaFunc (GL_GREATER, 0.0625); + g_GLTable.m_pfn_qglEnable (GL_ALPHA_TEST); + + g_GLTable.m_pfn_qglBegin (GL_QUADS); + for (const char* p = text; *p; p++) + { + if (*p < 32 || *p > 125) + continue; + if (glyphs[*p-32].width == 0) + continue; + + g_GLTable.m_pfn_qglTexCoord2f (glyphs[*p-32].left, glyphs[*p-32].top); + g_GLTable.m_pfn_qglVertex2f (l, t); + g_GLTable.m_pfn_qglTexCoord2f (glyphs[*p-32].left, glyphs[*p-32].bottom); + g_GLTable.m_pfn_qglVertex2f (l, t-16); + g_GLTable.m_pfn_qglTexCoord2f (glyphs[*p-32].right, glyphs[*p-32].bottom); + g_GLTable.m_pfn_qglVertex2f (l + glyphs[*p-32].width, t-16); + g_GLTable.m_pfn_qglTexCoord2f (glyphs[*p-32].right, glyphs[*p-32].top); + g_GLTable.m_pfn_qglVertex2f (l + glyphs[*p-32].width, t); + l += glyphs[*p-32].width; + } + g_GLTable.m_pfn_qglEnd (); + + g_GLTable.m_pfn_qglDisable (GL_ALPHA_TEST); + g_GLTable.m_pfn_qglDisable (GL_TEXTURE_2D); + g_GLTable.m_pfn_qglBindTexture (GL_TEXTURE_2D, 0); +} diff --git a/contrib/gtkgensurf/gendlgs.cpp b/contrib/gtkgensurf/gendlgs.cpp index 3faf2707..69c0805a 100644 --- a/contrib/gtkgensurf/gendlgs.cpp +++ b/contrib/gtkgensurf/gendlgs.cpp @@ -1,2364 +1,2364 @@ -/* -GenSurf plugin for GtkRadiant -Copyright (C) 2001 David Hyde, Loki software and qeradiant.com - -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 -*/ - -#include -#include -#include -#include -#include -#include "gensurf.h" - -#define GENERAL_TAB 0 -#define EXTENTS_TAB 1 -#define BITMAP_TAB 2 -#define FIXPOINTS_TAB 3 -#define TEXTURE_TAB 4 -//#define BUFF_SIZE 32768 - -#define ENABLE_WIDGET(name,enable) \ - gtk_widget_set_sensitive (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), (name))), (enable)) -#define CHECK_WIDGET(name,check) \ - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), name)), check) - -static GtkWidget *game_radios[NUMGAMES]; -static GtkWidget *wave_radios[5]; -static GtkWidget *plane_radios[6]; -static guint current_tab; -static int OldPreview; -static int WasDetail; -static GtkTooltips *tooltips; -static int FirstPassComplete = 0; - -void About (GtkWidget *parent) -{ -/* - char *icon_xpm[] = { -"32 32 4 1", -" c None", -". c #000000", -"+ c #FFFFFF", -"@ c #838183", -"................................", -"................................", -"................................", -"................................", -"................................", -"................................", -"................................", -"...............++...............", -".............++++++.............", -"............++@+++@+............", -"..........+++..++..+++..........", -"........++.+.++..++.+.@+........", -".......+..+..+.++.+..+..++......", -".....++..++.+..++..+.++..++.....", -"...++..++...+.+..+.++..++..++...", -"..++.+.++....++..++....++.+..+..", -".+.+..+..++....++....++..++.+.+.", -"..+++....+.++++++++++.+....+++..", -"....++.@@+++++.++.++++@++.++....", -"......+++++++......++@+++++.....", -".......+++.+.++..++.+..++.......", -".........++..+.++.+..++.........", -"...........++..++..++...........", -".............++..+.+............", -"..............+..+@.............", -"...............@@...............", -"................................", -"................................", -"................................", -"................................", -"................................", -"................................" -}; -*/ - // leo: I'm too lazy to create a nice about box - // ^Fishman - I am lazy too :P. - g_FuncTable.m_pfnMessageBox (parent, "GtkGenSurf 1.05\n\n" - "Original version\n" - "David Hyde (rascal@vicksburg.com)\n\n" - "Porting\n" - "Leonardo Zide (leo@lokigames.com)\n\n" - "Enhancements\n" - "Pablo Zurita (pablo@qeradiant.com)\n" - "Hydra (hydra@hydras-world.com)", - "About GtkGenSurf", MB_OK); -} - -// ============================================================================= -// main dialog - -static void SetupControls () -{ - switch (current_tab) - { - case GENERAL_TAB: - break; - - case EXTENTS_TAB: - if (Game != QUAKE3) - { - gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "use_patches"))); - ENABLE_WIDGET ("use_patches", FALSE); - } - else - { - gtk_widget_show (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "use_patches"))); - ENABLE_WIDGET ("use_patches", TRUE); - } - - if (Game == QUAKE3 && UsePatches != 0) - { - ENABLE_WIDGET ("decimate", FALSE); - } - gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "snap_text")), "Snap to grid:"); // ^Fishman - Snap to grid. - break; - - case BITMAP_TAB: - if (WaveType != WAVE_BITMAP) - { - ENABLE_WIDGET ("bmp_file", FALSE); - ENABLE_WIDGET ("bmp_file_browse", FALSE); - ENABLE_WIDGET ("bmp_black", FALSE); - ENABLE_WIDGET ("bmp_white", FALSE); - ENABLE_WIDGET ("bmp_text1", FALSE); - ENABLE_WIDGET ("bmp_text2", FALSE); - ENABLE_WIDGET ("bmp_text3", FALSE); - ENABLE_WIDGET ("bmp_reload", FALSE); - gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "bmp_note")), - "These options are disabled unless \"From Bitmap\"\n" - "is selected as the Waveform on the General tab."); - } - else - { - ENABLE_WIDGET ("bmp_file", TRUE); - ENABLE_WIDGET ("bmp_file_browse", TRUE); - ENABLE_WIDGET ("bmp_black", TRUE); - ENABLE_WIDGET ("bmp_white", TRUE); - ENABLE_WIDGET ("bmp_text1", TRUE); - ENABLE_WIDGET ("bmp_text2", TRUE); - ENABLE_WIDGET ("bmp_text3", TRUE); - ENABLE_WIDGET ("bmp_reload", strlen(gbmp.name) != 0); - gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "bmp_note")), - "GenSurf works only with 8-bit bitmaps. Color indices are\n" - "mapped to values for each vertex. Generally, gray scale\n" - "images are stored with black as color 0, white as color 255."); - } - break; - - case FIXPOINTS_TAB: - ENABLE_WIDGET ("fix_value", (NumVerticesSelected != 0)); - ENABLE_WIDGET ("fix_value_text", (NumVerticesSelected != 0)); - ENABLE_WIDGET ("fix_free", (NumVerticesSelected != 0)); - ENABLE_WIDGET ("fix_range", ((NumVerticesSelected != 0) && (WaveType != WAVE_ROUGH_ONLY))); - ENABLE_WIDGET ("fix_range_text", ((NumVerticesSelected != 0) && (WaveType != WAVE_ROUGH_ONLY))); - ENABLE_WIDGET ("fix_rate", ((NumVerticesSelected != 0) && (WaveType != WAVE_ROUGH_ONLY))); - ENABLE_WIDGET ("fix_rate_text", ((NumVerticesSelected != 0) && (WaveType != WAVE_ROUGH_ONLY))); - break; - - case TEXTURE_TAB: - ENABLE_WIDGET ("texture2", (UsePatches == 0)); - ENABLE_WIDGET ("texture3", (UsePatches == 0)); - ENABLE_WIDGET ("tex_slant", (UsePatches == 0)); - ENABLE_WIDGET ("detail", (UsePatches == 0)); - if (Game != QUAKE3 ) - { - ENABLE_WIDGET ("terrain_ent", FALSE); // ^Fishman - Adds terrain key to func_group. - ENABLE_WIDGET ("hint", (UsePatches == 0)); - } - break; - } - - switch (WaveType) - { - case WAVE_HCYLINDER: - case WAVE_VCYLINDER: - ENABLE_WIDGET ("amplitude", TRUE); - ENABLE_WIDGET ("wavelength", TRUE); - ENABLE_WIDGET ("z00", TRUE); - ENABLE_WIDGET ("z01", TRUE); - ENABLE_WIDGET ("z10", TRUE); - ENABLE_WIDGET ("z11", TRUE); - ENABLE_WIDGET ("linearborder", TRUE); - ENABLE_WIDGET ("go", TRUE); - break; - case WAVE_BITMAP: - ENABLE_WIDGET ("amplitude", FALSE); - ENABLE_WIDGET ("wavelength", FALSE); - ENABLE_WIDGET ("z00", FALSE); - ENABLE_WIDGET ("z01", FALSE); - ENABLE_WIDGET ("z10", FALSE); - ENABLE_WIDGET ("z11", FALSE); - ENABLE_WIDGET ("linearborder", FALSE); - ENABLE_WIDGET ("go", (gbmp.colors != NULL ? TRUE : FALSE)); - break; - case WAVE_ROUGH_ONLY: - ENABLE_WIDGET ("amplitude", FALSE); - ENABLE_WIDGET ("wavelength", FALSE); - ENABLE_WIDGET ("z00", TRUE); - ENABLE_WIDGET ("z01", TRUE); - ENABLE_WIDGET ("z10", TRUE); - ENABLE_WIDGET ("z11", TRUE); - ENABLE_WIDGET ("linearborder", TRUE); - ENABLE_WIDGET ("go", TRUE); - break; - default: - ENABLE_WIDGET ("amplitude", TRUE); - ENABLE_WIDGET ("wavelength", TRUE); - ENABLE_WIDGET ("z00", TRUE); - ENABLE_WIDGET ("z01", TRUE); - ENABLE_WIDGET ("z10", TRUE); - ENABLE_WIDGET ("z11", TRUE); - ENABLE_WIDGET ("linearborder", TRUE); - ENABLE_WIDGET ("go", TRUE); - } - - switch (Plane) - { - case PLANE_XZ0: - case PLANE_XZ1: - gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmin_text")), "X:"); - gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmax_text")), "X:"); - gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmin_text")), "Z:"); - gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmax_text")), "Z:"); - gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nh_text")), "X:"); - gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nv_text")), "Z:"); - break; - case PLANE_YZ0: - case PLANE_YZ1: - gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmin_text")), "Y:"); - gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmax_text")), "Y:"); - gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmin_text")), "Z:"); - gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmax_text")), "Z:"); - gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nh_text")), "Y:"); - gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nv_text")), "Z:"); - break; - default: - gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmin_text")), "X:"); - gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmax_text")), "X:"); - gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmin_text")), "Y:"); - gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmax_text")), "Y:"); - gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nh_text")), "X:"); - gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nv_text")), "Y:"); - break; - } -} - -// SetDlgValues fills in text boxes and initializes other input controls -static void SetDlgValues (int tab) -{ - char Text[256]; - char RForm[16] = "%.5g"; - int i; - - switch (tab) - { - case GENERAL_TAB: - // Hell if I know why, but in the release build the 2nd pass thru the - // set_sensitive loop for game_radios crashes. No need to do this more - // than once anyhow. - if (!FirstPassComplete) - { - for (i = 0; i < NUMGAMES; i++) - gtk_widget_set_sensitive (game_radios[i], (i == Game ? TRUE : FALSE)); - for (i = 0; i < 6; i++) - gtk_widget_set_sensitive (plane_radios[i], (i == Plane ? TRUE : FALSE)); - } - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (game_radios[Game]), TRUE); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (plane_radios[Plane]), TRUE); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wave_radios[WaveType]), TRUE); - gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "random")), - RandomSeed); - sprintf (Text, RForm, WaveLength); - gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "wavelength")), Text); - sprintf (Text, RForm, Amplitude); - gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "amplitude")), Text); - sprintf (Text, RForm, Roughness); - gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "roughness")), Text); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g_object_get_data - (G_OBJECT (g_pWnd), "main_antialiasing")), Antialiasing); - break; - - case EXTENTS_TAB: - sprintf (Text,RForm,Hll); - gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "hmin")), Text); - sprintf (Text,RForm,Vll); - gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "vmin")), Text); - sprintf (Text,RForm,Hur); - gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "hmax")), Text); - sprintf (Text,RForm,Vur); - gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "vmax")), Text); - sprintf (Text,RForm,Z00); - gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "z00")), Text); - sprintf (Text,RForm,Z01); - gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "z01")), Text); - sprintf (Text,RForm,Z10); - gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "z10")), Text); - sprintf (Text,RForm,Z11); - gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "z11")), Text); - gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "nh")), NH); - gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "nv")), NV); - gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "sp")), SP); // ^Fishman - Snap to grid. - - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g_object_get_data - (G_OBJECT (g_pWnd), "linearborder")), FixBorders); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g_object_get_data - (G_OBJECT (g_pWnd), "use_patches")), UsePatches); - gtk_adjustment_set_value (GTK_ADJUSTMENT (g_object_get_data (G_OBJECT (g_pWnd), "decimate_adj")), - Decimate); - - if (Game == QUAKE3 && UsePatches) - { - gtk_widget_set_sensitive (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "decimate")), FALSE); - - if (NH % 2) - { - NH++; - if (NH > MAX_ROWS) NH -= 2; - SetDlgValues (current_tab); - } - - if (NV % 2) - { - NV++; - if (NV > MAX_ROWS) NV -= 2; - SetDlgValues (current_tab); - } - if (NH % 2 ) NH++; - if (NH < 2 ) NH = 2; - if (NH > MAX_ROWS) NH = MAX_ROWS; - if (NV % 2 ) NV++; - if (NV < 2 ) NV = 2; - if (NV > MAX_ROWS) NV = MAX_ROWS; - - gpointer spin = g_object_get_data (G_OBJECT (g_pWnd), "nh"); - GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adj->lower = 2; - gtk_adjustment_changed (adj); - spin = g_object_get_data (G_OBJECT (g_pWnd), "nv"); - adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adj->lower = 2; - gtk_adjustment_changed (adj); - } - else - { - gtk_widget_set_sensitive (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "decimate")), TRUE); - - gpointer spin = g_object_get_data (G_OBJECT (g_pWnd), "nh"); - GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adj->lower = 1; - gtk_adjustment_changed (adj); - spin = g_object_get_data (G_OBJECT (g_pWnd), "nv"); - adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adj->lower = 1; - gtk_adjustment_changed (adj); - } - - gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "nh")), NH); - gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "nv")), NV); - - break; - - case BITMAP_TAB: - gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "bmp_file")), gbmp.name); - sprintf(Text,"%g",gbmp.black_value); - gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "bmp_black")), Text); - sprintf(Text,"%g",gbmp.white_value); - gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "bmp_white")), Text); - break; - - case FIXPOINTS_TAB: - break; - - case TEXTURE_TAB: - gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texture1")), Texture[Game][0]); - gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texture2")), Texture[Game][1]); - gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texture3")), Texture[Game][2]); - gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "tex_slant")), - SlantAngle); - sprintf(Text,RForm,TexOffset[0]); - gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texoffsetx")), Text); - sprintf(Text,RForm,TexOffset[1]); - gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texoffsety")), Text); - sprintf(Text,RForm,TexScale[0]); - gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texscalex")), Text); - sprintf(Text,RForm,TexScale[1]); - gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texscaley")), Text); - CHECK_WIDGET ("detail", UseDetail); - - if (Game==QUAKE3) - { - ENABLE_WIDGET ("hint", FALSE); - AddHints=0; - } - else - ENABLE_WIDGET ("hint", TRUE); - CHECK_WIDGET ("hint", AddHints); - - /* - if (Game==SIN) - { - // ArghRad doesn't currently support SiN - EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), 0); - EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), 0); - ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_TEXT), SW_HIDE); - ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), SW_HIDE); - ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), SW_HIDE); - SetDlgItemText(hwndDisplay,DLG_TEX_USEPAK,"Use sin file"); - SetDlgItemText(hwndDisplay,DLG_TEX_PAK_TEXT,"Sin:"); - } - */ - - if(Game==QUAKE3) - { - /* - // ArghRad sun is inapplicable (so far) - EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), 0); - EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), 0); - ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_TEXT), SW_HIDE); - ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), SW_HIDE); - ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), SW_HIDE); - // No ladders in Q3 - EnableWindow(GetDlgItem(hwndDisplay,DLG_LADDER), 0); - ShowWindow(GetDlgItem(hwndDisplay,DLG_LADDER), SW_HIDE); - SetDlgItemText(hwndDisplay,DLG_TEX_USEPAK,"Use pk3 file"); - SetDlgItemText(hwndDisplay,DLG_TEX_PAK_TEXT,"PK3:"); - */ - } - -/*trix if(Game==HERETIC2) - { - // ArghRad doesn't currently support Heretic2 - EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), 0); - EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), 0); - ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_TEXT), SW_HIDE); - ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), SW_HIDE); - ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), SW_HIDE); - - SetDlgItemText(hwndDisplay,DLG_TEX_USEPAK,"Use pak file"); - SetDlgItemText(hwndDisplay,DLG_TEX_PAK_TEXT,"Pak:"); - } */ - /* - if(Game==HALFLIFE) - { - // A bunch of controls aren't applicable to HL - EnableWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE_BROWSE), 0); - EnableWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE2_BROWSE),0); - EnableWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE3_BROWSE),0); - EnableWindow(GetDlgItem(hwndDisplay,DLG_DETAIL), 0); - EnableWindow(GetDlgItem(hwndDisplay,DLG_LADDER), 0); - EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), 0); - EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), 0); - ShowWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE_BROWSE), SW_HIDE); - ShowWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE2_BROWSE),SW_HIDE); - ShowWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE3_BROWSE),SW_HIDE); - ShowWindow(GetDlgItem(hwndDisplay,DLG_DETAIL), SW_HIDE); - ShowWindow(GetDlgItem(hwndDisplay,DLG_LADDER), SW_HIDE); - ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_TEXT), SW_HIDE); - ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), SW_HIDE); - ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), SW_HIDE); - - SetDlgItemText(hwndDisplay,DLG_TEX_USEPAK,"Use wad file"); - SetDlgItemText(hwndDisplay,DLG_TEX_PAK_TEXT,"Wad:"); - SetDlgItemText(hwndDisplay,DLG_HINT,"Hint brushes"); - } - - if(Game==GENESIS3D) - { - // No Q2-type compilers support Genesis3D (including ArghRad) - EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), 0); - EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), 0); - ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_TEXT), SW_HIDE); - ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), SW_HIDE); - ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), SW_HIDE); - - SetDlgItemText(hwndDisplay,DLG_TEX_USEPAK,"Use sin file"); - SetDlgItemText(hwndDisplay,DLG_TEX_PAK_TEXT,"Sin:"); - } - */ - break; - } - SetupControls (); -} - -static void ReadDlgValues (int tab) -{ - // char Text[256]; - // int i; - - switch (tab) - { - case GENERAL_TAB: - gpointer spin; - Roughness = atof ( gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "roughness")))); - WaveLength = atof ( gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "wavelength")))); - Amplitude = atof ( gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "amplitude")))); - spin = g_object_get_data (G_OBJECT (g_pWnd), "random"); - RandomSeed = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (spin)); - break; - - case EXTENTS_TAB: - SP = atoi (gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "sp")))); - NH = atoi (gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "nh")))); - NV = atoi (gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "nv")))); - - if (Game == QUAKE3 && UsePatches != 0) - { - if (NH % 2 ) NH++; - if (NH < 2 ) NH = 2; - if (NH > MAX_ROWS) NH = MAX_ROWS; - if (NV % 2 ) NV++; - if (NV < 2 ) NV = 2; - if (NV > MAX_ROWS) NV = MAX_ROWS; - } - break; - -#if 0 - case BITMAP_TAB: - - if (WaveType == WAVE_BITMAP) - { - GetDlgItemText(hwnd,DLG_BMP_FILE,gbmp.name,sizeof(gbmp.name)); - CheckValidDIB(hwnd); - GetDlgItemText(hwnd,DLG_BMP_BLACK,Text,sizeof(Text)); - gbmp.black_value = atof(Text); - GetDlgItemText(hwnd,DLG_BMP_WHITE,Text,sizeof(Text)); - gbmp.white_value = atof(Text); - UpdatePreview(TRUE); - } - break; - - case FIXPOINTS_TAB: - GetDlgItemText(hwnd,DLG_FIX_VALUE,Text,sizeof(Text)); - temp.fixed_value = atoi(Text); - GetDlgItemText(hwnd,DLG_FIX_RANGE,Text,sizeof(Text)); - temp.range = atoi(Text); - GetDlgItemText(hwnd,DLG_FIX_RATE, Text,sizeof(Text)); - temp.rate = atof(Text); - for(k=0; k MAX_ROWS) - { - sprintf (Text, "The number of divisions must be > 0 and no greater than %d.", MAX_ROWS); - g_FuncTable.m_pfnMessageBox (g_pWnd, Text, "GenSurf", MB_ICONEXCLAMATION); - gtk_notebook_set_page (GTK_NOTEBOOK (notebook), EXTENTS_TAB); - return; - } - - if (NV < 1 || NV > MAX_ROWS) - { - sprintf (Text, "The number of divisions must be > 0 and no greater than %d.", MAX_ROWS); - g_FuncTable.m_pfnMessageBox (g_pWnd, Text, "GenSurf", MB_ICONEXCLAMATION); - gtk_notebook_set_page (GTK_NOTEBOOK (notebook), EXTENTS_TAB); - return; - } - - if (Hll >= Hur) - { - g_FuncTable.m_pfnMessageBox (g_pWnd, "The \"lower-left\" values must be less than " - "the corresponding \"upper-right\" values in " - "the \"Extent\" box.","GenSurf", MB_OK | MB_ICONEXCLAMATION); - gtk_notebook_set_page (GTK_NOTEBOOK (notebook), EXTENTS_TAB); - return; - } - - if (Vll >= Vur) - { - g_FuncTable.m_pfnMessageBox (g_pWnd,"The \"lower-left\" values must be less than " - "the corresponding \"upper-right\" values in " - "the \"Extent\" box.","GenSurf", MB_OK | MB_ICONEXCLAMATION); - gtk_notebook_set_page (GTK_NOTEBOOK (notebook), EXTENTS_TAB); - return; - } - - if (!strlen (Texture[Game][0])) - { - g_FuncTable.m_pfnMessageBox (g_pWnd, "You must supply a texture name.", "GenSurf", MB_ICONEXCLAMATION); - gtk_notebook_set_page (GTK_NOTEBOOK (notebook), EXTENTS_TAB); - return; - } - -/* if (Decimate>0 && GimpHints!=0) - { - MessageBox(hwnd,"You've elected to use a decimated grid and gimp's non-detail hint brushes. " - "This combination usually produces bizarre visual errors in the game, " - "so GenSurf has turned off the hint brush option.", - "GenSurf",MB_ICONEXCLAMATION); - GimpHints = 0; - } */ - - gtk_widget_hide (g_pWnd); - if (g_pWndPreview) - gtk_widget_hide (g_pWndPreview); - - GenerateMap(); - WriteIniFile(gszIni); -} - -// ============================================================================= -// general tab callbacks - -static void general_game (GtkToggleButton *widget, gpointer data) -{ - if (gtk_toggle_button_get_active (widget)) - { - Game = GPOINTER_TO_INT (data); - UpdatePreview (TRUE); - } -} - -static void general_plane (GtkToggleButton *widget, gpointer data) -{ - if (gtk_toggle_button_get_active (widget)) - { - Plane = GPOINTER_TO_INT (data); - SetupControls (); - UpdatePreview (TRUE); - } -} - -static void general_wave (GtkToggleButton *widget, gpointer data) -{ - if (gtk_toggle_button_get_active (widget)) - { - WaveType = GPOINTER_TO_INT (data); - SetupControls (); - UpdatePreview (TRUE); - } -} - -static void general_random (GtkAdjustment *adj, gpointer data) -{ - int nPos = (int)adj->value; - - if (RandomSeed != nPos) - { - RandomSeed = nPos; - UpdatePreview (true); - } -} - -// ============================================================================= -// extents tab callbacks - -static void extents_linearborder (GtkToggleButton *check, gpointer data) -{ - FixBorders = gtk_toggle_button_get_active (check); - UpdatePreview (true); -} - -static void extents_use_patches (GtkToggleButton *check, gpointer data) -{ - if (Game != QUAKE3) - return; - - UsePatches = gtk_toggle_button_get_active (check); - SetDlgValues (current_tab); - SetupControls (); - UpdatePreview (true); -} - -static void extents_nhnv_spin (GtkAdjustment *adj, int *data) -{ - int nPos = (int)adj->value; - - if (*data != nPos) - { - if (Game==QUAKE3 && UsePatches && (nPos % 2)) - { - if (*data < nPos) - *data += 2; - else - *data -= 2; - gtk_adjustment_set_value (adj, *data); - } - else - *data = nPos; - UpdatePreview (true); - } -} - -static void extents_decimate (GtkAdjustment *adj, gpointer data) -{ - int nPos = (int)adj->value; - - Decimate = nPos; - UpdatePreview (true); -} - -// Hydra : snap to grid begin -/*static void extents_snaptogrid (GtkAdjustment *adj, gpointer data) -{ - int nPos = (int)adj->value; - - SnapToGrid = nPos; - UpdatePreview (true); -}*/ - -// ^Fishman - Modified version of Hydra's snap to grid code. -static void extents_snaptogrid_spin (GtkAdjustment *adj, int *data) -{ - int nPos = (int)adj->value; - SnapToGrid = nPos; - UpdatePreview (true); -} - -// ============================================================================= -// bitmap tab callbacks - -static gint bitmap_file_entryfocusout(GtkWidget* widget, GdkEventFocus* event, gpointer data) -{ - char filename[NAME_MAX]; - - strcpy (filename, gtk_entry_get_text (GTK_ENTRY(widget))); - if(strcmp (filename,gbmp.name)) - { - if (gbmp.colors) - { - free(gbmp.colors); - gbmp.colors=NULL; - } - strcpy (gbmp.name,filename); - if (strlen(gbmp.name) ) - OpenBitmap (); - ENABLE_WIDGET ("go", (gbmp.colors != NULL ? TRUE : FALSE)); - } - return FALSE; -} - -static void bitmap_browse (GtkWidget *widget, gpointer data) -{ - const char *filename; - char *ptr; - - filename = g_FuncTable.m_pfnFileDialog (g_pWnd, TRUE, "Bitmap File", gbmp.defpath); - - if (filename != NULL) - { - strcpy (gbmp.name, filename); - - ptr = strrchr (filename, G_DIR_SEPARATOR); - if (ptr != NULL) - { - *(ptr+1) = '\0'; - strcpy (gbmp.defpath, filename); - } - - OpenBitmap (); - ENABLE_WIDGET ("go", (gbmp.colors != NULL ? TRUE : FALSE)); - } -} - -static void bitmap_reload (GtkWidget *widget, gpointer data) -{ - strcpy (gbmp.name, gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "bmp_file")))); - if(strlen (gbmp.name) ) - { - OpenBitmap (); - ENABLE_WIDGET ("go", (gbmp.colors != NULL ? TRUE : FALSE)); - } - else - ENABLE_WIDGET ("go", FALSE ); -} - -// ============================================================================= -// fix points tab callbacks - -static gint fix_value_entryfocusout (GtkWidget* widget, GdkEventFocus *event, gpointer data) -{ - int i = atoi (gtk_entry_get_text (GTK_ENTRY(widget))), k; - char Text[32]; - - if (i < -65536 || i > 65536) - { - gdk_beep (); - g_FuncTable.m_pfnMessageBox (g_pWnd, "The value must be between -65536 and 65536, inclusive.", - "GenSurf", MB_OK | MB_ICONEXCLAMATION); - sprintf (Text, "%d", (int)xyz[Vertex[0].i][Vertex[0].j].fixed_value); - gtk_entry_set_text (GTK_ENTRY(widget), Text); - gtk_window_set_focus (GTK_WINDOW (gtk_widget_get_toplevel (widget)), widget); - } - else if (i != xyz[Vertex[0].i][Vertex[0].j].fixed_value) - { - for(k=0; kvalue; - - if (xyz[Vertex[0].i][Vertex[0].j].fixed_value != i) - { - for(k=0; k(data)); - return FALSE; -} - -// ============================================================================= -// create tooltips - -void create_tooltips () -{ - tooltips = gtk_tooltips_new (); - - // Main - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "go")), - "Accept all input and generate a surface in Q3Radiant", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "open")), - "Open a previously saved GenSurf settings file.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "save")), - "Save all settings to a file.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "defaults")), - "Restore default values from DEFAULTS.SRF. If this file does not exist, GenSurf " - "initializes all input parameters to reasonable values. You can create your own " - "default surface by setting all parameters to your liking, then saving a settings " - "file as DEFAULTS.SRF with the Save As button.", - ""); - - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "main_preview")), - "View a wire-frame representation of the surface", - ""); - - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "main_antialiasing")), - "The lines in the preview window are antialiased for better quality", - ""); - - // General tab - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (wave_radios[0]), - "Builds a surface with alternating hills and valleys. Uses the general form Z=cos(X) " - "x sin(Y)", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (wave_radios[1]), - "Builds a surface with ridges parallel to the vertical axis.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (wave_radios[2]), - "Builds a surface with ridges parallel to the horizontal axis.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (wave_radios[3]), - "Builds a map from a bitmap image representing a contour plot. Click the \"Bitmap\" " - "tab to select the image. GenSurf only supports 256-color (8 bit) " - "bitmaps. GenSurf will work with any 256-color bitmap, but gray scale bitmaps are a bit " - "more intuitive.", - "" ); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (wave_radios[4]), - "Builds a random surface using the Plasma Cloud technique. Variance is controlled " - "by the Roughness input. To build a surface with completely random values not " - "dependent on neighboring vertices, use one of the other waveforms with 0 amplitude.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "wavelength")), - "Enter the wavelength (distance between crests). NOTE: Wavelengths equal to the grid " - "size or 2 times the grid size will result in 0 amplitudes. For best results, the " - "wavelength value should be at least 4 times the grid size (extents divided by the " - "number of divisions", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "amplitude")), - "Enter the height of hills/ridges.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "roughness")), - "Enter the roughness value (noise) for the surface. For fractal surfaces, this value " - "is used as a variance in the fractal calculations.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "random")), - "Seed value for the pseudo-random number generator.", - ""); - // Extents tab - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "hmin")), - "Minimum horizontal coordinate of the surface, i.e. X for a surface parallel to " - "the XY or XZ planes, Y for a surface parallel to the YZ plane. For best results, " - "the extents (maximum-minimum values) in a given direction should be evenly " - "divisible by the number of divisions in that direction.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "hmax")), - "Maximum horizontal coordinate of the surface, i.e. X for a surface parallel to " - "the XY or XZ planes, Y for a surface parallel to the YZ plane. For best results, " - "the extents (maximum-minimum values) in a given direction should be evenly " - "divisible by the number of divisions in that direction.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "vmin")), - "Minimum vertical coordinate of the surface, i.e. Y for a surface parallel to " - "the XY plane, Z for a surface parallel to the XZ or YZ planes. For best results, " - "the extents (maximum-minimum values) in a given direction should be evenly " - "divisible by the number of divisions in that direction.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "vmax")), - "Maximum vertical coordinate of the surface, i.e. Y for a surface parallel to " - "the XY plane, Z for a surface parallel to the XZ or YZ planes. For best results, " - "the extents (maximum-minimum values) in a given direction should be evenly " - "divisible by the number of divisions in that direction.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "nh")), - "Number of divisions in the horizontal direction. For best results, the extents " - "in a given direction should be evenly divisible by the number of divisions in " - "that direction.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "nv")), - "Number of divisions in the vertical direction. For best results, the extents " - "in a given direction should be evenly divisible by the number of divisions in " - "that direction.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "use_patches")), - "Produce one or more curved patches in the shape of your selected surface rather " - "than producing solid brushes. Depending on the size of your surface (and the " - "user's graphic detail settings, which you cannot control), curved surfaces will " - "be represented in the game by a very large number of polygons. Read the warnings " - "concerning curved surfaces on the GenSurf web page before using this feature.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "decimate")), - "Use the slider to control the number of vertices discarded by GenSurf. For many " - "surfaces, you can produce roughly the same shape surface with a high decimation " - "value. This will generally result in a map with lower polygon counts (and better " - "in-game performance). However, this feature should NOT be used for large terrain " - "surfaces in Q3", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "z00")), - "Enter the height of the surface at the lower left corner. This value will likely " - "be modified unless \"Linear Borders\" is checked.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "z01")), - "Enter the height of the surface at the upper left corner. This value will likely " - "be modified unless \"Linear Borders\" is checked.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "z10")), - "Enter the height of the surface at the lower right corner. This value will likely " - "be modified unless \"Linear Borders\" is checked.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "z11")), - "Enter the height of the surface at the upper right corner. This value will likely " - "be modified unless \"Linear Borders\" is checked.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "linearborder")), - "Restrict the edges of the surface to a straight line. This will help match up " - "brush edges if you drop this surface into another map.", - ""); - // Bitmap tab - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_file")), - "Type the name of an 8-bit bitmap image file, or click Browse to select an image " - "from a list of those available on your system.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_file_browse")), - "Select a bitmap image file from a list of those available on your system.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_reload")), - "Reload the selected bitmap file after making changes in an external image editor.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_black")), - "Enter the value corresponding to color index 0 in the bitmap file. For gray scale " - "images, color 0 is normally black.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_white")), - "Enter the value corresponding to color index 255 in the bitmap file. For gray scale " - "images, color 255 is normally white.", - ""); - // Fixpoints tab - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "fix_value")), - "Enter a value for the selected vertex. This value will not be adjusted when applying " - "a waveform or roughness to the surface. Unlock this vertex (so that it will be " - "adjusted normally) by clicking \"Free\". This vertex will influence vertices within " - "the \"Range affected\" of this vertex.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "fix_range")), - "Enter the range away from the selected vertex that other vertices will be affected. " - "Use 0 if you don't want other vertices to be influenced by the currently selected " - "one. Note: this box is disabled if you've chosen the fractal generator, as it uses " - "a completely different method for determining values.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "fix_rate")), - "Enter a rate of change for the surface affected by the fixed value. 0 gives a smooth " - "sinusoidal curve, values less than 0 give progressively sharper spikes, and values " - "greater than 0 take on a square shape. Values less than -30 or greater than 30 are " - "set to -30 and 30, respectively. Note that this entry will have no effect unless " - "you also specify a \"range affected\".", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "fix_free")), - "Click this to free (unlock the value of) the currently selected vertex.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "fix_freeall")), - "Click this to free (unlock the values of) all vertices.", - ""); - // Texture tab - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "texture1")), - "Enter the name of the texture or shader used for the surface faces.", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "texture2")), - "Enter the name of the texture or shader used for faces other than the surface. Under " - "normal circumstances this should be \"common/caulk\"", - ""); - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "texture3")), - "Enter the name of the texture or shader used for \"steep\" surface faces, where \"steep\" " - "is the angle specified below. If this entry is left blank or if the \"steep\" angle is 0, " - "all surface faces will use the texture specified by \"Surface\".", - ""); - - gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), - GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "detail")), - "Check this box to use the detail content property on the generated brushes. Compile " - "times will be considerably shorter if the detail property is used, though the surface " - "will not block visibility at all. If you use the detail property, you should make sure " - "that \"common/caulk\" is used for the non-surface faces, or the polygon count will be " - "much higher than necessary.", - ""); -} - -// ============================================================================= -// create main dialog - -GtkWidget* create_main_dialog () -{ - GtkWidget *dlg, *vbox, *hbox, *hbox2, *button, *notebook, *frame, *table, *table2; - GtkWidget *check, *spin, *radio, *label, *entry, *scale; - GtkObject *adj; - GSList *group; - int i; - char *games[] = { "Quake 2", "Half-Life", "SiN", "Heretic 2", "Kingpin", "Genesis3D", "Quake 3 Arena" }; - char *waveforms[] = { "Alternating hill/valley", "Cylindrical left-to-right", "Cylindrical top-to-bottom", - "From bitmap", "Fractal" }; - char *orientations[] = { "Ground surface", "Ceiling", "Wall facing 0", "Wall facing 90", - "Wall facing 180","Wall facing 270" }; - - g_pWnd = dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), gszCaption); - g_signal_connect (G_OBJECT (dlg), "delete_event", G_CALLBACK (main_close), NULL); - // g_signal_connect (G_OBJECT (dlg), "destroy", G_CALLBACK (gtk_widget_destroy), NULL); - gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pRadiantWnd)); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_container_add (GTK_CONTAINER (dlg), hbox); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - - notebook = gtk_notebook_new (); - gtk_widget_show (notebook); - gtk_box_pack_start (GTK_BOX (hbox), notebook, TRUE, TRUE, 0); - g_signal_connect (G_OBJECT (notebook), "switch_page", - G_CALLBACK (switch_page), NULL); - gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP); - g_object_set_data (G_OBJECT (dlg), "notebook", notebook); - - table = gtk_table_new (2, 2, FALSE); - gtk_widget_show (table); - gtk_container_set_border_width (GTK_CONTAINER (table), 5); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("General"); - gtk_widget_show (label); - gtk_notebook_append_page (GTK_NOTEBOOK (notebook), table, label); - - frame = gtk_frame_new ("Game"); - gtk_widget_show (frame); - gtk_table_attach (GTK_TABLE (table), frame, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - - vbox = gtk_vbox_new (TRUE, 5); - gtk_widget_show (vbox); - gtk_container_add (GTK_CONTAINER (frame), vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - - for (i = 0, group = NULL; i < NUMGAMES; i++) - { - radio = gtk_radio_button_new_with_label (group, games[i]); - gtk_widget_show (radio); - gtk_box_pack_start (GTK_BOX (vbox), radio, TRUE, TRUE, 0); - group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio)); - game_radios[i] = radio; - g_signal_connect (G_OBJECT (radio), "toggled", G_CALLBACK (general_game), GINT_TO_POINTER (i)); - } - - frame = gtk_frame_new ("Waveform"); - gtk_widget_show (frame); - gtk_table_attach (GTK_TABLE (table), frame, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - - vbox = gtk_vbox_new (TRUE, 5); - gtk_widget_show (vbox); - gtk_container_add (GTK_CONTAINER (frame), vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - - for (i = 0, group = NULL; i < 5; i++) - { - radio = gtk_radio_button_new_with_label (group, waveforms[i]); - gtk_widget_show (radio); - gtk_box_pack_start (GTK_BOX (vbox), radio, TRUE, TRUE, 0); - group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio)); - wave_radios[i] = radio; - g_signal_connect (G_OBJECT (radio), "toggled", G_CALLBACK (general_wave), GINT_TO_POINTER (i)); - } - - frame = gtk_frame_new ("Orientation"); - gtk_widget_show (frame); - gtk_table_attach (GTK_TABLE (table), frame, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - - vbox = gtk_vbox_new (TRUE, 5); - gtk_widget_show (vbox); - gtk_container_add (GTK_CONTAINER (frame), vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - - for (i = 0, group = NULL; i < 6; i++) - { - radio = gtk_radio_button_new_with_label (group, orientations[i]); - gtk_widget_show (radio); - gtk_box_pack_start (GTK_BOX (vbox), radio, TRUE, TRUE, 0); - group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio)); - plane_radios[i] = radio; - g_signal_connect (G_OBJECT (radio), "toggled", G_CALLBACK (general_plane), GINT_TO_POINTER (i)); - } - - table2 = gtk_table_new (4, 2, FALSE); - gtk_widget_show (table2); - gtk_table_set_row_spacings (GTK_TABLE (table2), 5); - gtk_table_set_col_spacings (GTK_TABLE (table2), 5); - gtk_table_attach (GTK_TABLE (table), table2, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - - label = gtk_label_new ("Wavelength:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); - - label = gtk_label_new ("Max. amplitude:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); - - label = gtk_label_new ("Roughness:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); - - label = gtk_label_new ("Random seed:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 3, 4, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table2), entry, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - g_object_set_data (G_OBJECT (dlg), "wavelength", entry); - g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &WaveLength); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table2), entry, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - g_object_set_data (G_OBJECT (dlg), "amplitude", entry); - g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Amplitude); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table2), entry, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - g_object_set_data (G_OBJECT (dlg), "roughness", entry); - g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Roughness); - - adj = gtk_adjustment_new (1, 1, 32767, 1, 10, 10); - g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (general_random), NULL); - spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); - gtk_widget_show (spin); - gtk_table_attach (GTK_TABLE (table2), spin, 1, 2, 3, 4, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - gtk_widget_set_usize (spin, 60, -2); - g_object_set_data (G_OBJECT (dlg), "random", spin); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - - label = gtk_label_new ("Extents"); - gtk_widget_show (label); - gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); - - hbox2 = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox2); - gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, TRUE, 0); - - frame = gtk_frame_new ("Extents"); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (hbox2), frame, TRUE, TRUE, 0); - - table = gtk_table_new (3, 4, FALSE); - gtk_widget_show (table); - gtk_container_set_border_width (GTK_CONTAINER (table), 5); - gtk_container_add (GTK_CONTAINER (frame), table); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("X:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - g_object_set_data (G_OBJECT (dlg), "hmin_text", label); - - label = gtk_label_new ("X:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - g_object_set_data (G_OBJECT (dlg), "hmax_text", label); - - label = gtk_label_new ("Y:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - g_object_set_data (G_OBJECT (dlg), "vmin_text", label); - - label = gtk_label_new ("Y:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 2, 3, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - g_object_set_data (G_OBJECT (dlg), "vmax_text", label); - - label = gtk_label_new ("Lower-left"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label = gtk_label_new ("Upper-right"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 3, 4, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - g_object_set_data (G_OBJECT (dlg), "hmin", entry); - g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Hll); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - g_object_set_data (G_OBJECT (dlg), "hmax", entry); - g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Hur); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - g_object_set_data (G_OBJECT (dlg), "vmin", entry); - g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Vll); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 2, 3, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - g_object_set_data (G_OBJECT (dlg), "vmax", entry); - g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Vur); - - frame = gtk_frame_new ("Divisions"); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (hbox2), frame, TRUE, TRUE, 0); - - table = gtk_table_new (2, 2, FALSE); - gtk_widget_show (table); - gtk_container_set_border_width (GTK_CONTAINER (table), 5); - gtk_container_add (GTK_CONTAINER (frame), table); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("X:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - g_object_set_data (G_OBJECT (dlg), "nh_text", label); - - label = gtk_label_new ("Y:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - g_object_set_data (G_OBJECT (dlg), "nv_text", label); - - adj = gtk_adjustment_new (8, 1, MAX_ROWS, 1, 10, 10); - g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (extents_nhnv_spin), &NH); - spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); - gtk_widget_show (spin); - gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - gtk_widget_set_usize (spin, 60, -2); - g_object_set_data (G_OBJECT (dlg), "nh", spin); - - adj = gtk_adjustment_new (8, 1, MAX_ROWS, 1, 10, 10); - g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (extents_nhnv_spin), &NV); - spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); - gtk_widget_show (spin); - gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - gtk_widget_set_usize (spin, 60, -2); - g_object_set_data (G_OBJECT (dlg), "nv", spin); - - check = gtk_check_button_new_with_label ("Use Bezier patches"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); - g_object_set_data (G_OBJECT (dlg), "use_patches", check); - g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (extents_use_patches), NULL); - - // ^Fishman - Snap to grid, replaced scroll bar with a texbox. - label = gtk_label_new ("Snap to grid:"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); - gtk_object_set_data (GTK_OBJECT (dlg), "snap_text", label); - - adj = gtk_adjustment_new (8, 0, 256, 1, 10, 10); - g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (extents_snaptogrid_spin), &SP); - spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); - gtk_widget_show (spin); - gtk_box_pack_start (GTK_BOX (vbox), spin, FALSE, TRUE, 0); - gtk_widget_set_usize (spin, 60, -2); - g_object_set_data (G_OBJECT (dlg), "sp", spin); - // ^Fishman - End of Snap to grid code. - - hbox2 = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox2); - gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, TRUE, 10); - - label = gtk_label_new ("Decimate:"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 0); - - adj = gtk_adjustment_new (0, 0, 110, 1, 10, 10); - g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (extents_decimate), NULL); - g_object_set_data (G_OBJECT (dlg), "decimate_adj", adj); - scale = gtk_hscale_new (GTK_ADJUSTMENT (adj)); - gtk_widget_show (scale); - gtk_box_pack_start (GTK_BOX (hbox2), scale, TRUE, TRUE, 0); - gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_RIGHT); - gtk_scale_set_digits (GTK_SCALE (scale), 0); - g_object_set_data (G_OBJECT (dlg), "decimate", scale); - - frame = gtk_frame_new ("Corner values"); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); - - table = gtk_table_new (3, 4, FALSE); - gtk_widget_show (table); - gtk_container_set_border_width (GTK_CONTAINER (table), 5); - gtk_container_add (GTK_CONTAINER (frame), table); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("Upper-left:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label = gtk_label_new ("Lower-left:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label = gtk_label_new ("Upper-right:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label = gtk_label_new ("Lower-right:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - g_object_set_data (G_OBJECT (dlg), "z01", entry); - g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Z01); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - g_object_set_data (G_OBJECT (dlg), "z00", entry); - g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Z00); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 0, 1, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - g_object_set_data (G_OBJECT (dlg), "z11", entry); - g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Z11); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - g_object_set_data (G_OBJECT (dlg), "z10", entry); - g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Z10); - - check = gtk_check_button_new_with_label ("Linear borders"); - gtk_widget_show (check); - gtk_table_attach (GTK_TABLE (table), check, 0, 4, 2, 3, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - g_object_set_data (G_OBJECT (dlg), "linearborder", check); - g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (extents_linearborder), NULL); - - vbox = gtk_vbox_new (FALSE, 10); - gtk_widget_show (vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - - label = gtk_label_new ("Bitmap"); - gtk_widget_show (label); - gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); - - label = gtk_label_new (""); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); - g_object_set_data (G_OBJECT (dlg), "bmp_note", label); - - table = gtk_table_new (2, 2, FALSE); - gtk_widget_show (table); - gtk_container_set_border_width (GTK_CONTAINER (table), 5); - gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("Filename:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - g_object_set_data (G_OBJECT (dlg), "bmp_text1", label); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - g_object_set_data (G_OBJECT (dlg), "bmp_file", entry); - g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (bitmap_file_entryfocusout), NULL); - - hbox2 = gtk_hbox_new (TRUE, 5); - gtk_widget_show (hbox2); - gtk_table_attach (GTK_TABLE (table), hbox2, 1, 2, 1, 2, - (GtkAttachOptions) (0), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - - button = gtk_button_new_with_label ("Browse..."); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, FALSE, 0); - gtk_widget_set_usize (button, 60, -2); - g_object_set_data (G_OBJECT (dlg), "bmp_file_browse", button); - g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (bitmap_browse), NULL); - - button = gtk_button_new_with_label ("Reload"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, FALSE, 0); - gtk_widget_set_usize (button, 60, -2); - g_object_set_data (G_OBJECT (dlg), "bmp_reload", button); - g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (bitmap_reload), NULL); - - table = gtk_table_new (2, 2, TRUE); - gtk_widget_show (table); - gtk_container_set_border_width (GTK_CONTAINER (table), 5); - gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("Map color 0 to:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL|GTK_EXPAND), - (GtkAttachOptions) (GTK_FILL), 0, 0); - g_object_set_data (G_OBJECT (dlg), "bmp_text2", label); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); - - label = gtk_label_new ("Map color 255 to:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL|GTK_EXPAND), - (GtkAttachOptions) (GTK_FILL), 0, 0); - g_object_set_data (G_OBJECT (dlg), "bmp_text3", label); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); - - hbox2 = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox2); - gtk_table_attach (GTK_TABLE (table), hbox2, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_box_pack_start (GTK_BOX (hbox2), entry, FALSE, FALSE, 0); - gtk_widget_set_usize (entry, 50, -2); - g_object_set_data (G_OBJECT (dlg), "bmp_black", entry); - g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &gbmp.black_value); - - hbox2 = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox2); - gtk_table_attach (GTK_TABLE (table), hbox2, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_box_pack_start (GTK_BOX (hbox2), entry, FALSE, FALSE, 0); - gtk_widget_set_usize (entry, 50, -2); - g_object_set_data (G_OBJECT (dlg), "bmp_white", entry); - g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &gbmp.white_value); - - vbox = gtk_vbox_new (FALSE, 10); - gtk_widget_show (vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - - label = gtk_label_new ("Fix Points"); - gtk_widget_show (label); - gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); - - label = gtk_label_new ("Click on a vertex in the lower half of the preview window,\n" - "then use the arrow keys or text box to assign a value.\n" - "Use Ctrl+Click to select multiple vertices/toggle a\n" - "selection. Use Shift+Click to select a range of vertices.\n\n" - "Click \"Free\" to unlock a vertex. Vertices within \"Range\n" - "affected\" will be influenced by this vertex."); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); - - table = gtk_table_new (3, 3, FALSE); - gtk_widget_show (table); - gtk_container_set_border_width (GTK_CONTAINER (table), 5); - gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("Value:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - g_object_set_data (G_OBJECT (dlg), "fix_value_text", label); - - label = gtk_label_new ("Range affected:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - g_object_set_data (G_OBJECT (dlg), "fix_range_text", label); - - label = gtk_label_new ("Rate of change:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - g_object_set_data (G_OBJECT (dlg), "fix_rate_text", label); - - adj = gtk_adjustment_new (0, -65536, 65536, 1, 16, 16); - g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (fix_value_changed), NULL); - spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); - gtk_widget_show (spin); - gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND), - (GtkAttachOptions) (GTK_EXPAND), 0, 0); - gtk_widget_set_usize (spin, 60, -2); - g_object_set_data (G_OBJECT (dlg), "fix_value", spin); - g_signal_connect (G_OBJECT (spin), "focus_out_event", G_CALLBACK (fix_value_entryfocusout), NULL); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_widget_set_usize (entry, 60, -2); - g_object_set_data (G_OBJECT (dlg), "fix_range", entry); - g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (fix_range_entryfocusout), NULL); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_EXPAND), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_widget_set_usize (entry, 60, -2); - g_object_set_data (G_OBJECT (dlg), "fix_rate", entry); - g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (fix_rate_entryfocusout), NULL); - - button = gtk_button_new_with_label ("Free"); - gtk_widget_show (button); - gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_EXPAND), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_widget_set_usize (button, 60, -2); - g_object_set_data (G_OBJECT (dlg), "fix_free", button); - g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (fix_free), NULL); - - button = gtk_button_new_with_label ("Free All"); - gtk_widget_show (button); - gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_EXPAND), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_widget_set_usize (button, 60, -2); - g_object_set_data (G_OBJECT (dlg), "fix_freeall", button); - g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (fix_freeall), NULL); - - vbox = gtk_vbox_new (FALSE, 10); - gtk_widget_show (vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - - label = gtk_label_new ("Texture"); - gtk_widget_show (label); - gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); - - // ^Fishman - Modified to add more labels and textboxes. - table = gtk_table_new (5, 2, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("Surface:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - label = gtk_label_new ("Other:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - label = gtk_label_new ("Steep:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_widget_set_usize (entry, 60, -2); - g_object_set_data (G_OBJECT (dlg), "texture1", entry); - g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK(texture_entryfocusout), GINT_TO_POINTER (0)); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_widget_set_usize (entry, 60, -2); - g_object_set_data (G_OBJECT (dlg), "texture2", entry); - g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK(texture_entryfocusout), GINT_TO_POINTER (1)); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_widget_set_usize (entry, 60, -2); - g_object_set_data (G_OBJECT (dlg), "texture3", entry); - - hbox2 = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox2); - gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, TRUE, 0); - - label = gtk_label_new ("\"Steep\" angle:"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 0); - - adj = gtk_adjustment_new (60, 0, 90, 1, 10, 10); - spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); - gtk_widget_show (spin); - gtk_box_pack_start (GTK_BOX (hbox2), spin, FALSE, TRUE, 0); - g_object_set_data (G_OBJECT (dlg), "tex_slant", spin); - - table = gtk_table_new (2, 4, TRUE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("Offset "); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label = gtk_label_new ("Scale "); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 2, 4, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_widget_set_usize (entry, 60, -2); - g_object_set_data (G_OBJECT (dlg), "texoffsetx", entry); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_widget_set_usize (entry, 60, -2); - g_object_set_data (G_OBJECT (dlg), "texoffsety", entry); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_widget_set_usize (entry, 60, -2); - g_object_set_data (G_OBJECT (dlg), "texscalex", entry); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_widget_set_usize (entry, 60, -2); - g_object_set_data (G_OBJECT (dlg), "texscaley", entry); - - - - check = gtk_check_button_new_with_label ("Use detail brushes"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); - g_object_set_data (G_OBJECT (dlg), "detail", check); - g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (texture_detail), NULL); - - check = gtk_check_button_new_with_label ("Detail hint brushes"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); - g_object_set_data (G_OBJECT (dlg), "hint", check); - g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (texture_hint), NULL); - - // ^Fishman - Add terrain key to func_group. - check = gtk_check_button_new_with_label ("Add terrain key"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); - g_object_set_data (G_OBJECT (dlg), "terrain_ent", check); - g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (texture_terrainent), NULL); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, TRUE, 0); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0); - gtk_widget_set_usize (button, 60, -2); - g_object_set_data (G_OBJECT (dlg), "go", button); - g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (main_go), NULL); - - label = gtk_label_new ("Settings:"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); - - button = gtk_button_new_with_label ("Open..."); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0); - g_object_set_data (G_OBJECT (dlg), "open", button); - g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (main_open), NULL); - - button = gtk_button_new_with_label ("Save as..."); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0); - g_object_set_data (G_OBJECT (dlg), "save", button); - g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (main_save), NULL); - - button = gtk_button_new_with_label ("Defaults"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0); - g_object_set_data (G_OBJECT (dlg), "defaults", button); - g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (main_defaults), NULL); - - button = gtk_button_new_with_label ("About..."); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0); - g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (main_about), NULL); - - check = gtk_check_button_new_with_label ("Preview"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); - g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (main_preview), NULL); - g_object_set_data (G_OBJECT (dlg), "main_preview", check); - - // ^Fishman - Antializing for the preview window. - check = gtk_check_button_new_with_label ("Antialised lines"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); - g_object_set_data (G_OBJECT (dlg), "main_antialiasing", check); - g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (main_antialiasing), NULL); - - for (i = 0; i < 5; i++) - SetDlgValues (i); - - CreateViewWindow (); - - create_tooltips(); - - FirstPassComplete = 1; - - return dlg; -} - - -#if 0 - -HWND hwndDisplay = (HWND)NULL; -HWND ghwndTab = (HWND)NULL; -int iTab=0; -RECT rcTab; -FILE *ftex; - -char GenSurfURL[40] = {"http://tarot.telefragged.com/gensurf"}; -char GenSurfBoard[40]={"http://tarot.telefragged.com/board"}; - -/* -* AboutDlgProc - processes messages for the about dialog. -*/ - -qboolean CALLBACK AboutDlgProc( HWND hwnd, unsigned msg, UINT wparam, LONG lparam ) -{ - char szText[256]; - DRAWITEMSTRUCT *dis; - HDC hdc; - HPEN hpen; - HWND hwndURL; - RECT rc; - SIZE size; - - lparam = lparam; /* turn off warning */ - - switch( msg ) { - case WM_INITDIALOG: - strcpy(szText,"About " ); - strcat(szText,gszCaption); - SetWindowText(hwnd,gszCaption); - SetDlgItemText(hwnd,DLG_ABOUT_APP,szText); - /* Application icon: */ - SendDlgItemMessage( hwnd, DLG_ABOUT_ICON, - STM_SETICON, (WPARAM)(HICON)LoadIcon(ghInst,"GENSURF"), - (LPARAM) NULL); - - hwndURL = GetDlgItem(hwnd,DLG_ABOUT_URL); - hdc = GetDC(hwndURL); - GetTextExtentPoint(hdc,GenSurfURL,strlen(GenSurfURL),&size); - ReleaseDC(hwndURL,hdc); - GetWindowRect(hwndURL,&rc); - SetWindowPos(hwndURL,(HWND)NULL,0,0,size.cx,size.cy+2, - SWP_NOMOVE | SWP_NOZORDER); - - hwndURL = GetDlgItem(hwnd,DLG_ABOUT_BOARD); - hdc = GetDC(hwndURL); - GetTextExtentPoint(hdc,GenSurfBoard,strlen(GenSurfBoard),&size); - ReleaseDC(hwndURL,hdc); - GetWindowRect(hwndURL,&rc); - SetWindowPos(hwndURL,(HWND)NULL,0,0,size.cx,size.cy+2, - SWP_NOMOVE | SWP_NOZORDER); - - return TRUE; - - case WM_COMMAND: - switch(LOWORD(wparam)) - { - case DLG_ABOUT_URL: - HTTP(GenSurfURL); - break; - case DLG_ABOUT_BOARD: - HTTP(GenSurfBoard); - break; - case IDOK: - EndDialog(hwnd,1); - return TRUE; - } - break; - - case WM_DRAWITEM: - if(wparam == DLG_ABOUT_URL) - { - dis = (LPDRAWITEMSTRUCT)lparam; - SetTextColor(dis->hDC,RGB(0,0,255)); - TextOut(dis->hDC,0,0,GenSurfURL,strlen(GenSurfURL)); - GetWindowRect(dis->hwndItem,&rc); - GetTextExtentPoint(dis->hDC,GenSurfURL,strlen(GenSurfURL),&size); - hpen = CreatePen(PS_SOLID,0,RGB(0,0,255)); - SelectObject(dis->hDC,hpen); - MoveToEx(dis->hDC,0,size.cy,NULL); - LineTo(dis->hDC,size.cx,size.cy); - SelectObject(dis->hDC,GetStockObject(BLACK_PEN)); - DeleteObject(hpen); - } - else if(wparam==DLG_ABOUT_BOARD) - { - dis = (LPDRAWITEMSTRUCT)lparam; - SetTextColor(dis->hDC,RGB(0,0,255)); - TextOut(dis->hDC,0,0,GenSurfBoard,strlen(GenSurfBoard)); - GetWindowRect(dis->hwndItem,&rc); - GetTextExtentPoint(dis->hDC,GenSurfBoard,strlen(GenSurfBoard),&size); - hpen = CreatePen(PS_SOLID,0,RGB(0,0,255)); - SelectObject(dis->hDC,hpen); - MoveToEx(dis->hDC,0,size.cy,NULL); - LineTo(dis->hDC,size.cx,size.cy); - SelectObject(dis->hDC,GetStockObject(BLACK_PEN)); - DeleteObject(hpen); - } - break; - - case WM_CLOSE: - EndDialog(hwnd,1); - return TRUE; - - default: - return FALSE; - } - return FALSE; - -} /* AboutDlgProc */ - -void About() -{ - if( DialogBox( ghInst,"About", ghwnd_main, (DLGPROC)AboutDlgProc ) < 0) - { - char Text[256]; - sprintf(Text,"In About(), GetLastError()=0x%08x",GetLastError()); - MessageBox(ghwnd_main,Text,"GenSurf",MB_ICONEXCLAMATION); - } -} - -#endif +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +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 +*/ + +#include +#include +#include +#include +#include +#include "gensurf.h" + +#define GENERAL_TAB 0 +#define EXTENTS_TAB 1 +#define BITMAP_TAB 2 +#define FIXPOINTS_TAB 3 +#define TEXTURE_TAB 4 +//#define BUFF_SIZE 32768 + +#define ENABLE_WIDGET(name,enable) \ + gtk_widget_set_sensitive (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), (name))), (enable)) +#define CHECK_WIDGET(name,check) \ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), name)), check) + +static GtkWidget *game_radios[NUMGAMES]; +static GtkWidget *wave_radios[5]; +static GtkWidget *plane_radios[6]; +static guint current_tab; +static int OldPreview; +static int WasDetail; +static GtkTooltips *tooltips; +static int FirstPassComplete = 0; + +void About (GtkWidget *parent) +{ +/* + char *icon_xpm[] = { +"32 32 4 1", +" c None", +". c #000000", +"+ c #FFFFFF", +"@ c #838183", +"................................", +"................................", +"................................", +"................................", +"................................", +"................................", +"................................", +"...............++...............", +".............++++++.............", +"............++@+++@+............", +"..........+++..++..+++..........", +"........++.+.++..++.+.@+........", +".......+..+..+.++.+..+..++......", +".....++..++.+..++..+.++..++.....", +"...++..++...+.+..+.++..++..++...", +"..++.+.++....++..++....++.+..+..", +".+.+..+..++....++....++..++.+.+.", +"..+++....+.++++++++++.+....+++..", +"....++.@@+++++.++.++++@++.++....", +"......+++++++......++@+++++.....", +".......+++.+.++..++.+..++.......", +".........++..+.++.+..++.........", +"...........++..++..++...........", +".............++..+.+............", +"..............+..+@.............", +"...............@@...............", +"................................", +"................................", +"................................", +"................................", +"................................", +"................................" +}; +*/ + // leo: I'm too lazy to create a nice about box + // ^Fishman - I am lazy too :P. + g_FuncTable.m_pfnMessageBox (parent, "GtkGenSurf 1.05\n\n" + "Original version\n" + "David Hyde (rascal@vicksburg.com)\n\n" + "Porting\n" + "Leonardo Zide (leo@lokigames.com)\n\n" + "Enhancements\n" + "Pablo Zurita (pablo@qeradiant.com)\n" + "Hydra (hydra@hydras-world.com)", + "About GtkGenSurf", MB_OK); +} + +// ============================================================================= +// main dialog + +static void SetupControls () +{ + switch (current_tab) + { + case GENERAL_TAB: + break; + + case EXTENTS_TAB: + if (Game != QUAKE3) + { + gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "use_patches"))); + ENABLE_WIDGET ("use_patches", FALSE); + } + else + { + gtk_widget_show (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "use_patches"))); + ENABLE_WIDGET ("use_patches", TRUE); + } + + if (Game == QUAKE3 && UsePatches != 0) + { + ENABLE_WIDGET ("decimate", FALSE); + } + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "snap_text")), "Snap to grid:"); // ^Fishman - Snap to grid. + break; + + case BITMAP_TAB: + if (WaveType != WAVE_BITMAP) + { + ENABLE_WIDGET ("bmp_file", FALSE); + ENABLE_WIDGET ("bmp_file_browse", FALSE); + ENABLE_WIDGET ("bmp_black", FALSE); + ENABLE_WIDGET ("bmp_white", FALSE); + ENABLE_WIDGET ("bmp_text1", FALSE); + ENABLE_WIDGET ("bmp_text2", FALSE); + ENABLE_WIDGET ("bmp_text3", FALSE); + ENABLE_WIDGET ("bmp_reload", FALSE); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "bmp_note")), + "These options are disabled unless \"From Bitmap\"\n" + "is selected as the Waveform on the General tab."); + } + else + { + ENABLE_WIDGET ("bmp_file", TRUE); + ENABLE_WIDGET ("bmp_file_browse", TRUE); + ENABLE_WIDGET ("bmp_black", TRUE); + ENABLE_WIDGET ("bmp_white", TRUE); + ENABLE_WIDGET ("bmp_text1", TRUE); + ENABLE_WIDGET ("bmp_text2", TRUE); + ENABLE_WIDGET ("bmp_text3", TRUE); + ENABLE_WIDGET ("bmp_reload", strlen(gbmp.name) != 0); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "bmp_note")), + "GenSurf works only with 8-bit bitmaps. Color indices are\n" + "mapped to values for each vertex. Generally, gray scale\n" + "images are stored with black as color 0, white as color 255."); + } + break; + + case FIXPOINTS_TAB: + ENABLE_WIDGET ("fix_value", (NumVerticesSelected != 0)); + ENABLE_WIDGET ("fix_value_text", (NumVerticesSelected != 0)); + ENABLE_WIDGET ("fix_free", (NumVerticesSelected != 0)); + ENABLE_WIDGET ("fix_range", ((NumVerticesSelected != 0) && (WaveType != WAVE_ROUGH_ONLY))); + ENABLE_WIDGET ("fix_range_text", ((NumVerticesSelected != 0) && (WaveType != WAVE_ROUGH_ONLY))); + ENABLE_WIDGET ("fix_rate", ((NumVerticesSelected != 0) && (WaveType != WAVE_ROUGH_ONLY))); + ENABLE_WIDGET ("fix_rate_text", ((NumVerticesSelected != 0) && (WaveType != WAVE_ROUGH_ONLY))); + break; + + case TEXTURE_TAB: + ENABLE_WIDGET ("texture2", (UsePatches == 0)); + ENABLE_WIDGET ("texture3", (UsePatches == 0)); + ENABLE_WIDGET ("tex_slant", (UsePatches == 0)); + ENABLE_WIDGET ("detail", (UsePatches == 0)); + if (Game != QUAKE3 ) + { + ENABLE_WIDGET ("terrain_ent", FALSE); // ^Fishman - Adds terrain key to func_group. + ENABLE_WIDGET ("hint", (UsePatches == 0)); + } + break; + } + + switch (WaveType) + { + case WAVE_HCYLINDER: + case WAVE_VCYLINDER: + ENABLE_WIDGET ("amplitude", TRUE); + ENABLE_WIDGET ("wavelength", TRUE); + ENABLE_WIDGET ("z00", TRUE); + ENABLE_WIDGET ("z01", TRUE); + ENABLE_WIDGET ("z10", TRUE); + ENABLE_WIDGET ("z11", TRUE); + ENABLE_WIDGET ("linearborder", TRUE); + ENABLE_WIDGET ("go", TRUE); + break; + case WAVE_BITMAP: + ENABLE_WIDGET ("amplitude", FALSE); + ENABLE_WIDGET ("wavelength", FALSE); + ENABLE_WIDGET ("z00", FALSE); + ENABLE_WIDGET ("z01", FALSE); + ENABLE_WIDGET ("z10", FALSE); + ENABLE_WIDGET ("z11", FALSE); + ENABLE_WIDGET ("linearborder", FALSE); + ENABLE_WIDGET ("go", (gbmp.colors != NULL ? TRUE : FALSE)); + break; + case WAVE_ROUGH_ONLY: + ENABLE_WIDGET ("amplitude", FALSE); + ENABLE_WIDGET ("wavelength", FALSE); + ENABLE_WIDGET ("z00", TRUE); + ENABLE_WIDGET ("z01", TRUE); + ENABLE_WIDGET ("z10", TRUE); + ENABLE_WIDGET ("z11", TRUE); + ENABLE_WIDGET ("linearborder", TRUE); + ENABLE_WIDGET ("go", TRUE); + break; + default: + ENABLE_WIDGET ("amplitude", TRUE); + ENABLE_WIDGET ("wavelength", TRUE); + ENABLE_WIDGET ("z00", TRUE); + ENABLE_WIDGET ("z01", TRUE); + ENABLE_WIDGET ("z10", TRUE); + ENABLE_WIDGET ("z11", TRUE); + ENABLE_WIDGET ("linearborder", TRUE); + ENABLE_WIDGET ("go", TRUE); + } + + switch (Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmin_text")), "X:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmax_text")), "X:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmin_text")), "Z:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmax_text")), "Z:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nh_text")), "X:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nv_text")), "Z:"); + break; + case PLANE_YZ0: + case PLANE_YZ1: + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmin_text")), "Y:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmax_text")), "Y:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmin_text")), "Z:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmax_text")), "Z:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nh_text")), "Y:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nv_text")), "Z:"); + break; + default: + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmin_text")), "X:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmax_text")), "X:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmin_text")), "Y:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmax_text")), "Y:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nh_text")), "X:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nv_text")), "Y:"); + break; + } +} + +// SetDlgValues fills in text boxes and initializes other input controls +static void SetDlgValues (int tab) +{ + char Text[256]; + char RForm[16] = "%.5g"; + int i; + + switch (tab) + { + case GENERAL_TAB: + // Hell if I know why, but in the release build the 2nd pass thru the + // set_sensitive loop for game_radios crashes. No need to do this more + // than once anyhow. + if (!FirstPassComplete) + { + for (i = 0; i < NUMGAMES; i++) + gtk_widget_set_sensitive (game_radios[i], (i == Game ? TRUE : FALSE)); + for (i = 0; i < 6; i++) + gtk_widget_set_sensitive (plane_radios[i], (i == Plane ? TRUE : FALSE)); + } + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (game_radios[Game]), TRUE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (plane_radios[Plane]), TRUE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wave_radios[WaveType]), TRUE); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "random")), + RandomSeed); + sprintf (Text, RForm, WaveLength); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "wavelength")), Text); + sprintf (Text, RForm, Amplitude); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "amplitude")), Text); + sprintf (Text, RForm, Roughness); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "roughness")), Text); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g_object_get_data + (G_OBJECT (g_pWnd), "main_antialiasing")), Antialiasing); + break; + + case EXTENTS_TAB: + sprintf (Text,RForm,Hll); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "hmin")), Text); + sprintf (Text,RForm,Vll); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "vmin")), Text); + sprintf (Text,RForm,Hur); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "hmax")), Text); + sprintf (Text,RForm,Vur); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "vmax")), Text); + sprintf (Text,RForm,Z00); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "z00")), Text); + sprintf (Text,RForm,Z01); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "z01")), Text); + sprintf (Text,RForm,Z10); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "z10")), Text); + sprintf (Text,RForm,Z11); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "z11")), Text); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "nh")), NH); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "nv")), NV); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "sp")), SP); // ^Fishman - Snap to grid. + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g_object_get_data + (G_OBJECT (g_pWnd), "linearborder")), FixBorders); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g_object_get_data + (G_OBJECT (g_pWnd), "use_patches")), UsePatches); + gtk_adjustment_set_value (GTK_ADJUSTMENT (g_object_get_data (G_OBJECT (g_pWnd), "decimate_adj")), + Decimate); + + if (Game == QUAKE3 && UsePatches) + { + gtk_widget_set_sensitive (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "decimate")), FALSE); + + if (NH % 2) + { + NH++; + if (NH > MAX_ROWS) NH -= 2; + SetDlgValues (current_tab); + } + + if (NV % 2) + { + NV++; + if (NV > MAX_ROWS) NV -= 2; + SetDlgValues (current_tab); + } + if (NH % 2 ) NH++; + if (NH < 2 ) NH = 2; + if (NH > MAX_ROWS) NH = MAX_ROWS; + if (NV % 2 ) NV++; + if (NV < 2 ) NV = 2; + if (NV > MAX_ROWS) NV = MAX_ROWS; + + gpointer spin = g_object_get_data (G_OBJECT (g_pWnd), "nh"); + GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adj->lower = 2; + gtk_adjustment_changed (adj); + spin = g_object_get_data (G_OBJECT (g_pWnd), "nv"); + adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adj->lower = 2; + gtk_adjustment_changed (adj); + } + else + { + gtk_widget_set_sensitive (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "decimate")), TRUE); + + gpointer spin = g_object_get_data (G_OBJECT (g_pWnd), "nh"); + GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adj->lower = 1; + gtk_adjustment_changed (adj); + spin = g_object_get_data (G_OBJECT (g_pWnd), "nv"); + adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adj->lower = 1; + gtk_adjustment_changed (adj); + } + + gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "nh")), NH); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "nv")), NV); + + break; + + case BITMAP_TAB: + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "bmp_file")), gbmp.name); + sprintf(Text,"%g",gbmp.black_value); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "bmp_black")), Text); + sprintf(Text,"%g",gbmp.white_value); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "bmp_white")), Text); + break; + + case FIXPOINTS_TAB: + break; + + case TEXTURE_TAB: + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texture1")), Texture[Game][0]); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texture2")), Texture[Game][1]); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texture3")), Texture[Game][2]); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "tex_slant")), + SlantAngle); + sprintf(Text,RForm,TexOffset[0]); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texoffsetx")), Text); + sprintf(Text,RForm,TexOffset[1]); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texoffsety")), Text); + sprintf(Text,RForm,TexScale[0]); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texscalex")), Text); + sprintf(Text,RForm,TexScale[1]); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texscaley")), Text); + CHECK_WIDGET ("detail", UseDetail); + + if (Game==QUAKE3) + { + ENABLE_WIDGET ("hint", FALSE); + AddHints=0; + } + else + ENABLE_WIDGET ("hint", TRUE); + CHECK_WIDGET ("hint", AddHints); + + /* + if (Game==SIN) + { + // ArghRad doesn't currently support SiN + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), 0); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_TEXT), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), SW_HIDE); + SetDlgItemText(hwndDisplay,DLG_TEX_USEPAK,"Use sin file"); + SetDlgItemText(hwndDisplay,DLG_TEX_PAK_TEXT,"Sin:"); + } + */ + + if(Game==QUAKE3) + { + /* + // ArghRad sun is inapplicable (so far) + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), 0); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_TEXT), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), SW_HIDE); + // No ladders in Q3 + EnableWindow(GetDlgItem(hwndDisplay,DLG_LADDER), 0); + ShowWindow(GetDlgItem(hwndDisplay,DLG_LADDER), SW_HIDE); + SetDlgItemText(hwndDisplay,DLG_TEX_USEPAK,"Use pk3 file"); + SetDlgItemText(hwndDisplay,DLG_TEX_PAK_TEXT,"PK3:"); + */ + } + +/*trix if(Game==HERETIC2) + { + // ArghRad doesn't currently support Heretic2 + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), 0); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_TEXT), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), SW_HIDE); + + SetDlgItemText(hwndDisplay,DLG_TEX_USEPAK,"Use pak file"); + SetDlgItemText(hwndDisplay,DLG_TEX_PAK_TEXT,"Pak:"); + } */ + /* + if(Game==HALFLIFE) + { + // A bunch of controls aren't applicable to HL + EnableWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE_BROWSE), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE2_BROWSE),0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE3_BROWSE),0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_DETAIL), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_LADDER), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), 0); + ShowWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE_BROWSE), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE2_BROWSE),SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE3_BROWSE),SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_DETAIL), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_LADDER), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_TEXT), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), SW_HIDE); + + SetDlgItemText(hwndDisplay,DLG_TEX_USEPAK,"Use wad file"); + SetDlgItemText(hwndDisplay,DLG_TEX_PAK_TEXT,"Wad:"); + SetDlgItemText(hwndDisplay,DLG_HINT,"Hint brushes"); + } + + if(Game==GENESIS3D) + { + // No Q2-type compilers support Genesis3D (including ArghRad) + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), 0); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_TEXT), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), SW_HIDE); + + SetDlgItemText(hwndDisplay,DLG_TEX_USEPAK,"Use sin file"); + SetDlgItemText(hwndDisplay,DLG_TEX_PAK_TEXT,"Sin:"); + } + */ + break; + } + SetupControls (); +} + +static void ReadDlgValues (int tab) +{ + // char Text[256]; + // int i; + + switch (tab) + { + case GENERAL_TAB: + gpointer spin; + Roughness = atof ( gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "roughness")))); + WaveLength = atof ( gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "wavelength")))); + Amplitude = atof ( gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "amplitude")))); + spin = g_object_get_data (G_OBJECT (g_pWnd), "random"); + RandomSeed = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (spin)); + break; + + case EXTENTS_TAB: + SP = atoi (gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "sp")))); + NH = atoi (gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "nh")))); + NV = atoi (gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "nv")))); + + if (Game == QUAKE3 && UsePatches != 0) + { + if (NH % 2 ) NH++; + if (NH < 2 ) NH = 2; + if (NH > MAX_ROWS) NH = MAX_ROWS; + if (NV % 2 ) NV++; + if (NV < 2 ) NV = 2; + if (NV > MAX_ROWS) NV = MAX_ROWS; + } + break; + +#if 0 + case BITMAP_TAB: + + if (WaveType == WAVE_BITMAP) + { + GetDlgItemText(hwnd,DLG_BMP_FILE,gbmp.name,sizeof(gbmp.name)); + CheckValidDIB(hwnd); + GetDlgItemText(hwnd,DLG_BMP_BLACK,Text,sizeof(Text)); + gbmp.black_value = atof(Text); + GetDlgItemText(hwnd,DLG_BMP_WHITE,Text,sizeof(Text)); + gbmp.white_value = atof(Text); + UpdatePreview(TRUE); + } + break; + + case FIXPOINTS_TAB: + GetDlgItemText(hwnd,DLG_FIX_VALUE,Text,sizeof(Text)); + temp.fixed_value = atoi(Text); + GetDlgItemText(hwnd,DLG_FIX_RANGE,Text,sizeof(Text)); + temp.range = atoi(Text); + GetDlgItemText(hwnd,DLG_FIX_RATE, Text,sizeof(Text)); + temp.rate = atof(Text); + for(k=0; k MAX_ROWS) + { + sprintf (Text, "The number of divisions must be > 0 and no greater than %d.", MAX_ROWS); + g_FuncTable.m_pfnMessageBox (g_pWnd, Text, "GenSurf", MB_ICONEXCLAMATION); + gtk_notebook_set_page (GTK_NOTEBOOK (notebook), EXTENTS_TAB); + return; + } + + if (NV < 1 || NV > MAX_ROWS) + { + sprintf (Text, "The number of divisions must be > 0 and no greater than %d.", MAX_ROWS); + g_FuncTable.m_pfnMessageBox (g_pWnd, Text, "GenSurf", MB_ICONEXCLAMATION); + gtk_notebook_set_page (GTK_NOTEBOOK (notebook), EXTENTS_TAB); + return; + } + + if (Hll >= Hur) + { + g_FuncTable.m_pfnMessageBox (g_pWnd, "The \"lower-left\" values must be less than " + "the corresponding \"upper-right\" values in " + "the \"Extent\" box.","GenSurf", MB_OK | MB_ICONEXCLAMATION); + gtk_notebook_set_page (GTK_NOTEBOOK (notebook), EXTENTS_TAB); + return; + } + + if (Vll >= Vur) + { + g_FuncTable.m_pfnMessageBox (g_pWnd,"The \"lower-left\" values must be less than " + "the corresponding \"upper-right\" values in " + "the \"Extent\" box.","GenSurf", MB_OK | MB_ICONEXCLAMATION); + gtk_notebook_set_page (GTK_NOTEBOOK (notebook), EXTENTS_TAB); + return; + } + + if (!strlen (Texture[Game][0])) + { + g_FuncTable.m_pfnMessageBox (g_pWnd, "You must supply a texture name.", "GenSurf", MB_ICONEXCLAMATION); + gtk_notebook_set_page (GTK_NOTEBOOK (notebook), EXTENTS_TAB); + return; + } + +/* if (Decimate>0 && GimpHints!=0) + { + MessageBox(hwnd,"You've elected to use a decimated grid and gimp's non-detail hint brushes. " + "This combination usually produces bizarre visual errors in the game, " + "so GenSurf has turned off the hint brush option.", + "GenSurf",MB_ICONEXCLAMATION); + GimpHints = 0; + } */ + + gtk_widget_hide (g_pWnd); + if (g_pWndPreview) + gtk_widget_hide (g_pWndPreview); + + GenerateMap(); + WriteIniFile(gszIni); +} + +// ============================================================================= +// general tab callbacks + +static void general_game (GtkToggleButton *widget, gpointer data) +{ + if (gtk_toggle_button_get_active (widget)) + { + Game = GPOINTER_TO_INT (data); + UpdatePreview (TRUE); + } +} + +static void general_plane (GtkToggleButton *widget, gpointer data) +{ + if (gtk_toggle_button_get_active (widget)) + { + Plane = GPOINTER_TO_INT (data); + SetupControls (); + UpdatePreview (TRUE); + } +} + +static void general_wave (GtkToggleButton *widget, gpointer data) +{ + if (gtk_toggle_button_get_active (widget)) + { + WaveType = GPOINTER_TO_INT (data); + SetupControls (); + UpdatePreview (TRUE); + } +} + +static void general_random (GtkAdjustment *adj, gpointer data) +{ + int nPos = (int)adj->value; + + if (RandomSeed != nPos) + { + RandomSeed = nPos; + UpdatePreview (true); + } +} + +// ============================================================================= +// extents tab callbacks + +static void extents_linearborder (GtkToggleButton *check, gpointer data) +{ + FixBorders = gtk_toggle_button_get_active (check); + UpdatePreview (true); +} + +static void extents_use_patches (GtkToggleButton *check, gpointer data) +{ + if (Game != QUAKE3) + return; + + UsePatches = gtk_toggle_button_get_active (check); + SetDlgValues (current_tab); + SetupControls (); + UpdatePreview (true); +} + +static void extents_nhnv_spin (GtkAdjustment *adj, int *data) +{ + int nPos = (int)adj->value; + + if (*data != nPos) + { + if (Game==QUAKE3 && UsePatches && (nPos % 2)) + { + if (*data < nPos) + *data += 2; + else + *data -= 2; + gtk_adjustment_set_value (adj, *data); + } + else + *data = nPos; + UpdatePreview (true); + } +} + +static void extents_decimate (GtkAdjustment *adj, gpointer data) +{ + int nPos = (int)adj->value; + + Decimate = nPos; + UpdatePreview (true); +} + +// Hydra : snap to grid begin +/*static void extents_snaptogrid (GtkAdjustment *adj, gpointer data) +{ + int nPos = (int)adj->value; + + SnapToGrid = nPos; + UpdatePreview (true); +}*/ + +// ^Fishman - Modified version of Hydra's snap to grid code. +static void extents_snaptogrid_spin (GtkAdjustment *adj, int *data) +{ + int nPos = (int)adj->value; + SnapToGrid = nPos; + UpdatePreview (true); +} + +// ============================================================================= +// bitmap tab callbacks + +static gint bitmap_file_entryfocusout(GtkWidget* widget, GdkEventFocus* event, gpointer data) +{ + char filename[NAME_MAX]; + + strcpy (filename, gtk_entry_get_text (GTK_ENTRY(widget))); + if(strcmp (filename,gbmp.name)) + { + if (gbmp.colors) + { + free(gbmp.colors); + gbmp.colors=NULL; + } + strcpy (gbmp.name,filename); + if (strlen(gbmp.name) ) + OpenBitmap (); + ENABLE_WIDGET ("go", (gbmp.colors != NULL ? TRUE : FALSE)); + } + return FALSE; +} + +static void bitmap_browse (GtkWidget *widget, gpointer data) +{ + const char *filename; + char *ptr; + + filename = g_FuncTable.m_pfnFileDialog (g_pWnd, TRUE, "Bitmap File", gbmp.defpath); + + if (filename != NULL) + { + strcpy (gbmp.name, filename); + + ptr = strrchr (filename, G_DIR_SEPARATOR); + if (ptr != NULL) + { + *(ptr+1) = '\0'; + strcpy (gbmp.defpath, filename); + } + + OpenBitmap (); + ENABLE_WIDGET ("go", (gbmp.colors != NULL ? TRUE : FALSE)); + } +} + +static void bitmap_reload (GtkWidget *widget, gpointer data) +{ + strcpy (gbmp.name, gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "bmp_file")))); + if(strlen (gbmp.name) ) + { + OpenBitmap (); + ENABLE_WIDGET ("go", (gbmp.colors != NULL ? TRUE : FALSE)); + } + else + ENABLE_WIDGET ("go", FALSE ); +} + +// ============================================================================= +// fix points tab callbacks + +static gint fix_value_entryfocusout (GtkWidget* widget, GdkEventFocus *event, gpointer data) +{ + int i = atoi (gtk_entry_get_text (GTK_ENTRY(widget))), k; + char Text[32]; + + if (i < -65536 || i > 65536) + { + gdk_beep (); + g_FuncTable.m_pfnMessageBox (g_pWnd, "The value must be between -65536 and 65536, inclusive.", + "GenSurf", MB_OK | MB_ICONEXCLAMATION); + sprintf (Text, "%d", (int)xyz[Vertex[0].i][Vertex[0].j].fixed_value); + gtk_entry_set_text (GTK_ENTRY(widget), Text); + gtk_window_set_focus (GTK_WINDOW (gtk_widget_get_toplevel (widget)), widget); + } + else if (i != xyz[Vertex[0].i][Vertex[0].j].fixed_value) + { + for(k=0; kvalue; + + if (xyz[Vertex[0].i][Vertex[0].j].fixed_value != i) + { + for(k=0; k(data)); + return FALSE; +} + +// ============================================================================= +// create tooltips + +void create_tooltips () +{ + tooltips = gtk_tooltips_new (); + + // Main + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "go")), + "Accept all input and generate a surface in Q3Radiant", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "open")), + "Open a previously saved GenSurf settings file.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "save")), + "Save all settings to a file.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "defaults")), + "Restore default values from DEFAULTS.SRF. If this file does not exist, GenSurf " + "initializes all input parameters to reasonable values. You can create your own " + "default surface by setting all parameters to your liking, then saving a settings " + "file as DEFAULTS.SRF with the Save As button.", + ""); + + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "main_preview")), + "View a wire-frame representation of the surface", + ""); + + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "main_antialiasing")), + "The lines in the preview window are antialiased for better quality", + ""); + + // General tab + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (wave_radios[0]), + "Builds a surface with alternating hills and valleys. Uses the general form Z=cos(X) " + "x sin(Y)", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (wave_radios[1]), + "Builds a surface with ridges parallel to the vertical axis.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (wave_radios[2]), + "Builds a surface with ridges parallel to the horizontal axis.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (wave_radios[3]), + "Builds a map from a bitmap image representing a contour plot. Click the \"Bitmap\" " + "tab to select the image. GenSurf only supports 256-color (8 bit) " + "bitmaps. GenSurf will work with any 256-color bitmap, but gray scale bitmaps are a bit " + "more intuitive.", + "" ); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (wave_radios[4]), + "Builds a random surface using the Plasma Cloud technique. Variance is controlled " + "by the Roughness input. To build a surface with completely random values not " + "dependent on neighboring vertices, use one of the other waveforms with 0 amplitude.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "wavelength")), + "Enter the wavelength (distance between crests). NOTE: Wavelengths equal to the grid " + "size or 2 times the grid size will result in 0 amplitudes. For best results, the " + "wavelength value should be at least 4 times the grid size (extents divided by the " + "number of divisions", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "amplitude")), + "Enter the height of hills/ridges.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "roughness")), + "Enter the roughness value (noise) for the surface. For fractal surfaces, this value " + "is used as a variance in the fractal calculations.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "random")), + "Seed value for the pseudo-random number generator.", + ""); + // Extents tab + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "hmin")), + "Minimum horizontal coordinate of the surface, i.e. X for a surface parallel to " + "the XY or XZ planes, Y for a surface parallel to the YZ plane. For best results, " + "the extents (maximum-minimum values) in a given direction should be evenly " + "divisible by the number of divisions in that direction.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "hmax")), + "Maximum horizontal coordinate of the surface, i.e. X for a surface parallel to " + "the XY or XZ planes, Y for a surface parallel to the YZ plane. For best results, " + "the extents (maximum-minimum values) in a given direction should be evenly " + "divisible by the number of divisions in that direction.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "vmin")), + "Minimum vertical coordinate of the surface, i.e. Y for a surface parallel to " + "the XY plane, Z for a surface parallel to the XZ or YZ planes. For best results, " + "the extents (maximum-minimum values) in a given direction should be evenly " + "divisible by the number of divisions in that direction.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "vmax")), + "Maximum vertical coordinate of the surface, i.e. Y for a surface parallel to " + "the XY plane, Z for a surface parallel to the XZ or YZ planes. For best results, " + "the extents (maximum-minimum values) in a given direction should be evenly " + "divisible by the number of divisions in that direction.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "nh")), + "Number of divisions in the horizontal direction. For best results, the extents " + "in a given direction should be evenly divisible by the number of divisions in " + "that direction.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "nv")), + "Number of divisions in the vertical direction. For best results, the extents " + "in a given direction should be evenly divisible by the number of divisions in " + "that direction.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "use_patches")), + "Produce one or more curved patches in the shape of your selected surface rather " + "than producing solid brushes. Depending on the size of your surface (and the " + "user's graphic detail settings, which you cannot control), curved surfaces will " + "be represented in the game by a very large number of polygons. Read the warnings " + "concerning curved surfaces on the GenSurf web page before using this feature.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "decimate")), + "Use the slider to control the number of vertices discarded by GenSurf. For many " + "surfaces, you can produce roughly the same shape surface with a high decimation " + "value. This will generally result in a map with lower polygon counts (and better " + "in-game performance). However, this feature should NOT be used for large terrain " + "surfaces in Q3", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "z00")), + "Enter the height of the surface at the lower left corner. This value will likely " + "be modified unless \"Linear Borders\" is checked.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "z01")), + "Enter the height of the surface at the upper left corner. This value will likely " + "be modified unless \"Linear Borders\" is checked.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "z10")), + "Enter the height of the surface at the lower right corner. This value will likely " + "be modified unless \"Linear Borders\" is checked.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "z11")), + "Enter the height of the surface at the upper right corner. This value will likely " + "be modified unless \"Linear Borders\" is checked.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "linearborder")), + "Restrict the edges of the surface to a straight line. This will help match up " + "brush edges if you drop this surface into another map.", + ""); + // Bitmap tab + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_file")), + "Type the name of an 8-bit bitmap image file, or click Browse to select an image " + "from a list of those available on your system.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_file_browse")), + "Select a bitmap image file from a list of those available on your system.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_reload")), + "Reload the selected bitmap file after making changes in an external image editor.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_black")), + "Enter the value corresponding to color index 0 in the bitmap file. For gray scale " + "images, color 0 is normally black.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_white")), + "Enter the value corresponding to color index 255 in the bitmap file. For gray scale " + "images, color 255 is normally white.", + ""); + // Fixpoints tab + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "fix_value")), + "Enter a value for the selected vertex. This value will not be adjusted when applying " + "a waveform or roughness to the surface. Unlock this vertex (so that it will be " + "adjusted normally) by clicking \"Free\". This vertex will influence vertices within " + "the \"Range affected\" of this vertex.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "fix_range")), + "Enter the range away from the selected vertex that other vertices will be affected. " + "Use 0 if you don't want other vertices to be influenced by the currently selected " + "one. Note: this box is disabled if you've chosen the fractal generator, as it uses " + "a completely different method for determining values.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "fix_rate")), + "Enter a rate of change for the surface affected by the fixed value. 0 gives a smooth " + "sinusoidal curve, values less than 0 give progressively sharper spikes, and values " + "greater than 0 take on a square shape. Values less than -30 or greater than 30 are " + "set to -30 and 30, respectively. Note that this entry will have no effect unless " + "you also specify a \"range affected\".", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "fix_free")), + "Click this to free (unlock the value of) the currently selected vertex.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "fix_freeall")), + "Click this to free (unlock the values of) all vertices.", + ""); + // Texture tab + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "texture1")), + "Enter the name of the texture or shader used for the surface faces.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "texture2")), + "Enter the name of the texture or shader used for faces other than the surface. Under " + "normal circumstances this should be \"common/caulk\"", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "texture3")), + "Enter the name of the texture or shader used for \"steep\" surface faces, where \"steep\" " + "is the angle specified below. If this entry is left blank or if the \"steep\" angle is 0, " + "all surface faces will use the texture specified by \"Surface\".", + ""); + + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "detail")), + "Check this box to use the detail content property on the generated brushes. Compile " + "times will be considerably shorter if the detail property is used, though the surface " + "will not block visibility at all. If you use the detail property, you should make sure " + "that \"common/caulk\" is used for the non-surface faces, or the polygon count will be " + "much higher than necessary.", + ""); +} + +// ============================================================================= +// create main dialog + +GtkWidget* create_main_dialog () +{ + GtkWidget *dlg, *vbox, *hbox, *hbox2, *button, *notebook, *frame, *table, *table2; + GtkWidget *check, *spin, *radio, *label, *entry, *scale; + GtkObject *adj; + GSList *group; + int i; + char *games[] = { "Quake 2", "Half-Life", "SiN", "Heretic 2", "Kingpin", "Genesis3D", "Quake 3 Arena" }; + char *waveforms[] = { "Alternating hill/valley", "Cylindrical left-to-right", "Cylindrical top-to-bottom", + "From bitmap", "Fractal" }; + char *orientations[] = { "Ground surface", "Ceiling", "Wall facing 0", "Wall facing 90", + "Wall facing 180","Wall facing 270" }; + + g_pWnd = dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), gszCaption); + g_signal_connect (G_OBJECT (dlg), "delete_event", G_CALLBACK (main_close), NULL); + // g_signal_connect (G_OBJECT (dlg), "destroy", G_CALLBACK (gtk_widget_destroy), NULL); + gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pRadiantWnd)); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + notebook = gtk_notebook_new (); + gtk_widget_show (notebook); + gtk_box_pack_start (GTK_BOX (hbox), notebook, TRUE, TRUE, 0); + g_signal_connect (G_OBJECT (notebook), "switch_page", + G_CALLBACK (switch_page), NULL); + gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP); + g_object_set_data (G_OBJECT (dlg), "notebook", notebook); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("General"); + gtk_widget_show (label); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), table, label); + + frame = gtk_frame_new ("Game"); + gtk_widget_show (frame); + gtk_table_attach (GTK_TABLE (table), frame, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + + vbox = gtk_vbox_new (TRUE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (frame), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + for (i = 0, group = NULL; i < NUMGAMES; i++) + { + radio = gtk_radio_button_new_with_label (group, games[i]); + gtk_widget_show (radio); + gtk_box_pack_start (GTK_BOX (vbox), radio, TRUE, TRUE, 0); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio)); + game_radios[i] = radio; + g_signal_connect (G_OBJECT (radio), "toggled", G_CALLBACK (general_game), GINT_TO_POINTER (i)); + } + + frame = gtk_frame_new ("Waveform"); + gtk_widget_show (frame); + gtk_table_attach (GTK_TABLE (table), frame, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + + vbox = gtk_vbox_new (TRUE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (frame), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + for (i = 0, group = NULL; i < 5; i++) + { + radio = gtk_radio_button_new_with_label (group, waveforms[i]); + gtk_widget_show (radio); + gtk_box_pack_start (GTK_BOX (vbox), radio, TRUE, TRUE, 0); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio)); + wave_radios[i] = radio; + g_signal_connect (G_OBJECT (radio), "toggled", G_CALLBACK (general_wave), GINT_TO_POINTER (i)); + } + + frame = gtk_frame_new ("Orientation"); + gtk_widget_show (frame); + gtk_table_attach (GTK_TABLE (table), frame, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + + vbox = gtk_vbox_new (TRUE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (frame), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + for (i = 0, group = NULL; i < 6; i++) + { + radio = gtk_radio_button_new_with_label (group, orientations[i]); + gtk_widget_show (radio); + gtk_box_pack_start (GTK_BOX (vbox), radio, TRUE, TRUE, 0); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio)); + plane_radios[i] = radio; + g_signal_connect (G_OBJECT (radio), "toggled", G_CALLBACK (general_plane), GINT_TO_POINTER (i)); + } + + table2 = gtk_table_new (4, 2, FALSE); + gtk_widget_show (table2); + gtk_table_set_row_spacings (GTK_TABLE (table2), 5); + gtk_table_set_col_spacings (GTK_TABLE (table2), 5); + gtk_table_attach (GTK_TABLE (table), table2, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + + label = gtk_label_new ("Wavelength:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); + + label = gtk_label_new ("Max. amplitude:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); + + label = gtk_label_new ("Roughness:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); + + label = gtk_label_new ("Random seed:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table2), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "wavelength", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &WaveLength); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table2), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "amplitude", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Amplitude); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table2), entry, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "roughness", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Roughness); + + adj = gtk_adjustment_new (1, 1, 32767, 1, 10, 10); + g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (general_random), NULL); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table2), spin, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + g_object_set_data (G_OBJECT (dlg), "random", spin); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + label = gtk_label_new ("Extents"); + gtk_widget_show (label); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, TRUE, 0); + + frame = gtk_frame_new ("Extents"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (hbox2), frame, TRUE, TRUE, 0); + + table = gtk_table_new (3, 4, FALSE); + gtk_widget_show (table); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("X:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "hmin_text", label); + + label = gtk_label_new ("X:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "hmax_text", label); + + label = gtk_label_new ("Y:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "vmin_text", label); + + label = gtk_label_new ("Y:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "vmax_text", label); + + label = gtk_label_new ("Lower-left"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Upper-right"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "hmin", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Hll); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "hmax", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Hur); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "vmin", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Vll); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 2, 3, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "vmax", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Vur); + + frame = gtk_frame_new ("Divisions"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (hbox2), frame, TRUE, TRUE, 0); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("X:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "nh_text", label); + + label = gtk_label_new ("Y:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "nv_text", label); + + adj = gtk_adjustment_new (8, 1, MAX_ROWS, 1, 10, 10); + g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (extents_nhnv_spin), &NH); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + g_object_set_data (G_OBJECT (dlg), "nh", spin); + + adj = gtk_adjustment_new (8, 1, MAX_ROWS, 1, 10, 10); + g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (extents_nhnv_spin), &NV); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + g_object_set_data (G_OBJECT (dlg), "nv", spin); + + check = gtk_check_button_new_with_label ("Use Bezier patches"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "use_patches", check); + g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (extents_use_patches), NULL); + + // ^Fishman - Snap to grid, replaced scroll bar with a texbox. + label = gtk_label_new ("Snap to grid:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); + gtk_object_set_data (GTK_OBJECT (dlg), "snap_text", label); + + adj = gtk_adjustment_new (8, 0, 256, 1, 10, 10); + g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (extents_snaptogrid_spin), &SP); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_box_pack_start (GTK_BOX (vbox), spin, FALSE, TRUE, 0); + gtk_widget_set_usize (spin, 60, -2); + g_object_set_data (G_OBJECT (dlg), "sp", spin); + // ^Fishman - End of Snap to grid code. + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, TRUE, 10); + + label = gtk_label_new ("Decimate:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 0); + + adj = gtk_adjustment_new (0, 0, 110, 1, 10, 10); + g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (extents_decimate), NULL); + g_object_set_data (G_OBJECT (dlg), "decimate_adj", adj); + scale = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (scale); + gtk_box_pack_start (GTK_BOX (hbox2), scale, TRUE, TRUE, 0); + gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_RIGHT); + gtk_scale_set_digits (GTK_SCALE (scale), 0); + g_object_set_data (G_OBJECT (dlg), "decimate", scale); + + frame = gtk_frame_new ("Corner values"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (3, 4, FALSE); + gtk_widget_show (table); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Upper-left:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Lower-left:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Upper-right:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Lower-right:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "z01", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Z01); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "z00", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Z00); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "z11", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Z11); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "z10", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Z10); + + check = gtk_check_button_new_with_label ("Linear borders"); + gtk_widget_show (check); + gtk_table_attach (GTK_TABLE (table), check, 0, 4, 2, 3, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "linearborder", check); + g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (extents_linearborder), NULL); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_widget_show (vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + label = gtk_label_new ("Bitmap"); + gtk_widget_show (label); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); + + label = gtk_label_new (""); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "bmp_note", label); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Filename:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "bmp_text1", label); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "bmp_file", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (bitmap_file_entryfocusout), NULL); + + hbox2 = gtk_hbox_new (TRUE, 5); + gtk_widget_show (hbox2); + gtk_table_attach (GTK_TABLE (table), hbox2, 1, 2, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + + button = gtk_button_new_with_label ("Browse..."); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, FALSE, 0); + gtk_widget_set_usize (button, 60, -2); + g_object_set_data (G_OBJECT (dlg), "bmp_file_browse", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (bitmap_browse), NULL); + + button = gtk_button_new_with_label ("Reload"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, FALSE, 0); + gtk_widget_set_usize (button, 60, -2); + g_object_set_data (G_OBJECT (dlg), "bmp_reload", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (bitmap_reload), NULL); + + table = gtk_table_new (2, 2, TRUE); + gtk_widget_show (table); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Map color 0 to:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL|GTK_EXPAND), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "bmp_text2", label); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); + + label = gtk_label_new ("Map color 255 to:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL|GTK_EXPAND), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "bmp_text3", label); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_table_attach (GTK_TABLE (table), hbox2, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_box_pack_start (GTK_BOX (hbox2), entry, FALSE, FALSE, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "bmp_black", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &gbmp.black_value); + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_table_attach (GTK_TABLE (table), hbox2, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_box_pack_start (GTK_BOX (hbox2), entry, FALSE, FALSE, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "bmp_white", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &gbmp.white_value); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_widget_show (vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + label = gtk_label_new ("Fix Points"); + gtk_widget_show (label); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); + + label = gtk_label_new ("Click on a vertex in the lower half of the preview window,\n" + "then use the arrow keys or text box to assign a value.\n" + "Use Ctrl+Click to select multiple vertices/toggle a\n" + "selection. Use Shift+Click to select a range of vertices.\n\n" + "Click \"Free\" to unlock a vertex. Vertices within \"Range\n" + "affected\" will be influenced by this vertex."); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); + + table = gtk_table_new (3, 3, FALSE); + gtk_widget_show (table); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Value:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + g_object_set_data (G_OBJECT (dlg), "fix_value_text", label); + + label = gtk_label_new ("Range affected:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + g_object_set_data (G_OBJECT (dlg), "fix_range_text", label); + + label = gtk_label_new ("Rate of change:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + g_object_set_data (G_OBJECT (dlg), "fix_rate_text", label); + + adj = gtk_adjustment_new (0, -65536, 65536, 1, 16, 16); + g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (fix_value_changed), NULL); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND), + (GtkAttachOptions) (GTK_EXPAND), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + g_object_set_data (G_OBJECT (dlg), "fix_value", spin); + g_signal_connect (G_OBJECT (spin), "focus_out_event", G_CALLBACK (fix_value_entryfocusout), NULL); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "fix_range", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (fix_range_entryfocusout), NULL); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "fix_rate", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (fix_rate_entryfocusout), NULL); + + button = gtk_button_new_with_label ("Free"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_EXPAND), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (button, 60, -2); + g_object_set_data (G_OBJECT (dlg), "fix_free", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (fix_free), NULL); + + button = gtk_button_new_with_label ("Free All"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (button, 60, -2); + g_object_set_data (G_OBJECT (dlg), "fix_freeall", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (fix_freeall), NULL); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_widget_show (vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + label = gtk_label_new ("Texture"); + gtk_widget_show (label); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); + + // ^Fishman - Modified to add more labels and textboxes. + table = gtk_table_new (5, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Surface:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + label = gtk_label_new ("Other:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + label = gtk_label_new ("Steep:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "texture1", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK(texture_entryfocusout), GINT_TO_POINTER (0)); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "texture2", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK(texture_entryfocusout), GINT_TO_POINTER (1)); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "texture3", entry); + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, TRUE, 0); + + label = gtk_label_new ("\"Steep\" angle:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 0); + + adj = gtk_adjustment_new (60, 0, 90, 1, 10, 10); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_box_pack_start (GTK_BOX (hbox2), spin, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "tex_slant", spin); + + table = gtk_table_new (2, 4, TRUE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Offset "); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Scale "); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 4, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "texoffsetx", entry); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "texoffsety", entry); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "texscalex", entry); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "texscaley", entry); + + + + check = gtk_check_button_new_with_label ("Use detail brushes"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "detail", check); + g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (texture_detail), NULL); + + check = gtk_check_button_new_with_label ("Detail hint brushes"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "hint", check); + g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (texture_hint), NULL); + + // ^Fishman - Add terrain key to func_group. + check = gtk_check_button_new_with_label ("Add terrain key"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "terrain_ent", check); + g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (texture_terrainent), NULL); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0); + gtk_widget_set_usize (button, 60, -2); + g_object_set_data (G_OBJECT (dlg), "go", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (main_go), NULL); + + label = gtk_label_new ("Settings:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("Open..."); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "open", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (main_open), NULL); + + button = gtk_button_new_with_label ("Save as..."); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "save", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (main_save), NULL); + + button = gtk_button_new_with_label ("Defaults"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "defaults", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (main_defaults), NULL); + + button = gtk_button_new_with_label ("About..."); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (main_about), NULL); + + check = gtk_check_button_new_with_label ("Preview"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); + g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (main_preview), NULL); + g_object_set_data (G_OBJECT (dlg), "main_preview", check); + + // ^Fishman - Antializing for the preview window. + check = gtk_check_button_new_with_label ("Antialised lines"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "main_antialiasing", check); + g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (main_antialiasing), NULL); + + for (i = 0; i < 5; i++) + SetDlgValues (i); + + CreateViewWindow (); + + create_tooltips(); + + FirstPassComplete = 1; + + return dlg; +} + + +#if 0 + +HWND hwndDisplay = (HWND)NULL; +HWND ghwndTab = (HWND)NULL; +int iTab=0; +RECT rcTab; +FILE *ftex; + +char GenSurfURL[40] = {"http://tarot.telefragged.com/gensurf"}; +char GenSurfBoard[40]={"http://tarot.telefragged.com/board"}; + +/* +* AboutDlgProc - processes messages for the about dialog. +*/ + +qboolean CALLBACK AboutDlgProc( HWND hwnd, unsigned msg, UINT wparam, LONG lparam ) +{ + char szText[256]; + DRAWITEMSTRUCT *dis; + HDC hdc; + HPEN hpen; + HWND hwndURL; + RECT rc; + SIZE size; + + lparam = lparam; /* turn off warning */ + + switch( msg ) { + case WM_INITDIALOG: + strcpy(szText,"About " ); + strcat(szText,gszCaption); + SetWindowText(hwnd,gszCaption); + SetDlgItemText(hwnd,DLG_ABOUT_APP,szText); + /* Application icon: */ + SendDlgItemMessage( hwnd, DLG_ABOUT_ICON, + STM_SETICON, (WPARAM)(HICON)LoadIcon(ghInst,"GENSURF"), + (LPARAM) NULL); + + hwndURL = GetDlgItem(hwnd,DLG_ABOUT_URL); + hdc = GetDC(hwndURL); + GetTextExtentPoint(hdc,GenSurfURL,strlen(GenSurfURL),&size); + ReleaseDC(hwndURL,hdc); + GetWindowRect(hwndURL,&rc); + SetWindowPos(hwndURL,(HWND)NULL,0,0,size.cx,size.cy+2, + SWP_NOMOVE | SWP_NOZORDER); + + hwndURL = GetDlgItem(hwnd,DLG_ABOUT_BOARD); + hdc = GetDC(hwndURL); + GetTextExtentPoint(hdc,GenSurfBoard,strlen(GenSurfBoard),&size); + ReleaseDC(hwndURL,hdc); + GetWindowRect(hwndURL,&rc); + SetWindowPos(hwndURL,(HWND)NULL,0,0,size.cx,size.cy+2, + SWP_NOMOVE | SWP_NOZORDER); + + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wparam)) + { + case DLG_ABOUT_URL: + HTTP(GenSurfURL); + break; + case DLG_ABOUT_BOARD: + HTTP(GenSurfBoard); + break; + case IDOK: + EndDialog(hwnd,1); + return TRUE; + } + break; + + case WM_DRAWITEM: + if(wparam == DLG_ABOUT_URL) + { + dis = (LPDRAWITEMSTRUCT)lparam; + SetTextColor(dis->hDC,RGB(0,0,255)); + TextOut(dis->hDC,0,0,GenSurfURL,strlen(GenSurfURL)); + GetWindowRect(dis->hwndItem,&rc); + GetTextExtentPoint(dis->hDC,GenSurfURL,strlen(GenSurfURL),&size); + hpen = CreatePen(PS_SOLID,0,RGB(0,0,255)); + SelectObject(dis->hDC,hpen); + MoveToEx(dis->hDC,0,size.cy,NULL); + LineTo(dis->hDC,size.cx,size.cy); + SelectObject(dis->hDC,GetStockObject(BLACK_PEN)); + DeleteObject(hpen); + } + else if(wparam==DLG_ABOUT_BOARD) + { + dis = (LPDRAWITEMSTRUCT)lparam; + SetTextColor(dis->hDC,RGB(0,0,255)); + TextOut(dis->hDC,0,0,GenSurfBoard,strlen(GenSurfBoard)); + GetWindowRect(dis->hwndItem,&rc); + GetTextExtentPoint(dis->hDC,GenSurfBoard,strlen(GenSurfBoard),&size); + hpen = CreatePen(PS_SOLID,0,RGB(0,0,255)); + SelectObject(dis->hDC,hpen); + MoveToEx(dis->hDC,0,size.cy,NULL); + LineTo(dis->hDC,size.cx,size.cy); + SelectObject(dis->hDC,GetStockObject(BLACK_PEN)); + DeleteObject(hpen); + } + break; + + case WM_CLOSE: + EndDialog(hwnd,1); + return TRUE; + + default: + return FALSE; + } + return FALSE; + +} /* AboutDlgProc */ + +void About() +{ + if( DialogBox( ghInst,"About", ghwnd_main, (DLGPROC)AboutDlgProc ) < 0) + { + char Text[256]; + sprintf(Text,"In About(), GetLastError()=0x%08x",GetLastError()); + MessageBox(ghwnd_main,Text,"GenSurf",MB_ICONEXCLAMATION); + } +} + +#endif diff --git a/contrib/gtkgensurf/genmap.cpp b/contrib/gtkgensurf/genmap.cpp index ace97b68..f4b118b2 100644 --- a/contrib/gtkgensurf/genmap.cpp +++ b/contrib/gtkgensurf/genmap.cpp @@ -1,2056 +1,2056 @@ -/* -GenSurf plugin for GtkRadiant -Copyright (C) 2001 David Hyde, Loki software and qeradiant.com - -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 -*/ - -#include -#include -#include -#include "gensurf.h" - -double xmin,xmax,ymin,ymax,zmin,zmax; -double backface; -extern double dh, dv; -FILE *fmap; -XYZ xyz[MAX_ROWS+1][MAX_ROWS+1]; -int contents; -int surface[3]; -LPVOID h_func_group; -LPVOID terrainkey; // ^Fishman - Add terrain key to func_group. - -//============================================================= -// Hydra : snap-to-grid begin -double CalculateSnapValue(double value) -{ - long snapvalue; - - // simple uncomplicated snapping, rounding both UP and DOWN to the nearest - // grid unit. - if (SnapToGrid >0) - { - snapvalue = (int)value / SnapToGrid; - if ((long)value % SnapToGrid < (SnapToGrid / 2)) // Snap Downwards if less than halfway between to grid units - value = snapvalue * SnapToGrid; - else // Snap Upwards if more than halfway between to grid units - value = (snapvalue+1) * SnapToGrid; - } - return value; -} -// Hydra : snap-to-grid end - -//============================================================= -bool ValidSurface() -{ - if(WaveType == WAVE_BITMAP && !gbmp.colors) return FALSE; - if(NH < 1) return FALSE; - if(NH > MAX_ROWS) return FALSE; - if(NV < 1) return FALSE; - if(NV > MAX_ROWS) return FALSE; - if(Hll >= Hur) return FALSE; - if(Vll >= Vur) return FALSE; - return TRUE; -} - -//============================================================= -int MapPatches() -{ - int NH_remain; - int NV_remain; - int NH_patch; - int NV_patch; - int BrushNum = 0; - int i, j, k1, k2, k3; - int i0, j0, ii; - char szOops[128]; - patchMesh_t p; - - dh = (Hur-Hll)/NH; - dv = (Vur-Vll)/NV; - memset(&p,0,sizeof(patchMesh_t)); - - // Generate control points in pp array to give desired values currently - // in p array. - switch(Plane) - { - case PLANE_XY0: - case PLANE_XY1: - k1 = 0; - k2 = 1; - k3 = 2; - break; - case PLANE_XZ0: - case PLANE_XZ1: - k1 = 0; - k2 = 2; - k3 = 1; - break; - case PLANE_YZ0: - case PLANE_YZ1: - k1 = 1; - k2 = 2; - k3 = 0; - break; - } - for(i=0; i<=NH; i++) - { - for(j=0; j<=NV; j++) - { - xyz[i][j].pp[k1] = xyz[i][j].p[k1]; - xyz[i][j].pp[k2] = xyz[i][j].p[k2]; - } - } - for(i=0; i<=NH; i+=2) - { - for(j=0; j<=NV; j+=2) - xyz[i][j].pp[k3] = xyz[i][j].p[k3]; - } - for(i=1; i 1) - { - if(( (NH_remain-1) % 14) == 0) - NH_patch = 15; - else if(( (NH_remain-1) % 12) == 0) - NH_patch = 13; - else if(( (NH_remain-1) % 10) == 0) - NH_patch = 11; - else if(( (NH_remain-1) % 8) == 0) - NH_patch = 9; - else if(( (NH_remain-1) % 6) == 0) - NH_patch = 7; - else if(( (NH_remain-1) % 4) == 0) - NH_patch = 5; - else if(( (NH_remain-1) % 2) == 0) - NH_patch = 3; - else if(NH_remain > 16) - NH_patch = 7; - else if(NH_remain > 4) - NH_patch = 5; - else - NH_patch = 3; - while( NH_patch > 3 && (NH_patch-1)*dh > 512 ) - NH_patch -= 2; - NH_remain -= (NH_patch-1); - if(NH_remain < 0) - { - sprintf(szOops,"Oops... screwed up with NH=%d",NH); - g_FuncTable.m_pfnMessageBox(NULL,szOops,"Uh oh"); - } - NV_remain = NV+1; - j0 = 0; - while(NV_remain > 1) - { - if(( (NV_remain-1) % 14) == 0) - NV_patch = 15; - else if(( (NV_remain-1) % 12) == 0) - NV_patch = 13; - else if(( (NV_remain-1) % 10) == 0) - NV_patch = 11; - else if(( (NV_remain-1) % 8) == 0) - NV_patch = 9; - else if(( (NV_remain-1) % 6) == 0) - NV_patch = 7; - else if(( (NV_remain-1) % 4) == 0) - NV_patch = 5; - else if(( (NV_remain-1) % 2) == 0) - NV_patch = 3; - else if(NV_remain > 16) - NV_patch = 7; - else if(NV_remain > 4) - NV_patch = 5; - else - NV_patch = 3; - while( NV_patch > 3 && (NV_patch-1)*dh > 512 ) - NV_patch -= 2; - NV_remain -= (NV_patch-1); - if(NV_remain < 0) - { - sprintf(szOops,"Oops... screwed up with NV=%d",NV); - g_FuncTable.m_pfnMessageBox(NULL,szOops,"Uh oh"); - } - - p.width = NH_patch; - p.height = NV_patch; - p.type = PATCH_GENERIC; - for(i=0; i 0 && (Game != QUAKE3 || UsePatches==0) ) - { - MapOut(gNumNodes,gNumTris,gNode,gTri); - /* - ghCursorCurrent = ghCursorDefault; - SetCursor(ghCursorCurrent); - */ - return; - } - - contents = 0; - // HL doesn't have detail property - if((Game != HALFLIFE) && UseDetail) contents += CONTENTS_DETAIL; - // HL and Q3 don't have ladder property - if((Game != HALFLIFE && Game != QUAKE3) && UseLadder) contents += CONTENTS_LADDER; - // Genesis requires solid property to be set explicitly - if(Game == GENESIS3D) contents |= CONTENTS_SOLID; - // Heretic 2 uses different sounds (in surface props) for different texture types - if(Game == HERETIC2) - { - surface[0] = GetDefSurfaceProps(Texture[Game][0]); - surface[1] = GetDefSurfaceProps(Texture[Game][1]); - surface[2] = GetDefSurfaceProps(Texture[Game][2]); - } - else - { - surface[0] = 0; - surface[1] = 0; - surface[2] = 0; - } - if(Game!=QUAKE3 || UsePatches == 0) - MapBrushes(); - - /* - ghCursorCurrent = ghCursorDefault; - SetCursor(ghCursorCurrent); - */ -} - -//============================================================= -void GenerateXYZ() -{ - extern void MakeDecimatedMap(int *, int *, NODE **, TRI **); - double zl, zu; - double wh, wv; - int NHalfcycles; - double a,v,h,ha,va; - double delta, dr, rate; - double range, maxrange; - double r; - int i, j, k, N; - int i0, i1, j0, j1; - int ii, jj; - -// FILE *f; -// char CSV[64]; - - if(!ValidSurface()) return; - - srand(1); - srand(RandomSeed); - - dh = (Hur-Hll)/NH; - dv = (Vur-Vll)/NV; - - // H & V - for(i=0; i<=NH; i++) - { - for(j=0;j<=NV;j++) - { - switch(Plane) - { - case PLANE_XZ0: - case PLANE_XZ1: - xyz[i][j].p[0] = Hll + i*dh; - xyz[i][j].p[2] = Vll + j*dv; - break; - case PLANE_YZ0: - case PLANE_YZ1: - xyz[i][j].p[1] = Hll + i*dh; - xyz[i][j].p[2] = Vll + j*dv; - break; - default: - xyz[i][j].p[0] = Hll + i*dh; - xyz[i][j].p[1] = Vll + j*dv; - } - } - } - - if(WaveType == WAVE_BITMAP) - GenerateBitmapMapping(); - /* - else if(WaveType == WAVE_FORMULA) - DoFormula(); - */ - else - { - // Initialize Z values using bilinear interpolation - for(i=0; i<=NH; i++) - { - zl = Z00 + i*(Z10 - Z00)/NH; - zu = Z01 + i*(Z11 - Z01)/NH; - switch(Plane) - { - case PLANE_XZ0: - case PLANE_XZ1: - for(j=0; j<=NV; j++) - xyz[i][j].p[1] = zl + j*(zu-zl)/NV; - break; - case PLANE_YZ0: - case PLANE_YZ1: - for(j=0; j<=NV; j++) - xyz[i][j].p[0] = zl + j*(zu-zl)/NV; - break; - default: - for(j=0; j<=NV; j++) - xyz[i][j].p[2] = zl + j*(zu-zl)/NV; - } - } - } - - switch(WaveType) - { - case WAVE_COS_SIN: - if(FixBorders) - { - NHalfcycles = (int)((Hur-Hll)/(WaveLength/2.)); - NHalfcycles = max(NHalfcycles,1); - wh = 2.*(Hur-Hll)/NHalfcycles; - NHalfcycles = (int)((Vur-Vll)/(WaveLength/2.)); - wv = 2.*(Vur-Vll)/NHalfcycles; - NHalfcycles = max(NHalfcycles,1); - i0 = 1; - i1 = NH-1; - j0 = 1; - j1 = NV-1; - } - else - { - wh = WaveLength; - wv = WaveLength; - i0 = 0; - i1 = NH; - j0 = 0; - j1 = NV; - } - - for(i=i0; i<=i1; i++) - { - h = Hll + i*dh; - ha = ((h-Hll)/wh)*2.*PI - PI/2.; - for(j=j0; j<=j1; j++) - { - v = Vll + j*dv; - va = ((v-Vll)/wv)*2.*PI; - a = Amplitude * cos( ha ) * sin( va ); - switch(Plane) - { - case PLANE_XY1: - xyz[i][j].p[2] -= a; - break; - case PLANE_XZ0: - xyz[i][j].p[1] += a; - break; - case PLANE_XZ1: - xyz[i][j].p[1] -= a; - break; - case PLANE_YZ0: - xyz[i][j].p[0] += a; - break; - case PLANE_YZ1: - xyz[i][j].p[0] -= a; - break; - default: - xyz[i][j].p[2] += a; - } - } - } - break; - case WAVE_HCYLINDER: - for(i=0; i<=NH; i++) - { - h = Hll + i*dh; - ha = ((h-Hll)/WaveLength)*2.*PI - PI/2.; - for(j=0; j<=NV; j++) - { - a = Amplitude * cos( ha ); - switch(Plane) - { - case PLANE_XY1: - xyz[i][j].p[2] -= a; - break; - case PLANE_XZ0: - xyz[i][j].p[1] += a; - break; - case PLANE_XZ1: - xyz[i][j].p[1] -= a; - break; - case PLANE_YZ0: - xyz[i][j].p[0] += a; - break; - case PLANE_YZ1: - xyz[i][j].p[0] -= a; - break; - default: - xyz[i][j].p[2] += a; - } - } - } - break; - case WAVE_VCYLINDER: - for(i=0; i<=NH; i++) - { - h = Hll + i*dh; - for(j=0; j<=NV; j++) - { - v = Vll + j*dv; - va = ((v-Vll)/WaveLength)*2.*PI; - a = Amplitude * sin( va ); - switch(Plane) - { - case PLANE_XY1: - xyz[i][j].p[2] -= a; - break; - case PLANE_XZ0: - xyz[i][j].p[1] += a; - break; - case PLANE_XZ1: - xyz[i][j].p[1] -= a; - break; - case PLANE_YZ0: - xyz[i][j].p[0] += a; - break; - case PLANE_YZ1: - xyz[i][j].p[0] -= a; - break; - default: - xyz[i][j].p[2] += a; - } - } - } - break; - case WAVE_ROUGH_ONLY: - PlasmaCloud(); - break; - } - - if(WaveType != WAVE_ROUGH_ONLY) - { - // Fixed values - for(i=0; i<=NH; i++) - { - for(j=0; j<=NV; j++) - { - if(xyz[i][j].fixed) - { - switch(Plane) - { - case PLANE_XZ0: - case PLANE_XZ1: - xyz[i][j].p[1] = xyz[i][j].fixed_value; - break; - case PLANE_YZ0: - case PLANE_YZ1: - xyz[i][j].p[0] = xyz[i][j].fixed_value; - break; - default: - xyz[i][j].p[2] = xyz[i][j].fixed_value; - } - - if(xyz[i][j].range > 0) - { - maxrange = pow(xyz[i][j].range,2); // so we don't have to do sqrt's - i0 = i - (int)( floor(xyz[i][j].range/dh - 0.5) + 1 ); - i1 = i + i - i0; - j0 = j - (int)( floor(xyz[i][j].range/dv - 0.5) + 1 ); - j1 = j + j - j0; - if(FixBorders) - { - i0 = max(i0,1); - i1 = min(i1,NH-1); - j0 = max(j0,1); - j1 = min(j1,NV-1); - } - else - { - i0 = max(i0,0); - i1 = min(i1,NH); - j0 = max(j0,0); - j1 = min(j1,NV); - } - for(ii=i0; ii<=i1; ii++) - { - for(jj=j0; jj<=j1; jj++) - { - if(ii==i && jj==j) continue; - range = pow( dh*(i-ii), 2) + pow( dv*(j-jj), 2); - if(range > maxrange) continue; - dr = sqrt(range/maxrange); - rate = max(-30.,min(xyz[i][j].rate,30.)); - if(rate < -1.) - { - delta = pow((1.-dr),-rate+1.); - } - else if(rate < 0.) - { - delta = (1+rate)*0.5*(cos(dr*PI)+1.0) - - rate*pow((1.-dr),2); - } - else if(rate == 0.) - { - delta = 0.5*(cos(dr*PI)+1.0); - } - else if(rate <= 1.) - { - delta = (1.-rate)*0.5*(cos(dr*PI)+1.0) + - rate*(1.-pow(dr,2)); - } - else - { - delta = 1.-pow(dr,rate+1); - } - switch(Plane) - { - case PLANE_XZ0: - case PLANE_XZ1: - xyz[ii][jj].p[1] += (xyz[i][j].p[1] - xyz[ii][jj].p[1])*delta; - break; - case PLANE_YZ0: - case PLANE_YZ1: - xyz[ii][jj].p[0] += (xyz[i][j].p[0] - xyz[ii][jj].p[0])*delta; - break; - default: - xyz[ii][jj].p[2] += (xyz[i][j].p[2] - xyz[ii][jj].p[2])*delta; - } - } - } - } - } - } - } - } - - if((Roughness > 0.) && (WaveType != WAVE_ROUGH_ONLY) ) - { - for(i=0; i<=NH; i++) - { - for(j=0; j<=NV; j++) - { - if(CanEdit(i,j) && !xyz[i][j].fixed) - { - switch(Plane) - { - case PLANE_XZ0: - case PLANE_XZ1: - xyz[i][j].p[1] += -Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX); - break; - case PLANE_YZ0: - case PLANE_YZ1: - xyz[i][j].p[0] += -Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX); - break; - default: - xyz[i][j].p[2] += -Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX); - } - } - else - r = rand(); // We still get a random number, so that fixing points - // doesn't change the sequence. - - } - } - } - - for(i=0; i<=NH; i++) - { - for(j=0; j<=NV; j++) - { - for(k=0; k<3; k++) - { - xyz[i][j].p[k] = Nearest(xyz[i][j].p[k],2.0); - } - } - } - - // Find minima and maxima - switch(Plane) - { - case PLANE_XZ0: - case PLANE_XZ1: - xmin = Hll; - xmax = Hur; - zmin = Vll; - zmax = Vur; - ymin = xyz[0][0].p[1]; - ymax = ymin; - for(i=0; i<=NH; i++) - { - for(j=0; j<=NV; j++) - { - ymin = min(ymin,xyz[i][j].p[1]); - ymax = max(ymax,xyz[i][j].p[1]); - } - } - break; - case PLANE_YZ0: - case PLANE_YZ1: - ymin = Hll; - ymax = Hur; - zmin = Vll; - zmax = Vur; - xmin = xyz[0][0].p[0]; - xmax = ymin; - for(i=0; i<=NH; i++) - { - for(j=0; j<=NV; j++) - { - xmin = min(xmin,xyz[i][j].p[0]); - xmax = max(xmax,xyz[i][j].p[0]); - } - } - break; - break; - default: - xmin = Hll; - xmax = Hur; - ymin = Vll; - ymax = Vur; - zmin = xyz[0][0].p[2]; - zmax = zmin; - for(i=0; i<=NH; i++) - { - for(j=0; j<=NV; j++) - { - zmin = min(zmin,xyz[i][j].p[2]); - zmax = max(zmax,xyz[i][j].p[2]); - } - } - } - - xmin = Nearest(xmin,2.); - xmax = Nearest(xmax,2.); - ymin = Nearest(ymin,2.); - ymax = Nearest(ymax,2.); - zmin = Nearest(zmin,2.); - zmax = Nearest(zmax,2.); - - switch(Plane) - { - case PLANE_XY1: - backface = AtLeast(zmax+32.,32.); - break; - case PLANE_XZ0: - backface = NoMoreThan(ymin-32.,32.); - break; - case PLANE_XZ1: - backface = AtLeast(ymax+32.,32.); - break; - case PLANE_YZ0: - backface = NoMoreThan(xmin-32.,32.); - break; - case PLANE_YZ1: - backface = AtLeast(xmax+32.,32.); - break; - default: - backface = NoMoreThan(zmin-32.,32.); - } - - if(gNode) - { - free(gNode); - free(gTri); - gNode = (NODE *)NULL; - gTri = (TRI *)NULL; - } - if(Decimate > 0 && (Game != QUAKE3 || UsePatches==0) ) - { - MakeDecimatedMap(&gNumNodes,&gNumTris,&gNode,&gTri); - } - else - { - gNumNodes = (NH+1)*(NV+1); - gNumTris = NH*NV*2; - gNode = (NODE *) malloc(gNumNodes * sizeof(NODE)); - gTri = (TRI *) malloc(gNumTris * sizeof(TRI)); - - for(i=0,N=0; i<=NH; i++) - { - for(j=0; j<=NV; j++, N++) - { - gNode[N].used = 1; - gNode[N].p[0] = (float)xyz[i][j].p[0]; - gNode[N].p[1] = (float)xyz[i][j].p[1]; - gNode[N].p[2] = (float)xyz[i][j].p[2]; - } - } - - for(i=0; i 0) - { - for(i=0; i x) xx -= dx; - return xx; -} -//============================================================= -double AtLeast(double x, double dx) -{ - double xx; - - xx = (double)(floor(x/dx - 0.5)+1.)*dx; - if(xx < x) xx += dx; - return xx; -} -//============================================================= -double LessThan(double x,double dx) -{ - double xx; - - xx = (double)(floor(x/dx - 0.5)+1.)*dx; - if(xx >= x) xx -= dx; - return xx; -} -//============================================================= -double MoreThan(double x,double dx) -{ - double xx; - - xx = (double)(floor(x/dx - 0.5)+1.)*dx; - while(xx <= x) - xx += dx; - return xx; -} -//============================================================= -void SubdividePlasma(int i0,int j0,int i1,int j1) -{ - int i, j; - double z1, z2; - double r; // NOTE: This is used to keep the random number sequence the same - // when we fix a point. If we did NOT do this, then simply - // fixing a point at its current value would change the entire - // surface. - - i = (i0+i1)/2; - j = (j0+j1)/2; - if(i1 > i0+1) - { - if(!xyz[i][j0].done) - { - xyz[i][j0].pp[2] = xyz[i0][j0].pp[2] + - (xyz[i1][j0].pp[2] - xyz[i0][j0].pp[2])*(double)(i-i0)/(double)(i1-i0) + - ((double)(i-i0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX)); - xyz[i][j0].done = 1; - } - else - r = rand(); - if((j1 > j0) && (!xyz[i][j1].done) ) - { - xyz[i][j1].pp[2] = xyz[i0][j1].pp[2] + - (xyz[i1][j1].pp[2] - xyz[i0][j1].pp[2])*(double)(i-i0)/(double)(i1-i0) + - ((double)(i-i0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX)); - xyz[i][j1].done = 1; - } - else - r = rand(); - } - if(j1 > j0 + 1) - { - if(!xyz[i0][j].done) - { - xyz[i0][j].pp[2] = xyz[i0][j0].pp[2] + - (xyz[i0][j1].pp[2] - xyz[i0][j0].pp[2])*(double)(j-j0)/(double)(j1-j0) + - ((double)(j-j0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX)); - xyz[i0][j].done = 1; - } - else - r = rand(); - if((i1 > i0) && (!xyz[i1][j].done)) - { - xyz[i1][j].pp[2] = xyz[i1][j0].pp[2] + - (xyz[i1][j1].pp[2] - xyz[i1][j0].pp[2])*(double)(j-j0)/(double)(j1-j0) + - ((double)(j-j0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX)); - xyz[i1][j].done = 1; - } - else - r = rand(); - } - if((i1 > i0+1) && (j1 > j0+1)) - { - if(!xyz[i][j].done) - { - z1 = xyz[i0][j].pp[2] + - (xyz[i1][j].pp[2] - xyz[i0][j].pp[2])*(double)(i-i0)/(double)(i1-i0); - z2 = xyz[i][j0].pp[2] + - (xyz[i][j1].pp[2] - xyz[i][j0].pp[2])*(double)(j-j0)/(double)(j1-j0); - xyz[i][j].pp[2] = (z1+z2)/2. + - ((double)(i-i0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX)); - xyz[i][j].done = 1; - } - else - r = rand(); - } - if(i > i0+1 || j > j0+1) - SubdividePlasma(i0,j0,i,j); - if(i1 > i+1 || j > j0+1) - SubdividePlasma(i,j0,i1,j); - if(i > i0+1 || j1 > j0+1) - SubdividePlasma(i0,j,i,j1); - if(i1 > i+1 || j1 > j0+1) - SubdividePlasma(i,j,i1,j1); -} -//================================================================================== -void PlasmaCloud() -{ - int i, j; - /* use pp[2] values until done to avoid messing with a bunch of - switch statements */ - - for(i=0; i<=NH; i++) - { - for(j=0; j<=NV; j++) - { - if(FixedPoint(i,j)) - xyz[i][j].done = 1; - else - xyz[i][j].done = 0; - } - } - - switch(Plane) - { - case PLANE_XZ0: - case PLANE_XZ1: - for(i=0; i<=NH; i++) - { - for(j=0; j<=NV; j++) - { - if(xyz[i][j].fixed) - xyz[i][j].pp[2] = xyz[i][j].fixed_value; - else - xyz[i][j].pp[2] = xyz[i][j].p[1]; - } - } - break; - case PLANE_YZ0: - case PLANE_YZ1: - for(i=0; i<=NH; i++) - { - for(j=0; j<=NV; j++) - { - if(xyz[i][j].fixed) - xyz[i][j].pp[2] = xyz[i][j].fixed_value; - else - xyz[i][j].pp[2] = xyz[i][j].p[0]; - } - } - break; - default: - for(i=0; i<=NH; i++) - { - for(j=0; j<=NV; j++) - { - if(xyz[i][j].fixed) - xyz[i][j].pp[2] = xyz[i][j].fixed_value; - else - xyz[i][j].pp[2] = xyz[i][j].p[2]; - } - } - break; - } - SubdividePlasma(0,0,NH,NV); - switch(Plane) - { - case PLANE_XZ0: - case PLANE_XZ1: - for(i=0; i<=NH; i++) - { - for(j=0; j<=NV; j++) - { - xyz[i][j].p[1] = xyz[i][j].pp[2]; - } - } - break; - case PLANE_YZ0: - case PLANE_YZ1: - for(i=0; i<=NH; i++) - { - for(j=0; j<=NV; j++) - { - xyz[i][j].p[0] = xyz[i][j].pp[2]; - } - } - break; - default: - for(i=0; i<=NH; i++) - { - for(j=0; j<=NV; j++) - { - xyz[i][j].p[2] = xyz[i][j].pp[2]; - } - } - break; - } -} -//=========================================================================== -bool FixedPoint(int i, int j) -{ - if(xyz[i][j].fixed) return TRUE; - return !CanEdit(i,j); -} -//=========================================================================== -bool CanEdit(int i, int j) -{ - if(FixBorders && ( (WaveType==WAVE_COS_SIN) || (WaveType==WAVE_ROUGH_ONLY) ) ) - { - if(i== 0) return FALSE; - if(i==NH) return FALSE; - if(j== 0) return FALSE; - if(j==NV) return FALSE; - } - if(i== 0 && j== 0) return FALSE; - if(i==NH && j== 0) return FALSE; - if(i== 0 && j==NV) return FALSE; - if(i==NH && j==NV) return FALSE; - return TRUE; -} -/*============================================================================ - TriangleFromPoint - Determines which triangle in the gTri array bounds the input point. Doesn't - do anything special with border points. -*/ -int TriangleFromPoint(double x, double y) -{ - int j, tri; - - if(!gTri) return -1; - - for(j=0, tri=-1; jp[0],2.); - v[0][1] = (vec)Nearest(xyz->p[1],2.); - v[0][2] = (vec)Nearest(xyz->p[2],2.); -} - -//============================================================= -void MakePatch(patchMesh_t *p) -{ - int ret; - char shadername[64+9]; - - ret = g_FuncTable.m_pfnCreatePatchHandle(); - // strcpy(shadername, "textures/"); - // strcpy(shadername+9, Texture[Game][0]); - strcpy(shadername, Texture[Game][0]); - g_FuncTable.m_pfnCommitPatchHandleToMap(ret,p,shadername); - g_FuncTable.m_pfnReleasePatchHandles(); -} - -//============================================================= -void MakeBrush(BRUSH *brush) -{ - LPVOID vp; - int i; - _QERFaceData QERFaceData; - - if(g_FuncTable.m_pfnCreateBrushHandle==NULL) - { - g_FuncTable.m_pfnMessageBox(g_pRadiantWnd,"m_pfnCreateBrushHandle==NULL","Aw damn",0); - return; - } - vp=(g_FuncTable.m_pfnCreateBrushHandle)(); - if(!vp) return; - for(i=0; iNumFaces; i++) - { - if(!strncmp(brush->face[i].texture, "textures/", 9)) - strcpy(QERFaceData.m_TextureName,brush->face[i].texture); - else - { - strcpy(QERFaceData.m_TextureName,"textures/"); - strcpy(QERFaceData.m_TextureName+9,brush->face[i].texture); - } - QERFaceData.m_nContents = brush->face[i].Contents; - QERFaceData.m_nFlags = brush->face[i].Surface; - QERFaceData.m_nValue = brush->face[i].Value; - QERFaceData.m_fShift[0] = brush->face[i].Shift[0]; - QERFaceData.m_fShift[1] = brush->face[i].Shift[1]; - QERFaceData.m_fRotate = brush->face[i].Rotate; - QERFaceData.m_fScale[0] = brush->face[i].Scale[0]; - QERFaceData.m_fScale[1] = brush->face[i].Scale[1]; - QERFaceData.m_v1[0] = brush->face[i].v[0][0]; - QERFaceData.m_v1[1] = brush->face[i].v[0][1]; - QERFaceData.m_v1[2] = brush->face[i].v[0][2]; - QERFaceData.m_v2[0] = brush->face[i].v[1][0]; - QERFaceData.m_v2[1] = brush->face[i].v[1][1]; - QERFaceData.m_v2[2] = brush->face[i].v[1][2]; - QERFaceData.m_v3[0] = brush->face[i].v[2][0]; - QERFaceData.m_v3[1] = brush->face[i].v[2][1]; - QERFaceData.m_v3[2] = brush->face[i].v[2][2]; - QERFaceData.m_bBPrimit = false; - (g_FuncTable.m_pfnAddFaceData)(vp,&QERFaceData); - } - if(g_FuncTable.m_pfnCommitBrushHandle!=NULL) - { - if(h_func_group) - g_FuncTable.m_pfnCommitBrushHandleToEntity(vp,h_func_group); - else - g_FuncTable.m_pfnCommitBrushHandle(vp); - } -} -//============================================================= -void OpenFuncGroup() -{ - if (g_FuncTable.m_pfnAllocateEpair!=NULL) - { - epair_t *ep; - - h_func_group = g_FuncTable.m_pfnCreateEntityHandle(); - ep = g_EntityTable.m_pfnAllocateEpair("classname","func_group"); - g_EntityTable.m_pfnSetEntityKeyValList((entity_t *)h_func_group,ep); - - if (AddTerrainKey) // ^Fishman - Add terrain key to func_group. - { - epair_t *ep2; - terrainkey = g_FuncTable.m_pfnCreateEntityHandle(); - ep2 = g_EntityTable.m_pfnAllocateEpair("terrain","1"); - ep->next = ep2; - g_EntityTable.m_pfnSetEntityKeyValList((entity_t *)h_func_group,ep); - } - } - else - h_func_group = NULL; -} -//============================================================= -void CloseFuncGroup() -{ - if (h_func_group) - g_FuncTable.m_pfnCommitEntityHandleToMap (h_func_group); - if (g_FuncTable.m_pfnSysUpdateWindows != NULL) - g_FuncTable.m_pfnSysUpdateWindows (W_ALL); -} +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +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 +*/ + +#include +#include +#include +#include "gensurf.h" + +double xmin,xmax,ymin,ymax,zmin,zmax; +double backface; +extern double dh, dv; +FILE *fmap; +XYZ xyz[MAX_ROWS+1][MAX_ROWS+1]; +int contents; +int surface[3]; +LPVOID h_func_group; +LPVOID terrainkey; // ^Fishman - Add terrain key to func_group. + +//============================================================= +// Hydra : snap-to-grid begin +double CalculateSnapValue(double value) +{ + long snapvalue; + + // simple uncomplicated snapping, rounding both UP and DOWN to the nearest + // grid unit. + if (SnapToGrid >0) + { + snapvalue = (int)value / SnapToGrid; + if ((long)value % SnapToGrid < (SnapToGrid / 2)) // Snap Downwards if less than halfway between to grid units + value = snapvalue * SnapToGrid; + else // Snap Upwards if more than halfway between to grid units + value = (snapvalue+1) * SnapToGrid; + } + return value; +} +// Hydra : snap-to-grid end + +//============================================================= +bool ValidSurface() +{ + if(WaveType == WAVE_BITMAP && !gbmp.colors) return FALSE; + if(NH < 1) return FALSE; + if(NH > MAX_ROWS) return FALSE; + if(NV < 1) return FALSE; + if(NV > MAX_ROWS) return FALSE; + if(Hll >= Hur) return FALSE; + if(Vll >= Vur) return FALSE; + return TRUE; +} + +//============================================================= +int MapPatches() +{ + int NH_remain; + int NV_remain; + int NH_patch; + int NV_patch; + int BrushNum = 0; + int i, j, k1, k2, k3; + int i0, j0, ii; + char szOops[128]; + patchMesh_t p; + + dh = (Hur-Hll)/NH; + dv = (Vur-Vll)/NV; + memset(&p,0,sizeof(patchMesh_t)); + + // Generate control points in pp array to give desired values currently + // in p array. + switch(Plane) + { + case PLANE_XY0: + case PLANE_XY1: + k1 = 0; + k2 = 1; + k3 = 2; + break; + case PLANE_XZ0: + case PLANE_XZ1: + k1 = 0; + k2 = 2; + k3 = 1; + break; + case PLANE_YZ0: + case PLANE_YZ1: + k1 = 1; + k2 = 2; + k3 = 0; + break; + } + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + xyz[i][j].pp[k1] = xyz[i][j].p[k1]; + xyz[i][j].pp[k2] = xyz[i][j].p[k2]; + } + } + for(i=0; i<=NH; i+=2) + { + for(j=0; j<=NV; j+=2) + xyz[i][j].pp[k3] = xyz[i][j].p[k3]; + } + for(i=1; i 1) + { + if(( (NH_remain-1) % 14) == 0) + NH_patch = 15; + else if(( (NH_remain-1) % 12) == 0) + NH_patch = 13; + else if(( (NH_remain-1) % 10) == 0) + NH_patch = 11; + else if(( (NH_remain-1) % 8) == 0) + NH_patch = 9; + else if(( (NH_remain-1) % 6) == 0) + NH_patch = 7; + else if(( (NH_remain-1) % 4) == 0) + NH_patch = 5; + else if(( (NH_remain-1) % 2) == 0) + NH_patch = 3; + else if(NH_remain > 16) + NH_patch = 7; + else if(NH_remain > 4) + NH_patch = 5; + else + NH_patch = 3; + while( NH_patch > 3 && (NH_patch-1)*dh > 512 ) + NH_patch -= 2; + NH_remain -= (NH_patch-1); + if(NH_remain < 0) + { + sprintf(szOops,"Oops... screwed up with NH=%d",NH); + g_FuncTable.m_pfnMessageBox(NULL,szOops,"Uh oh"); + } + NV_remain = NV+1; + j0 = 0; + while(NV_remain > 1) + { + if(( (NV_remain-1) % 14) == 0) + NV_patch = 15; + else if(( (NV_remain-1) % 12) == 0) + NV_patch = 13; + else if(( (NV_remain-1) % 10) == 0) + NV_patch = 11; + else if(( (NV_remain-1) % 8) == 0) + NV_patch = 9; + else if(( (NV_remain-1) % 6) == 0) + NV_patch = 7; + else if(( (NV_remain-1) % 4) == 0) + NV_patch = 5; + else if(( (NV_remain-1) % 2) == 0) + NV_patch = 3; + else if(NV_remain > 16) + NV_patch = 7; + else if(NV_remain > 4) + NV_patch = 5; + else + NV_patch = 3; + while( NV_patch > 3 && (NV_patch-1)*dh > 512 ) + NV_patch -= 2; + NV_remain -= (NV_patch-1); + if(NV_remain < 0) + { + sprintf(szOops,"Oops... screwed up with NV=%d",NV); + g_FuncTable.m_pfnMessageBox(NULL,szOops,"Uh oh"); + } + + p.width = NH_patch; + p.height = NV_patch; + p.type = PATCH_GENERIC; + for(i=0; i 0 && (Game != QUAKE3 || UsePatches==0) ) + { + MapOut(gNumNodes,gNumTris,gNode,gTri); + /* + ghCursorCurrent = ghCursorDefault; + SetCursor(ghCursorCurrent); + */ + return; + } + + contents = 0; + // HL doesn't have detail property + if((Game != HALFLIFE) && UseDetail) contents += CONTENTS_DETAIL; + // HL and Q3 don't have ladder property + if((Game != HALFLIFE && Game != QUAKE3) && UseLadder) contents += CONTENTS_LADDER; + // Genesis requires solid property to be set explicitly + if(Game == GENESIS3D) contents |= CONTENTS_SOLID; + // Heretic 2 uses different sounds (in surface props) for different texture types + if(Game == HERETIC2) + { + surface[0] = GetDefSurfaceProps(Texture[Game][0]); + surface[1] = GetDefSurfaceProps(Texture[Game][1]); + surface[2] = GetDefSurfaceProps(Texture[Game][2]); + } + else + { + surface[0] = 0; + surface[1] = 0; + surface[2] = 0; + } + if(Game!=QUAKE3 || UsePatches == 0) + MapBrushes(); + + /* + ghCursorCurrent = ghCursorDefault; + SetCursor(ghCursorCurrent); + */ +} + +//============================================================= +void GenerateXYZ() +{ + extern void MakeDecimatedMap(int *, int *, NODE **, TRI **); + double zl, zu; + double wh, wv; + int NHalfcycles; + double a,v,h,ha,va; + double delta, dr, rate; + double range, maxrange; + double r; + int i, j, k, N; + int i0, i1, j0, j1; + int ii, jj; + +// FILE *f; +// char CSV[64]; + + if(!ValidSurface()) return; + + srand(1); + srand(RandomSeed); + + dh = (Hur-Hll)/NH; + dv = (Vur-Vll)/NV; + + // H & V + for(i=0; i<=NH; i++) + { + for(j=0;j<=NV;j++) + { + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + xyz[i][j].p[0] = Hll + i*dh; + xyz[i][j].p[2] = Vll + j*dv; + break; + case PLANE_YZ0: + case PLANE_YZ1: + xyz[i][j].p[1] = Hll + i*dh; + xyz[i][j].p[2] = Vll + j*dv; + break; + default: + xyz[i][j].p[0] = Hll + i*dh; + xyz[i][j].p[1] = Vll + j*dv; + } + } + } + + if(WaveType == WAVE_BITMAP) + GenerateBitmapMapping(); + /* + else if(WaveType == WAVE_FORMULA) + DoFormula(); + */ + else + { + // Initialize Z values using bilinear interpolation + for(i=0; i<=NH; i++) + { + zl = Z00 + i*(Z10 - Z00)/NH; + zu = Z01 + i*(Z11 - Z01)/NH; + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + for(j=0; j<=NV; j++) + xyz[i][j].p[1] = zl + j*(zu-zl)/NV; + break; + case PLANE_YZ0: + case PLANE_YZ1: + for(j=0; j<=NV; j++) + xyz[i][j].p[0] = zl + j*(zu-zl)/NV; + break; + default: + for(j=0; j<=NV; j++) + xyz[i][j].p[2] = zl + j*(zu-zl)/NV; + } + } + } + + switch(WaveType) + { + case WAVE_COS_SIN: + if(FixBorders) + { + NHalfcycles = (int)((Hur-Hll)/(WaveLength/2.)); + NHalfcycles = max(NHalfcycles,1); + wh = 2.*(Hur-Hll)/NHalfcycles; + NHalfcycles = (int)((Vur-Vll)/(WaveLength/2.)); + wv = 2.*(Vur-Vll)/NHalfcycles; + NHalfcycles = max(NHalfcycles,1); + i0 = 1; + i1 = NH-1; + j0 = 1; + j1 = NV-1; + } + else + { + wh = WaveLength; + wv = WaveLength; + i0 = 0; + i1 = NH; + j0 = 0; + j1 = NV; + } + + for(i=i0; i<=i1; i++) + { + h = Hll + i*dh; + ha = ((h-Hll)/wh)*2.*PI - PI/2.; + for(j=j0; j<=j1; j++) + { + v = Vll + j*dv; + va = ((v-Vll)/wv)*2.*PI; + a = Amplitude * cos( ha ) * sin( va ); + switch(Plane) + { + case PLANE_XY1: + xyz[i][j].p[2] -= a; + break; + case PLANE_XZ0: + xyz[i][j].p[1] += a; + break; + case PLANE_XZ1: + xyz[i][j].p[1] -= a; + break; + case PLANE_YZ0: + xyz[i][j].p[0] += a; + break; + case PLANE_YZ1: + xyz[i][j].p[0] -= a; + break; + default: + xyz[i][j].p[2] += a; + } + } + } + break; + case WAVE_HCYLINDER: + for(i=0; i<=NH; i++) + { + h = Hll + i*dh; + ha = ((h-Hll)/WaveLength)*2.*PI - PI/2.; + for(j=0; j<=NV; j++) + { + a = Amplitude * cos( ha ); + switch(Plane) + { + case PLANE_XY1: + xyz[i][j].p[2] -= a; + break; + case PLANE_XZ0: + xyz[i][j].p[1] += a; + break; + case PLANE_XZ1: + xyz[i][j].p[1] -= a; + break; + case PLANE_YZ0: + xyz[i][j].p[0] += a; + break; + case PLANE_YZ1: + xyz[i][j].p[0] -= a; + break; + default: + xyz[i][j].p[2] += a; + } + } + } + break; + case WAVE_VCYLINDER: + for(i=0; i<=NH; i++) + { + h = Hll + i*dh; + for(j=0; j<=NV; j++) + { + v = Vll + j*dv; + va = ((v-Vll)/WaveLength)*2.*PI; + a = Amplitude * sin( va ); + switch(Plane) + { + case PLANE_XY1: + xyz[i][j].p[2] -= a; + break; + case PLANE_XZ0: + xyz[i][j].p[1] += a; + break; + case PLANE_XZ1: + xyz[i][j].p[1] -= a; + break; + case PLANE_YZ0: + xyz[i][j].p[0] += a; + break; + case PLANE_YZ1: + xyz[i][j].p[0] -= a; + break; + default: + xyz[i][j].p[2] += a; + } + } + } + break; + case WAVE_ROUGH_ONLY: + PlasmaCloud(); + break; + } + + if(WaveType != WAVE_ROUGH_ONLY) + { + // Fixed values + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + if(xyz[i][j].fixed) + { + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + xyz[i][j].p[1] = xyz[i][j].fixed_value; + break; + case PLANE_YZ0: + case PLANE_YZ1: + xyz[i][j].p[0] = xyz[i][j].fixed_value; + break; + default: + xyz[i][j].p[2] = xyz[i][j].fixed_value; + } + + if(xyz[i][j].range > 0) + { + maxrange = pow(xyz[i][j].range,2); // so we don't have to do sqrt's + i0 = i - (int)( floor(xyz[i][j].range/dh - 0.5) + 1 ); + i1 = i + i - i0; + j0 = j - (int)( floor(xyz[i][j].range/dv - 0.5) + 1 ); + j1 = j + j - j0; + if(FixBorders) + { + i0 = max(i0,1); + i1 = min(i1,NH-1); + j0 = max(j0,1); + j1 = min(j1,NV-1); + } + else + { + i0 = max(i0,0); + i1 = min(i1,NH); + j0 = max(j0,0); + j1 = min(j1,NV); + } + for(ii=i0; ii<=i1; ii++) + { + for(jj=j0; jj<=j1; jj++) + { + if(ii==i && jj==j) continue; + range = pow( dh*(i-ii), 2) + pow( dv*(j-jj), 2); + if(range > maxrange) continue; + dr = sqrt(range/maxrange); + rate = max(-30.,min(xyz[i][j].rate,30.)); + if(rate < -1.) + { + delta = pow((1.-dr),-rate+1.); + } + else if(rate < 0.) + { + delta = (1+rate)*0.5*(cos(dr*PI)+1.0) - + rate*pow((1.-dr),2); + } + else if(rate == 0.) + { + delta = 0.5*(cos(dr*PI)+1.0); + } + else if(rate <= 1.) + { + delta = (1.-rate)*0.5*(cos(dr*PI)+1.0) + + rate*(1.-pow(dr,2)); + } + else + { + delta = 1.-pow(dr,rate+1); + } + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + xyz[ii][jj].p[1] += (xyz[i][j].p[1] - xyz[ii][jj].p[1])*delta; + break; + case PLANE_YZ0: + case PLANE_YZ1: + xyz[ii][jj].p[0] += (xyz[i][j].p[0] - xyz[ii][jj].p[0])*delta; + break; + default: + xyz[ii][jj].p[2] += (xyz[i][j].p[2] - xyz[ii][jj].p[2])*delta; + } + } + } + } + } + } + } + } + + if((Roughness > 0.) && (WaveType != WAVE_ROUGH_ONLY) ) + { + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + if(CanEdit(i,j) && !xyz[i][j].fixed) + { + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + xyz[i][j].p[1] += -Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX); + break; + case PLANE_YZ0: + case PLANE_YZ1: + xyz[i][j].p[0] += -Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX); + break; + default: + xyz[i][j].p[2] += -Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX); + } + } + else + r = rand(); // We still get a random number, so that fixing points + // doesn't change the sequence. + + } + } + } + + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + for(k=0; k<3; k++) + { + xyz[i][j].p[k] = Nearest(xyz[i][j].p[k],2.0); + } + } + } + + // Find minima and maxima + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + xmin = Hll; + xmax = Hur; + zmin = Vll; + zmax = Vur; + ymin = xyz[0][0].p[1]; + ymax = ymin; + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + ymin = min(ymin,xyz[i][j].p[1]); + ymax = max(ymax,xyz[i][j].p[1]); + } + } + break; + case PLANE_YZ0: + case PLANE_YZ1: + ymin = Hll; + ymax = Hur; + zmin = Vll; + zmax = Vur; + xmin = xyz[0][0].p[0]; + xmax = ymin; + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + xmin = min(xmin,xyz[i][j].p[0]); + xmax = max(xmax,xyz[i][j].p[0]); + } + } + break; + break; + default: + xmin = Hll; + xmax = Hur; + ymin = Vll; + ymax = Vur; + zmin = xyz[0][0].p[2]; + zmax = zmin; + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + zmin = min(zmin,xyz[i][j].p[2]); + zmax = max(zmax,xyz[i][j].p[2]); + } + } + } + + xmin = Nearest(xmin,2.); + xmax = Nearest(xmax,2.); + ymin = Nearest(ymin,2.); + ymax = Nearest(ymax,2.); + zmin = Nearest(zmin,2.); + zmax = Nearest(zmax,2.); + + switch(Plane) + { + case PLANE_XY1: + backface = AtLeast(zmax+32.,32.); + break; + case PLANE_XZ0: + backface = NoMoreThan(ymin-32.,32.); + break; + case PLANE_XZ1: + backface = AtLeast(ymax+32.,32.); + break; + case PLANE_YZ0: + backface = NoMoreThan(xmin-32.,32.); + break; + case PLANE_YZ1: + backface = AtLeast(xmax+32.,32.); + break; + default: + backface = NoMoreThan(zmin-32.,32.); + } + + if(gNode) + { + free(gNode); + free(gTri); + gNode = (NODE *)NULL; + gTri = (TRI *)NULL; + } + if(Decimate > 0 && (Game != QUAKE3 || UsePatches==0) ) + { + MakeDecimatedMap(&gNumNodes,&gNumTris,&gNode,&gTri); + } + else + { + gNumNodes = (NH+1)*(NV+1); + gNumTris = NH*NV*2; + gNode = (NODE *) malloc(gNumNodes * sizeof(NODE)); + gTri = (TRI *) malloc(gNumTris * sizeof(TRI)); + + for(i=0,N=0; i<=NH; i++) + { + for(j=0; j<=NV; j++, N++) + { + gNode[N].used = 1; + gNode[N].p[0] = (float)xyz[i][j].p[0]; + gNode[N].p[1] = (float)xyz[i][j].p[1]; + gNode[N].p[2] = (float)xyz[i][j].p[2]; + } + } + + for(i=0; i 0) + { + for(i=0; i x) xx -= dx; + return xx; +} +//============================================================= +double AtLeast(double x, double dx) +{ + double xx; + + xx = (double)(floor(x/dx - 0.5)+1.)*dx; + if(xx < x) xx += dx; + return xx; +} +//============================================================= +double LessThan(double x,double dx) +{ + double xx; + + xx = (double)(floor(x/dx - 0.5)+1.)*dx; + if(xx >= x) xx -= dx; + return xx; +} +//============================================================= +double MoreThan(double x,double dx) +{ + double xx; + + xx = (double)(floor(x/dx - 0.5)+1.)*dx; + while(xx <= x) + xx += dx; + return xx; +} +//============================================================= +void SubdividePlasma(int i0,int j0,int i1,int j1) +{ + int i, j; + double z1, z2; + double r; // NOTE: This is used to keep the random number sequence the same + // when we fix a point. If we did NOT do this, then simply + // fixing a point at its current value would change the entire + // surface. + + i = (i0+i1)/2; + j = (j0+j1)/2; + if(i1 > i0+1) + { + if(!xyz[i][j0].done) + { + xyz[i][j0].pp[2] = xyz[i0][j0].pp[2] + + (xyz[i1][j0].pp[2] - xyz[i0][j0].pp[2])*(double)(i-i0)/(double)(i1-i0) + + ((double)(i-i0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX)); + xyz[i][j0].done = 1; + } + else + r = rand(); + if((j1 > j0) && (!xyz[i][j1].done) ) + { + xyz[i][j1].pp[2] = xyz[i0][j1].pp[2] + + (xyz[i1][j1].pp[2] - xyz[i0][j1].pp[2])*(double)(i-i0)/(double)(i1-i0) + + ((double)(i-i0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX)); + xyz[i][j1].done = 1; + } + else + r = rand(); + } + if(j1 > j0 + 1) + { + if(!xyz[i0][j].done) + { + xyz[i0][j].pp[2] = xyz[i0][j0].pp[2] + + (xyz[i0][j1].pp[2] - xyz[i0][j0].pp[2])*(double)(j-j0)/(double)(j1-j0) + + ((double)(j-j0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX)); + xyz[i0][j].done = 1; + } + else + r = rand(); + if((i1 > i0) && (!xyz[i1][j].done)) + { + xyz[i1][j].pp[2] = xyz[i1][j0].pp[2] + + (xyz[i1][j1].pp[2] - xyz[i1][j0].pp[2])*(double)(j-j0)/(double)(j1-j0) + + ((double)(j-j0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX)); + xyz[i1][j].done = 1; + } + else + r = rand(); + } + if((i1 > i0+1) && (j1 > j0+1)) + { + if(!xyz[i][j].done) + { + z1 = xyz[i0][j].pp[2] + + (xyz[i1][j].pp[2] - xyz[i0][j].pp[2])*(double)(i-i0)/(double)(i1-i0); + z2 = xyz[i][j0].pp[2] + + (xyz[i][j1].pp[2] - xyz[i][j0].pp[2])*(double)(j-j0)/(double)(j1-j0); + xyz[i][j].pp[2] = (z1+z2)/2. + + ((double)(i-i0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX)); + xyz[i][j].done = 1; + } + else + r = rand(); + } + if(i > i0+1 || j > j0+1) + SubdividePlasma(i0,j0,i,j); + if(i1 > i+1 || j > j0+1) + SubdividePlasma(i,j0,i1,j); + if(i > i0+1 || j1 > j0+1) + SubdividePlasma(i0,j,i,j1); + if(i1 > i+1 || j1 > j0+1) + SubdividePlasma(i,j,i1,j1); +} +//================================================================================== +void PlasmaCloud() +{ + int i, j; + /* use pp[2] values until done to avoid messing with a bunch of + switch statements */ + + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + if(FixedPoint(i,j)) + xyz[i][j].done = 1; + else + xyz[i][j].done = 0; + } + } + + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + if(xyz[i][j].fixed) + xyz[i][j].pp[2] = xyz[i][j].fixed_value; + else + xyz[i][j].pp[2] = xyz[i][j].p[1]; + } + } + break; + case PLANE_YZ0: + case PLANE_YZ1: + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + if(xyz[i][j].fixed) + xyz[i][j].pp[2] = xyz[i][j].fixed_value; + else + xyz[i][j].pp[2] = xyz[i][j].p[0]; + } + } + break; + default: + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + if(xyz[i][j].fixed) + xyz[i][j].pp[2] = xyz[i][j].fixed_value; + else + xyz[i][j].pp[2] = xyz[i][j].p[2]; + } + } + break; + } + SubdividePlasma(0,0,NH,NV); + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + xyz[i][j].p[1] = xyz[i][j].pp[2]; + } + } + break; + case PLANE_YZ0: + case PLANE_YZ1: + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + xyz[i][j].p[0] = xyz[i][j].pp[2]; + } + } + break; + default: + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + xyz[i][j].p[2] = xyz[i][j].pp[2]; + } + } + break; + } +} +//=========================================================================== +bool FixedPoint(int i, int j) +{ + if(xyz[i][j].fixed) return TRUE; + return !CanEdit(i,j); +} +//=========================================================================== +bool CanEdit(int i, int j) +{ + if(FixBorders && ( (WaveType==WAVE_COS_SIN) || (WaveType==WAVE_ROUGH_ONLY) ) ) + { + if(i== 0) return FALSE; + if(i==NH) return FALSE; + if(j== 0) return FALSE; + if(j==NV) return FALSE; + } + if(i== 0 && j== 0) return FALSE; + if(i==NH && j== 0) return FALSE; + if(i== 0 && j==NV) return FALSE; + if(i==NH && j==NV) return FALSE; + return TRUE; +} +/*============================================================================ + TriangleFromPoint + Determines which triangle in the gTri array bounds the input point. Doesn't + do anything special with border points. +*/ +int TriangleFromPoint(double x, double y) +{ + int j, tri; + + if(!gTri) return -1; + + for(j=0, tri=-1; jp[0],2.); + v[0][1] = (vec)Nearest(xyz->p[1],2.); + v[0][2] = (vec)Nearest(xyz->p[2],2.); +} + +//============================================================= +void MakePatch(patchMesh_t *p) +{ + int ret; + char shadername[64+9]; + + ret = g_FuncTable.m_pfnCreatePatchHandle(); + // strcpy(shadername, "textures/"); + // strcpy(shadername+9, Texture[Game][0]); + strcpy(shadername, Texture[Game][0]); + g_FuncTable.m_pfnCommitPatchHandleToMap(ret,p,shadername); + g_FuncTable.m_pfnReleasePatchHandles(); +} + +//============================================================= +void MakeBrush(BRUSH *brush) +{ + LPVOID vp; + int i; + _QERFaceData QERFaceData; + + if(g_FuncTable.m_pfnCreateBrushHandle==NULL) + { + g_FuncTable.m_pfnMessageBox(g_pRadiantWnd,"m_pfnCreateBrushHandle==NULL","Aw damn",0); + return; + } + vp=(g_FuncTable.m_pfnCreateBrushHandle)(); + if(!vp) return; + for(i=0; iNumFaces; i++) + { + if(!strncmp(brush->face[i].texture, "textures/", 9)) + strcpy(QERFaceData.m_TextureName,brush->face[i].texture); + else + { + strcpy(QERFaceData.m_TextureName,"textures/"); + strcpy(QERFaceData.m_TextureName+9,brush->face[i].texture); + } + QERFaceData.m_nContents = brush->face[i].Contents; + QERFaceData.m_nFlags = brush->face[i].Surface; + QERFaceData.m_nValue = brush->face[i].Value; + QERFaceData.m_fShift[0] = brush->face[i].Shift[0]; + QERFaceData.m_fShift[1] = brush->face[i].Shift[1]; + QERFaceData.m_fRotate = brush->face[i].Rotate; + QERFaceData.m_fScale[0] = brush->face[i].Scale[0]; + QERFaceData.m_fScale[1] = brush->face[i].Scale[1]; + QERFaceData.m_v1[0] = brush->face[i].v[0][0]; + QERFaceData.m_v1[1] = brush->face[i].v[0][1]; + QERFaceData.m_v1[2] = brush->face[i].v[0][2]; + QERFaceData.m_v2[0] = brush->face[i].v[1][0]; + QERFaceData.m_v2[1] = brush->face[i].v[1][1]; + QERFaceData.m_v2[2] = brush->face[i].v[1][2]; + QERFaceData.m_v3[0] = brush->face[i].v[2][0]; + QERFaceData.m_v3[1] = brush->face[i].v[2][1]; + QERFaceData.m_v3[2] = brush->face[i].v[2][2]; + QERFaceData.m_bBPrimit = false; + (g_FuncTable.m_pfnAddFaceData)(vp,&QERFaceData); + } + if(g_FuncTable.m_pfnCommitBrushHandle!=NULL) + { + if(h_func_group) + g_FuncTable.m_pfnCommitBrushHandleToEntity(vp,h_func_group); + else + g_FuncTable.m_pfnCommitBrushHandle(vp); + } +} +//============================================================= +void OpenFuncGroup() +{ + if (g_FuncTable.m_pfnAllocateEpair!=NULL) + { + epair_t *ep; + + h_func_group = g_FuncTable.m_pfnCreateEntityHandle(); + ep = g_EntityTable.m_pfnAllocateEpair("classname","func_group"); + g_EntityTable.m_pfnSetEntityKeyValList((entity_t *)h_func_group,ep); + + if (AddTerrainKey) // ^Fishman - Add terrain key to func_group. + { + epair_t *ep2; + terrainkey = g_FuncTable.m_pfnCreateEntityHandle(); + ep2 = g_EntityTable.m_pfnAllocateEpair("terrain","1"); + ep->next = ep2; + g_EntityTable.m_pfnSetEntityKeyValList((entity_t *)h_func_group,ep); + } + } + else + h_func_group = NULL; +} +//============================================================= +void CloseFuncGroup() +{ + if (h_func_group) + g_FuncTable.m_pfnCommitEntityHandleToMap (h_func_group); + if (g_FuncTable.m_pfnSysUpdateWindows != NULL) + g_FuncTable.m_pfnSysUpdateWindows (W_ALL); +} diff --git a/contrib/gtkgensurf/gensurf.cpp b/contrib/gtkgensurf/gensurf.cpp index b9ff7d47..32b54b55 100644 --- a/contrib/gtkgensurf/gensurf.cpp +++ b/contrib/gtkgensurf/gensurf.cpp @@ -1,467 +1,467 @@ -/* -GenSurf plugin for GtkRadiant -Copyright (C) 2001 David Hyde, Loki software and qeradiant.com - -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 -*/ - -#include -#include -#include -/* -#include -#include -#include -*/ -#include "gensurf.h" - -char gszAppDir[NAME_MAX]; -char gszCaption[64]; -char gszIni[NAME_MAX]; -char gszHelpFile[NAME_MAX]; -char gszMapFile[NAME_MAX]; -char gszVersion[64]; -double Amplitude; -double Roughness; -double TexOffset[2]; -double TexScale[2]; -double WaveLength; -double Hll, Hur, Vll, Vur; -double Z00, Z01, Z10, Z11; -ELEMENT Vertex[(MAX_ROWS+1)*(MAX_ROWS+1)]; -int AddHints; -int ArghRad2; -int AutoOverwrite; -int Decimate=0; -int SnapToGrid=0; // 0, or the grid size to snap to. // Hydra : snap to grid -int FileAppend=0; -int FixBorders; -int HideBackFaces=0; -int NH, NV; -int NumVerticesSelected; -int Plane; -int Preview; -int RandomSeed=1; -int Skybox; -int UseDetail; -int UseLadder; -int VertexMode=0; -int WaveType; -int gNumNodes=0; -int gNumTris=0; -int vid_x, vid_y; -int view_x, view_y; -int view_cx, view_cy; -int UsePatches; -int SlantAngle; -int GimpHints; -int Antialiasing; // ^Fishman - Antializing for the preview window. -int AddTerrainKey; // ^Fishman - Add terrain key to func_group. -int SP; // ^Fishman - Snap to grid. - -GtkWidget *g_pWnd; // ghwnd; -GtkWidget *g_pRadiantWnd; // ghwnd_main; -/*HWND ghwndAngles; -*/GtkWidget *g_pWndPreview; -GtkWidget *g_pPreviewWidget; -MYBITMAP gbmp; -NODE *gNode=(NODE *)NULL; -TRI *gTri=(TRI *)NULL; - -int Game; -bounding_box PlayerBox[NUMGAMES] = { {{-16., 16.}, {-16., 16.}, {-24., 32.}}, // Quake2 - {{-16., 16.}, {-16., 16.}, {-36., 36.}}, // Half-Life - {{-16., 16.}, {-16., 16.}, {-32., 32.}}, // SiN - {{-16., 16.}, {-16., 16.}, {-24., 32.}}, // Heretic2 (guess) - {{-16., 16.}, {-16., 16.}, {-24., 32.}}, // KingPin (guess) - {{-30., 30.}, {-30., 30.}, {-10.,160.}}, // Genesis3D (no idea) - {{-16., 16.}, {-16., 16.}, {-24., 32.}}}; // Quake3 (not sure) -//char gszOutputDir[NUMGAMES][NAME_MAX]; -//char gszTextureDir[NUMGAMES][NAME_MAX]; -char Texture[NUMGAMES][3][64]; -//char pakfile[NUMGAMES][NAME_MAX]; -//char lastpakfile[NUMGAMES][NAME_MAX]; -//int UsePak[NUMGAMES]; -//char GameDir[NUMGAMES][NAME_MAX]; - -char GameName[NUMGAMES][16] = {"Quake2", "Half-Life", "SiN", "Heretic2", "Kingpin", "Genesis3D", "Quake3" }; - - -bool GenSurfInit () -{ - strcpy (gszVersion, "1.05"); - strcpy (gszCaption, "GtkGenSurf"); - if (strlen (gszVersion)) - { - strcat (gszCaption, " v"); - strcat (gszCaption, gszVersion); - } - - strcpy (gszIni, g_FuncTable.m_pfnProfileGetDirectory ()); - strcat (gszIni, "gensurf.ini"); - -/*if (g_FuncTable.m_pfnReadProjectKey != NULL) - { - char *basepath; - - basepath = g_FuncTable.m_pfnReadProjectKey("basepath"); - if (basepath) - { - g_strdown (basepath); - if (strstr(basepath,"baseq3")) - Game = QUAKE3; - else if (strstr (basepath,"baseq2")) - Game = QUAKE2; - else // Gotta have a game, might as well be Quake3 - Game = QUAKE3; - } - else - Game = QUAKE3; - } - else */ - Game = QUAKE3; - - ReadIniFile (gszIni); - - if (g_pWnd == NULL) - g_pWnd = create_main_dialog (); - - return true; -} - -// Reads default values - -#define OPTS_SECTION "Options" - -void ReadIniFile (const char *file) -{ - char *Text; - float x1,x2,x3,x4; - int i; - - Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "Amplitude", ""); - if (strlen (Text)) - Amplitude = atof (Text); - else - Amplitude = 128; - - Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "Roughness", ""); - if (strlen (Text)) - Roughness = atof (Text); - else - Roughness = 16; - - Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "WaveLength", ""); - if (strlen (Text)) - WaveLength = atof (Text); - else - WaveLength = 1024; - - Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "Extents", ""); - if (strlen (Text)) - { - sscanf(Text,"%f,%f,%f,%f",&x1,&x2,&x3,&x4); - Hll = x1; - Vll = x2; - Hur = x3; - Vur = x4; - } - else - { - Hll = -512; - Vll = -512; - Hur = 512; - Vur = 512; - } - - Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "CornerValues", ""); - if (strlen (Text)) - { - sscanf(Text,"%f,%f,%f,%f",&x1,&x2,&x3,&x4); - Z00 = x1; - Z01 = x2; - Z10 = x3; - Z11 = x4; - } - else - { - Z00 = 0.; - Z01 = 0.; - Z10 = 0.; - Z11 = 0.; - } - - Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "TextureOffset", ""); - if (strlen (Text)) - { - sscanf(Text,"%f,%f",&x1,&x2); - TexOffset[0] = x1; - TexOffset[1] = x2; - } - else - { - TexOffset[0] = 0.; - TexOffset[1] = 0.; - } - - Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION,"TextureScale",""); - if (strlen (Text)) - { - sscanf(Text,"%f,%f",&x1,&x2); - TexScale[0] = x1; - TexScale[1] = x2; - if(TexScale[0] == 0.) TexScale[0] = 1.0; - if(TexScale[1] == 0.) TexScale[1] = 1.0; - } - else - { - TexScale[0] = 1.; - TexScale[1] = 1.; - } - - NH = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"NH",8); - NH = max(1,min(NH,MAX_ROWS)); - NV = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"NV",8); - NV = max(1,min(NV,MAX_ROWS)); - -// Decimate = GetPrivateProfileInt(OPTS_SECTION,"Decimate",0,file); -// Decimate = max(0,min(Decimate,100)); - - AddHints = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"AddHints",0); - ArghRad2 = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"ArghRad2",0); - AutoOverwrite = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"AutoOverwrite",0); - FixBorders = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"FixBorders",1); - HideBackFaces = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"HideBackFaces",0); - Plane = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"Plane",0); - Preview = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"Preview", 0); - Antialiasing = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"Antialiasing",0); // ^Fishman - Antializing for the preview window. - RandomSeed = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"RandomSeed",1); - Skybox = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"Skybox",0); - UseDetail = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"UseDetail",0); - AddTerrainKey = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"AddTerrainKey",0); // ^Fishman - Add terrain key to func_group. - UseLadder = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"UseLadder",0); - WaveType = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"WaveType",0); - vid_x = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"vid_x", 0); - vid_y = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"vid_y", 0); - view_x = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"view_x",0); - view_y = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"view_y",0); - view_cx = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"view_cx",0); - view_cy = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"view_cy",0); - - UsePatches = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"UsePatches",0); - - SlantAngle = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"SlantAngle",60); - GimpHints = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"GimpHints",0); - - for(i=0; i +#include +#include +/* +#include +#include +#include +*/ +#include "gensurf.h" + +char gszAppDir[NAME_MAX]; +char gszCaption[64]; +char gszIni[NAME_MAX]; +char gszHelpFile[NAME_MAX]; +char gszMapFile[NAME_MAX]; +char gszVersion[64]; +double Amplitude; +double Roughness; +double TexOffset[2]; +double TexScale[2]; +double WaveLength; +double Hll, Hur, Vll, Vur; +double Z00, Z01, Z10, Z11; +ELEMENT Vertex[(MAX_ROWS+1)*(MAX_ROWS+1)]; +int AddHints; +int ArghRad2; +int AutoOverwrite; +int Decimate=0; +int SnapToGrid=0; // 0, or the grid size to snap to. // Hydra : snap to grid +int FileAppend=0; +int FixBorders; +int HideBackFaces=0; +int NH, NV; +int NumVerticesSelected; +int Plane; +int Preview; +int RandomSeed=1; +int Skybox; +int UseDetail; +int UseLadder; +int VertexMode=0; +int WaveType; +int gNumNodes=0; +int gNumTris=0; +int vid_x, vid_y; +int view_x, view_y; +int view_cx, view_cy; +int UsePatches; +int SlantAngle; +int GimpHints; +int Antialiasing; // ^Fishman - Antializing for the preview window. +int AddTerrainKey; // ^Fishman - Add terrain key to func_group. +int SP; // ^Fishman - Snap to grid. + +GtkWidget *g_pWnd; // ghwnd; +GtkWidget *g_pRadiantWnd; // ghwnd_main; +/*HWND ghwndAngles; +*/GtkWidget *g_pWndPreview; +GtkWidget *g_pPreviewWidget; +MYBITMAP gbmp; +NODE *gNode=(NODE *)NULL; +TRI *gTri=(TRI *)NULL; + +int Game; +bounding_box PlayerBox[NUMGAMES] = { {{-16., 16.}, {-16., 16.}, {-24., 32.}}, // Quake2 + {{-16., 16.}, {-16., 16.}, {-36., 36.}}, // Half-Life + {{-16., 16.}, {-16., 16.}, {-32., 32.}}, // SiN + {{-16., 16.}, {-16., 16.}, {-24., 32.}}, // Heretic2 (guess) + {{-16., 16.}, {-16., 16.}, {-24., 32.}}, // KingPin (guess) + {{-30., 30.}, {-30., 30.}, {-10.,160.}}, // Genesis3D (no idea) + {{-16., 16.}, {-16., 16.}, {-24., 32.}}}; // Quake3 (not sure) +//char gszOutputDir[NUMGAMES][NAME_MAX]; +//char gszTextureDir[NUMGAMES][NAME_MAX]; +char Texture[NUMGAMES][3][64]; +//char pakfile[NUMGAMES][NAME_MAX]; +//char lastpakfile[NUMGAMES][NAME_MAX]; +//int UsePak[NUMGAMES]; +//char GameDir[NUMGAMES][NAME_MAX]; + +char GameName[NUMGAMES][16] = {"Quake2", "Half-Life", "SiN", "Heretic2", "Kingpin", "Genesis3D", "Quake3" }; + + +bool GenSurfInit () +{ + strcpy (gszVersion, "1.05"); + strcpy (gszCaption, "GtkGenSurf"); + if (strlen (gszVersion)) + { + strcat (gszCaption, " v"); + strcat (gszCaption, gszVersion); + } + + strcpy (gszIni, g_FuncTable.m_pfnProfileGetDirectory ()); + strcat (gszIni, "gensurf.ini"); + +/*if (g_FuncTable.m_pfnReadProjectKey != NULL) + { + char *basepath; + + basepath = g_FuncTable.m_pfnReadProjectKey("basepath"); + if (basepath) + { + g_strdown (basepath); + if (strstr(basepath,"baseq3")) + Game = QUAKE3; + else if (strstr (basepath,"baseq2")) + Game = QUAKE2; + else // Gotta have a game, might as well be Quake3 + Game = QUAKE3; + } + else + Game = QUAKE3; + } + else */ + Game = QUAKE3; + + ReadIniFile (gszIni); + + if (g_pWnd == NULL) + g_pWnd = create_main_dialog (); + + return true; +} + +// Reads default values + +#define OPTS_SECTION "Options" + +void ReadIniFile (const char *file) +{ + char *Text; + float x1,x2,x3,x4; + int i; + + Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "Amplitude", ""); + if (strlen (Text)) + Amplitude = atof (Text); + else + Amplitude = 128; + + Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "Roughness", ""); + if (strlen (Text)) + Roughness = atof (Text); + else + Roughness = 16; + + Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "WaveLength", ""); + if (strlen (Text)) + WaveLength = atof (Text); + else + WaveLength = 1024; + + Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "Extents", ""); + if (strlen (Text)) + { + sscanf(Text,"%f,%f,%f,%f",&x1,&x2,&x3,&x4); + Hll = x1; + Vll = x2; + Hur = x3; + Vur = x4; + } + else + { + Hll = -512; + Vll = -512; + Hur = 512; + Vur = 512; + } + + Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "CornerValues", ""); + if (strlen (Text)) + { + sscanf(Text,"%f,%f,%f,%f",&x1,&x2,&x3,&x4); + Z00 = x1; + Z01 = x2; + Z10 = x3; + Z11 = x4; + } + else + { + Z00 = 0.; + Z01 = 0.; + Z10 = 0.; + Z11 = 0.; + } + + Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "TextureOffset", ""); + if (strlen (Text)) + { + sscanf(Text,"%f,%f",&x1,&x2); + TexOffset[0] = x1; + TexOffset[1] = x2; + } + else + { + TexOffset[0] = 0.; + TexOffset[1] = 0.; + } + + Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION,"TextureScale",""); + if (strlen (Text)) + { + sscanf(Text,"%f,%f",&x1,&x2); + TexScale[0] = x1; + TexScale[1] = x2; + if(TexScale[0] == 0.) TexScale[0] = 1.0; + if(TexScale[1] == 0.) TexScale[1] = 1.0; + } + else + { + TexScale[0] = 1.; + TexScale[1] = 1.; + } + + NH = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"NH",8); + NH = max(1,min(NH,MAX_ROWS)); + NV = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"NV",8); + NV = max(1,min(NV,MAX_ROWS)); + +// Decimate = GetPrivateProfileInt(OPTS_SECTION,"Decimate",0,file); +// Decimate = max(0,min(Decimate,100)); + + AddHints = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"AddHints",0); + ArghRad2 = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"ArghRad2",0); + AutoOverwrite = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"AutoOverwrite",0); + FixBorders = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"FixBorders",1); + HideBackFaces = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"HideBackFaces",0); + Plane = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"Plane",0); + Preview = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"Preview", 0); + Antialiasing = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"Antialiasing",0); // ^Fishman - Antializing for the preview window. + RandomSeed = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"RandomSeed",1); + Skybox = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"Skybox",0); + UseDetail = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"UseDetail",0); + AddTerrainKey = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"AddTerrainKey",0); // ^Fishman - Add terrain key to func_group. + UseLadder = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"UseLadder",0); + WaveType = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"WaveType",0); + vid_x = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"vid_x", 0); + vid_y = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"vid_y", 0); + view_x = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"view_x",0); + view_y = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"view_y",0); + view_cx = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"view_cx",0); + view_cy = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"view_cy",0); + + UsePatches = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"UsePatches",0); + + SlantAngle = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"SlantAngle",60); + GimpHints = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"GimpHints",0); + + for(i=0; i -#include -#include -#include "gensurf.h" - -// Heretic 2 - specific routines - -typedef struct palette_s -{ - guint8 r,g,b; -} palette_t; - -#define MIP_VERSION 2 -#define PAL_SIZE 256 -#define MIPLEVELS 16 - -typedef struct miptex_s -{ - int version; - char name[32]; - unsigned width[MIPLEVELS], height[MIPLEVELS]; - unsigned offsets[MIPLEVELS]; // four mip maps stored - char animname[32]; // next frame in animation chain - palette_t palette[PAL_SIZE]; - int flags; - int contents; - int value; -} miptex_t; - -//============================================================= -int GetDefSurfaceProps(char *Tex) -{ - return 0; // leo: only used for Heretic 2, fix later - /* - char path[NAME_MAX]; - char *p; - int flags; - miptex_t *mt; - FILE *f; - int length; - int pos; - - if(Game != HERETIC2) return 0; - if(!strlen(Tex)) return 0; - - mt = NULL; - flags = 0; - if(UsePak[Game]) - { - FILE *fpak; - pak_header_t pakheader; - pak_item_t pakitem; - int i; - int num; - int numitems; - - if (NULL != (fpak = fopen(pakfile[Game], "rb"))) - { - sprintf(path,"textures/%s.m8",Tex); - g_strdown(path); - num=fread(&pakheader,1,sizeof(pak_header_t),fpak); - if((size_t)num < sizeof(pak_header_t)) - { - fclose(fpak); - return 0; - } - if(strncmp(pakheader.id,"PACK",4)) - { - fclose(fpak); - return 0; - } - numitems = pakheader.dsize/sizeof(pak_item_t); - fseek(fpak,pakheader.dstart,SEEK_SET); - for(i=0; iflags; - free(mt); - } - } - } - fclose(fpak); - } - } - else - { - // Assume .map will be output to gamedir/maps, then back up - // to the gamedir and append /textures. Ugly but it should work - strcpy(path,gszMapFile); - g_strdown(path); - p = strstr(path,"maps"); - if(!p) return 0; - p[0] = '\0'; - strcat(path,"textures/"); - strcat(path,Tex); - strcat(path,".m8"); - f = fopen (path, "rb"); - if (!f) - flags = 0; - else - { - pos = ftell (f); - fseek (f, 0, SEEK_END); - length = ftell (f); - fseek (f, pos, SEEK_SET); - if((mt = (miptex_t*)malloc(length+1))==NULL) - flags = 0; - else - { - ((char *)mt)[length] = 0; - fread(mt, 1, length, f); - fclose (f); - flags = mt->flags; - free(mt); - } - } - } - return flags; - */ -} +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +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 +*/ + +#include +#include +#include +#include "gensurf.h" + +// Heretic 2 - specific routines + +typedef struct palette_s +{ + guint8 r,g,b; +} palette_t; + +#define MIP_VERSION 2 +#define PAL_SIZE 256 +#define MIPLEVELS 16 + +typedef struct miptex_s +{ + int version; + char name[32]; + unsigned width[MIPLEVELS], height[MIPLEVELS]; + unsigned offsets[MIPLEVELS]; // four mip maps stored + char animname[32]; // next frame in animation chain + palette_t palette[PAL_SIZE]; + int flags; + int contents; + int value; +} miptex_t; + +//============================================================= +int GetDefSurfaceProps(char *Tex) +{ + return 0; // leo: only used for Heretic 2, fix later + /* + char path[NAME_MAX]; + char *p; + int flags; + miptex_t *mt; + FILE *f; + int length; + int pos; + + if(Game != HERETIC2) return 0; + if(!strlen(Tex)) return 0; + + mt = NULL; + flags = 0; + if(UsePak[Game]) + { + FILE *fpak; + pak_header_t pakheader; + pak_item_t pakitem; + int i; + int num; + int numitems; + + if (NULL != (fpak = fopen(pakfile[Game], "rb"))) + { + sprintf(path,"textures/%s.m8",Tex); + g_strdown(path); + num=fread(&pakheader,1,sizeof(pak_header_t),fpak); + if((size_t)num < sizeof(pak_header_t)) + { + fclose(fpak); + return 0; + } + if(strncmp(pakheader.id,"PACK",4)) + { + fclose(fpak); + return 0; + } + numitems = pakheader.dsize/sizeof(pak_item_t); + fseek(fpak,pakheader.dstart,SEEK_SET); + for(i=0; iflags; + free(mt); + } + } + } + fclose(fpak); + } + } + else + { + // Assume .map will be output to gamedir/maps, then back up + // to the gamedir and append /textures. Ugly but it should work + strcpy(path,gszMapFile); + g_strdown(path); + p = strstr(path,"maps"); + if(!p) return 0; + p[0] = '\0'; + strcat(path,"textures/"); + strcat(path,Tex); + strcat(path,".m8"); + f = fopen (path, "rb"); + if (!f) + flags = 0; + else + { + pos = ftell (f); + fseek (f, 0, SEEK_END); + length = ftell (f); + fseek (f, pos, SEEK_SET); + if((mt = (miptex_t*)malloc(length+1))==NULL) + flags = 0; + else + { + ((char *)mt)[length] = 0; + fread(mt, 1, length, f); + fclose (f); + flags = mt->flags; + free(mt); + } + } + } + return flags; + */ +} diff --git a/contrib/gtkgensurf/plugin.cpp b/contrib/gtkgensurf/plugin.cpp index eeb8e35c..ec8e6a3f 100644 --- a/contrib/gtkgensurf/plugin.cpp +++ b/contrib/gtkgensurf/plugin.cpp @@ -1,232 +1,232 @@ -/* -GenSurf plugin for GtkRadiant -Copyright (C) 2001 David Hyde, Loki software and qeradiant.com - -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 -*/ - -#include "gensurf.h" - -// Global plugin FuncTable -_QERFuncTable_1 g_FuncTable; -_QERQglTable g_GLTable; -_QERUIGtkTable g_UIGtkTable; -_QEREntityTable g_EntityTable; -bool SingleBrushSelected; -bool g_bInitDone; - -#include "iplugin.h" - -const char* QERPlug_Init(void* hApp, void* pMainWidget) -{ - g_pRadiantWnd = (GtkWidget*)pMainWidget; - - return "GenSurf for Q3Radiant"; -} - -const char* QERPlug_GetName () -{ - return "GtkGenSurf"; -} - -const char* QERPlug_GetCommandList () -{ - return "Wall facing 270...;Wall facing 180...;Wall facing 90...;Wall facing 0...;" - "Ceiling...;Ground surface...;-;About..."; -} - -// vMin/vMax provide the bounds of the selection, they are zero if there is no selection -// if there is a selection, bSingleBrush will be true if a single brush is selected -// if so, typical plugin behaviour (such as primitive creation) would use the bounds as -// a rule to create the primitive, then delete the selection -void QERPlug_Dispatch (const char *p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) -{ - bool Generate = false; - - if (!g_bInitDone) - { - if (GenSurfInit ()) - g_bInitDone = true; - } - - if (!strcmp (p, "Ground surface...")) - { - SingleBrushSelected = bSingleBrush; - Plane = PLANE_XY0; - if (SingleBrushSelected) - { - Hll = vMin[0]; - Vll = vMin[1]; - Hur = vMax[0]; - Vur = vMax[1]; - Z00 = Z01 = Z10 = Z11 = vMax[2]; - } - Generate = true; - } - else if (!strcmp (p, "Ceiling...")) - { - SingleBrushSelected = bSingleBrush; - Plane = PLANE_XY1; - if(SingleBrushSelected) - { - Hll = vMin[0]; - Vll = vMin[1]; - Hur = vMax[0]; - Vur = vMax[1]; - Z00 = Z01 = Z10 = Z11 = vMin[2]; - } - Generate = true; - } - else if (!strcmp (p, "Wall facing 0...")) - { - SingleBrushSelected = bSingleBrush; - Plane = PLANE_YZ0; - if (SingleBrushSelected) - { - Hll = vMin[1]; - Vll = vMin[2]; - Hur = vMax[1]; - Vur = vMax[2]; - Z00 = Z01 = Z10 = Z11 = vMax[0]; - } - Generate = true; - } - else if (!strcmp (p, "Wall facing 90...")) - { - SingleBrushSelected = bSingleBrush; - Plane = PLANE_XZ0; - if (SingleBrushSelected) - { - Hll = vMin[0]; - Vll = vMin[2]; - Hur = vMax[0]; - Vur = vMax[2]; - Z00 = Z01 = Z10 = Z11 = vMax[1]; - } - Generate = true; - } - else if (!strcmp (p, "Wall facing 180...")) - { - SingleBrushSelected = bSingleBrush; - Plane = PLANE_YZ1; - if (SingleBrushSelected) - { - Hll = vMin[1]; - Vll = vMin[2]; - Hur = vMax[1]; - Vur = vMax[2]; - Z00 = Z01 = Z10 = Z11 = vMin[0]; - } - Generate = true; - } - else if (!strcmp (p, "Wall facing 270...")) - { - SingleBrushSelected = bSingleBrush; - Plane = PLANE_XZ1; - if (SingleBrushSelected) - { - Hll = vMin[0]; - Vll = vMin[2]; - Hur = vMax[0]; - Vur = vMax[2]; - Z00 = Z01 = Z10 = Z11 = vMin[1]; - } - Generate = true; - } - else if (!strcmp(p,"About...")) - About (g_pRadiantWnd); - - if (Generate) - { - if (SingleBrushSelected) - UseFaceBounds (); - - gtk_widget_show (g_pWnd); - } -} - -extern "C" LPVOID WINAPI QERPlug_GetFuncTable() -{ - return &g_FuncTable; -} - -// ============================================================================= -// SYNAPSE - -#include "synapse.h" - -class GenSurfSynapseClient : public CSynapseClient -{ -public: - // CSynapseClient API - bool RequestAPI(APIDescriptor_t *pAPI); - const char* GetInfo(); - - GenSurfSynapseClient() { } - virtual ~GenSurfSynapseClient() { } -}; - -CSynapseServer* g_pSynapseServer = NULL; -GenSurfSynapseClient 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(PLUGIN_MAJOR, "gtkgensurf", sizeof(_QERPluginTable)); - - g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); - g_SynapseClient.AddAPI(UIGTK_MAJOR, NULL, sizeof(_QERUIGtkTable), SYN_REQUIRE, &g_UIGtkTable); - g_SynapseClient.AddAPI(QGL_MAJOR, NULL, sizeof(_QERQglTable), SYN_REQUIRE, &g_GLTable); - g_SynapseClient.AddAPI(ENTITY_MAJOR, NULL, sizeof(_QEREntityTable), SYN_REQUIRE, &g_EntityTable); - - return &g_SynapseClient; -} - -bool GenSurfSynapseClient::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; - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -#include "version.h" - -const char* GenSurfSynapseClient::GetInfo() -{ - return "GtkGenSurf - built " __DATE__ " " RADIANT_VERSION; -} +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +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 +*/ + +#include "gensurf.h" + +// Global plugin FuncTable +_QERFuncTable_1 g_FuncTable; +_QERQglTable g_GLTable; +_QERUIGtkTable g_UIGtkTable; +_QEREntityTable g_EntityTable; +bool SingleBrushSelected; +bool g_bInitDone; + +#include "iplugin.h" + +const char* QERPlug_Init(void* hApp, void* pMainWidget) +{ + g_pRadiantWnd = (GtkWidget*)pMainWidget; + + return "GenSurf for Q3Radiant"; +} + +const char* QERPlug_GetName () +{ + return "GtkGenSurf"; +} + +const char* QERPlug_GetCommandList () +{ + return "Wall facing 270...;Wall facing 180...;Wall facing 90...;Wall facing 0...;" + "Ceiling...;Ground surface...;-;About..."; +} + +// vMin/vMax provide the bounds of the selection, they are zero if there is no selection +// if there is a selection, bSingleBrush will be true if a single brush is selected +// if so, typical plugin behaviour (such as primitive creation) would use the bounds as +// a rule to create the primitive, then delete the selection +void QERPlug_Dispatch (const char *p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) +{ + bool Generate = false; + + if (!g_bInitDone) + { + if (GenSurfInit ()) + g_bInitDone = true; + } + + if (!strcmp (p, "Ground surface...")) + { + SingleBrushSelected = bSingleBrush; + Plane = PLANE_XY0; + if (SingleBrushSelected) + { + Hll = vMin[0]; + Vll = vMin[1]; + Hur = vMax[0]; + Vur = vMax[1]; + Z00 = Z01 = Z10 = Z11 = vMax[2]; + } + Generate = true; + } + else if (!strcmp (p, "Ceiling...")) + { + SingleBrushSelected = bSingleBrush; + Plane = PLANE_XY1; + if(SingleBrushSelected) + { + Hll = vMin[0]; + Vll = vMin[1]; + Hur = vMax[0]; + Vur = vMax[1]; + Z00 = Z01 = Z10 = Z11 = vMin[2]; + } + Generate = true; + } + else if (!strcmp (p, "Wall facing 0...")) + { + SingleBrushSelected = bSingleBrush; + Plane = PLANE_YZ0; + if (SingleBrushSelected) + { + Hll = vMin[1]; + Vll = vMin[2]; + Hur = vMax[1]; + Vur = vMax[2]; + Z00 = Z01 = Z10 = Z11 = vMax[0]; + } + Generate = true; + } + else if (!strcmp (p, "Wall facing 90...")) + { + SingleBrushSelected = bSingleBrush; + Plane = PLANE_XZ0; + if (SingleBrushSelected) + { + Hll = vMin[0]; + Vll = vMin[2]; + Hur = vMax[0]; + Vur = vMax[2]; + Z00 = Z01 = Z10 = Z11 = vMax[1]; + } + Generate = true; + } + else if (!strcmp (p, "Wall facing 180...")) + { + SingleBrushSelected = bSingleBrush; + Plane = PLANE_YZ1; + if (SingleBrushSelected) + { + Hll = vMin[1]; + Vll = vMin[2]; + Hur = vMax[1]; + Vur = vMax[2]; + Z00 = Z01 = Z10 = Z11 = vMin[0]; + } + Generate = true; + } + else if (!strcmp (p, "Wall facing 270...")) + { + SingleBrushSelected = bSingleBrush; + Plane = PLANE_XZ1; + if (SingleBrushSelected) + { + Hll = vMin[0]; + Vll = vMin[2]; + Hur = vMax[0]; + Vur = vMax[2]; + Z00 = Z01 = Z10 = Z11 = vMin[1]; + } + Generate = true; + } + else if (!strcmp(p,"About...")) + About (g_pRadiantWnd); + + if (Generate) + { + if (SingleBrushSelected) + UseFaceBounds (); + + gtk_widget_show (g_pWnd); + } +} + +extern "C" LPVOID WINAPI QERPlug_GetFuncTable() +{ + return &g_FuncTable; +} + +// ============================================================================= +// SYNAPSE + +#include "synapse.h" + +class GenSurfSynapseClient : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + + GenSurfSynapseClient() { } + virtual ~GenSurfSynapseClient() { } +}; + +CSynapseServer* g_pSynapseServer = NULL; +GenSurfSynapseClient 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(PLUGIN_MAJOR, "gtkgensurf", sizeof(_QERPluginTable)); + + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(UIGTK_MAJOR, NULL, sizeof(_QERUIGtkTable), SYN_REQUIRE, &g_UIGtkTable); + g_SynapseClient.AddAPI(QGL_MAJOR, NULL, sizeof(_QERQglTable), SYN_REQUIRE, &g_GLTable); + g_SynapseClient.AddAPI(ENTITY_MAJOR, NULL, sizeof(_QEREntityTable), SYN_REQUIRE, &g_EntityTable); + + return &g_SynapseClient; +} + +bool GenSurfSynapseClient::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; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* GenSurfSynapseClient::GetInfo() +{ + return "GtkGenSurf - built " __DATE__ " " RADIANT_VERSION; +} diff --git a/contrib/gtkgensurf/view.cpp b/contrib/gtkgensurf/view.cpp index ff4b1572..9344a69e 100644 --- a/contrib/gtkgensurf/view.cpp +++ b/contrib/gtkgensurf/view.cpp @@ -1,1287 +1,1287 @@ -/* -GenSurf plugin for GtkRadiant -Copyright (C) 2001 David Hyde, Loki software and qeradiant.com - -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 -*/ - -#include -#include -#include -#include "gensurf.h" - -#undef ISOMETRIC - -extern double backface; -extern double dh, dv; -extern double xmin,xmax,ymin,ymax,zmin,zmax; - -double SF, SFG; // Graphics scale factors -double XLo, XHi, YLo, YHi, ZLo, ZHi; -double yaw,roll; -double elevation,azimuth; -int cxChar = 10, cyChar = 16; -int X0, Y0; -int X0G, Y0G; - -static RECT rcCoord; // where X= Y= is drawn -static RECT rcGrid; // rectangle within rcLower that forms the border of the grid, plus - // a 3 pixel slop. -static RECT rcLower; // lower half of window, where plan view is drawn -static RECT rcUpper; // upper half or entire window, where isometric projection is drawn - -void vertex_selected (); -void texfont_init (); -void texfont_write (const char *text, float l, float t); - -#define PEN_GRID { \ - g_GLTable.m_pfn_qglLineWidth (1); \ - g_GLTable.m_pfn_qglColor3f (0, 1, 0); \ - g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); } - -#define PEN_RED { \ - g_GLTable.m_pfn_qglLineWidth (2); \ - g_GLTable.m_pfn_qglColor3f (1, 0, 0); \ - g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); } - -#define PEN_DASH { \ - g_GLTable.m_pfn_qglLineWidth (1); \ - g_GLTable.m_pfn_qglColor3f (0, 1, 0); \ - g_GLTable.m_pfn_qglLineStipple (1, 0xF0F0); \ - g_GLTable.m_pfn_qglEnable (GL_LINE_STIPPLE); } - -#define DRAW_QUAD(rc,r,g,b) { \ - g_GLTable.m_pfn_qglBegin (GL_QUADS); \ - g_GLTable.m_pfn_qglColor3f (0,1,0); \ - g_GLTable.m_pfn_qglVertex2f (rc.left-1, rc.bottom); \ - g_GLTable.m_pfn_qglVertex2f (rc.right, rc.bottom); \ - g_GLTable.m_pfn_qglVertex2f (rc.right, rc.top+1); \ - g_GLTable.m_pfn_qglVertex2f (rc.left-1, rc.top+1); \ - g_GLTable.m_pfn_qglColor3f (r,g,b); \ - g_GLTable.m_pfn_qglVertex2f (rc.left, rc.bottom+1); \ - g_GLTable.m_pfn_qglVertex2f (rc.right-1, rc.bottom+1); \ - g_GLTable.m_pfn_qglVertex2f (rc.right-1, rc.top); \ - g_GLTable.m_pfn_qglVertex2f (rc.left, rc.top); \ - g_GLTable.m_pfn_qglEnd (); } - - -#ifndef ISOMETRIC -double D=65536.; -double ct[3],st[3]; -double Hhi, Hlo, Vhi, Vlo; -#endif - -#define SUBDIVS 6 - - -void ShowPreview () -{ - if (Preview) - { - if (g_pWndPreview == NULL) - CreateViewWindow (); - gtk_widget_show (g_pWndPreview); - - UpdatePreview (true); - } - else - gtk_widget_hide (g_pWndPreview); -} - -static void draw_preview () -{ - int width = g_pPreviewWidget->allocation.width, height = g_pPreviewWidget->allocation.height; - - g_GLTable.m_pfn_qglClearColor (0, 0, 0, 1); - g_GLTable.m_pfn_qglViewport (0, 0, width, height); - g_GLTable.m_pfn_qglMatrixMode (GL_PROJECTION); - g_GLTable.m_pfn_qglLoadIdentity (); - g_GLTable.m_pfn_qglOrtho (0, width, 0, height, -1, 1); - g_GLTable.m_pfn_qglClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); - - // ^Fishman - Antializing for the preview window. - if (Antialiasing) - { - g_GLTable.m_pfn_qglEnable(GL_BLEND); - g_GLTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - g_GLTable.m_pfn_qglEnable(GL_LINE_SMOOTH); - } - else - { - g_GLTable.m_pfn_qglDisable(GL_BLEND); - g_GLTable.m_pfn_qglDisable(GL_LINE_SMOOTH); - } - - texfont_init (); - - if (!ValidSurface ()) - return; - - rcUpper.left = 0; - rcUpper.right = width; - rcUpper.bottom = 0; - rcUpper.top = height; - rcLower.left = 0; - rcLower.right = width; - rcLower.bottom = 0; - rcLower.top = height; - - if (VertexMode) - { - rcUpper.bottom = rcUpper.top/2; - DrawPreview (rcUpper); - g_GLTable.m_pfn_qglBegin (GL_LINES); - g_GLTable.m_pfn_qglVertex2f (rcUpper.left, rcUpper.bottom); - g_GLTable.m_pfn_qglVertex2f (rcUpper.right, rcUpper.bottom); - g_GLTable.m_pfn_qglEnd (); - rcLower.top = rcUpper.bottom-1; - DrawGrid (rcLower); - rcCoord.left = rcLower.left; - rcCoord.right = rcLower.right; - rcCoord.bottom = rcLower.bottom; - rcCoord.top = rcLower.top; - rcCoord.top = rcCoord.bottom+cyChar; - rcCoord.right = rcCoord.left + 15*cxChar; - rcGrid.left = X0G - 3; - rcGrid.bottom = Y0G - 3; - rcGrid.right = X0G + (int)(SFG*(Hur-Hll)) + 3; - rcGrid.top = Y0G + (int)(SFG*(Vur-Vll)) + 3; - } - else - DrawPreview (rcUpper); -} - -static gint expose (GtkWidget *widget, GdkEventExpose *event, gpointer data) -{ - if (event->count > 0) - return TRUE; - - if (!g_UIGtkTable.m_pfn_glwidget_make_current (g_pPreviewWidget)) - { - g_FuncTable.m_pfnSysPrintf ("GtkGenSurf: glMakeCurrent failed\n"); - return TRUE; - } - - draw_preview (); - - g_UIGtkTable.m_pfn_glwidget_swap_buffers (g_pPreviewWidget); - g_GLTable.m_pfn_QE_CheckOpenGLForErrors (); - - return TRUE; -} - -static void button_press (GtkWidget *widget, GdkEventButton *event, gpointer data) -{ - POINT pt = { (long)event->x, widget->allocation.height - (long)event->y }; - bool Selected; - double x,y; - int i, j, k, ks; - int i0, i1, j0, j1; - - if ((!VertexMode) || (event->button != 1)) - return; - - if (!PtInRect (&rcGrid,pt)) - { - gdk_beep (); - return; - } - - x = Hll + (pt.x-X0G)/SFG; - y = Vur - (pt.y-Y0G)/SFG; - i = (int)(floor( (x-Hll)/dh - 0.5) + 1); - j = (int)(floor( (y-Vll)/dv - 0.5) + 1); - if (i < 0 || i > NH || j < 0 || j > NV) - { - gdk_beep (); - return; - } - - if(!CanEdit(i,j)) - { - gdk_beep (); - return; - } - - // Control key pressed - add this point, or remove it if already selected - if ((event->state & GDK_CONTROL_MASK) != 0) - { - Selected = FALSE; - if (NumVerticesSelected) - { - for (k=0; kstate & GDK_SHIFT_MASK) != 0) - { - if (NumVerticesSelected) - { - NumVerticesSelected = 1; - i0 = min(Vertex[0].i, i); - i1 = max(Vertex[0].i, i); - j0 = min(Vertex[0].j, j); - j1 = max(Vertex[0].j, j); - for(i=i0; i<=i1; i++) - { - for(j=j0; j<=j1; j++) - { - if(i==0 && j==0 ) continue; - if(i==NH && j==0 ) continue; - if(i==0 && j==NV) continue; - if(i==NH && j==NV) continue; - if(i != Vertex[0].i || j != Vertex[0].j) - { - Vertex[NumVerticesSelected].i = i; - Vertex[NumVerticesSelected].j = j; - NumVerticesSelected++; - } - } - } - } - else - { - Vertex[0].i = i; - Vertex[0].j = j; - NumVerticesSelected = 1; - } - } - else - { - Vertex[0].i = i; - Vertex[0].j = j; - NumVerticesSelected = 1; - } - - vertex_selected (); -} - -static void motion (GtkWidget *widget, GdkEventMotion *event, gpointer data) -{ - POINT pt = { (long)event->x, widget->allocation.height - (long)event->y }; - - if (!VertexMode) - return; - - if (!g_UIGtkTable.m_pfn_glwidget_make_current (g_pPreviewWidget)) - { - g_FuncTable.m_pfnSysPrintf ("GtkGenSurf: glMakeCurrent failed\n"); - return; - } - - g_GLTable.m_pfn_qglEnable (GL_SCISSOR_TEST); - g_GLTable.m_pfn_qglScissor (rcCoord.left, rcCoord.bottom, rcCoord.right-rcCoord.left, - rcCoord.top-rcCoord.bottom); - g_GLTable.m_pfn_qglClear (GL_COLOR_BUFFER_BIT); - - if (PtInRect(&rcGrid,pt)) - { - GdkCursor *cursor = gdk_cursor_new (GDK_CROSS); - gdk_window_set_cursor (g_pWndPreview->window, cursor); - gdk_cursor_unref (cursor); - - char Text[32]; - int x, y; - - x = (int)(Hll + (pt.x-X0G)/SFG); - y = (int)(Vur - (pt.y-Y0G)/SFG); - switch(Plane) - { - case PLANE_XZ0: - case PLANE_XZ1: - sprintf(Text," x=%d, z=%d ",(int)(floor(x-0.5)+1.) ,(int)(floor(y-0.5)+1.) ); - break; - case PLANE_YZ0: - case PLANE_YZ1: - sprintf(Text," y=%d, z=%d ",(int)(floor(x-0.5)+1.) ,(int)(floor(y-0.5)+1.) ); - break; - default: - sprintf(Text," x=%d, y=%d ",(int)(floor(x-0.5)+1.) ,(int)(floor(y-0.5)+1.) ); - } - - texfont_write (Text, rcCoord.left, rcCoord.top); - } - else - { - gdk_window_set_cursor (g_pWndPreview->window, NULL); - } - - g_UIGtkTable.m_pfn_glwidget_swap_buffers (g_pPreviewWidget); - g_GLTable.m_pfn_QE_CheckOpenGLForErrors (); - g_GLTable.m_pfn_qglDisable (GL_SCISSOR_TEST); -} - -static gint preview_close (GtkWidget *widget, gpointer data) -{ - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "main_preview")), FALSE); - return TRUE; -} - -static void preview_focusout (GtkSpinButton *spin, GdkEventFocus *event, double *data) -{ - *data = DegreesToRadians ((double)(gtk_spin_button_get_value_as_int (spin) % 360)); - UpdatePreview (false); -} - -static gint doublevariable_spinfocusout(GtkWidget* widget, GdkEventFocus* event, gpointer data) -{ - preview_focusout(GTK_SPIN_BUTTON(widget), event, reinterpret_cast(data)); - return FALSE; -} - -static void preview_spin (GtkAdjustment *adj, double *data) -{ - *data = DegreesToRadians (adj->value); - UpdatePreview (false); -} - -void CreateViewWindow () -{ - GtkWidget *dlg, *vbox, *hbox, *label, *spin, *frame; - GtkObject *adj; - -#ifndef ISOMETRIC - elevation = PI/6.; - azimuth = PI/6.; -#endif - - g_pWndPreview = dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "GtkGenSurf Preview"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", GTK_SIGNAL_FUNC (preview_close), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pWnd)); - gtk_window_set_default_size (GTK_WINDOW (dlg), 300, 400); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_container_add (GTK_CONTAINER (dlg), vbox); - -#ifndef ISOMETRIC - hbox = gtk_hbox_new (TRUE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 3); - - label = gtk_label_new ("Elevation"); - gtk_widget_show (label); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0); - - adj = gtk_adjustment_new (30, -90, 90, 1, 10, 10); - gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (preview_spin), &elevation); - spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); - gtk_widget_show (spin); - gtk_box_pack_start (GTK_BOX (hbox), spin, FALSE, TRUE, 0); - g_signal_connect (G_OBJECT (spin), "focus_out_event", G_CALLBACK (doublevariable_spinfocusout), &elevation); - - adj = gtk_adjustment_new (30, 0, 359, 1, 10, 10); - gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (preview_spin), &azimuth); - spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); - gtk_widget_show (spin); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spin), TRUE); - gtk_box_pack_end (GTK_BOX (hbox), spin, FALSE, TRUE, 0); - - label = gtk_label_new ("Azimuth"); - gtk_widget_show (label); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, TRUE, 0); - g_signal_connect (G_OBJECT (spin), "focus_out_event", G_CALLBACK (doublevariable_spinfocusout), &azimuth); -#endif - - frame = gtk_frame_new (NULL); - gtk_widget_show (frame); - gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); - gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); - - g_pPreviewWidget = g_UIGtkTable.m_pfn_glwidget_new (FALSE, NULL); - - gtk_widget_set_events (g_pPreviewWidget, GDK_EXPOSURE_MASK|GDK_BUTTON_PRESS_MASK|GDK_POINTER_MOTION_MASK); - gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "expose_event", GTK_SIGNAL_FUNC (expose), NULL); - gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "motion_notify_event", GTK_SIGNAL_FUNC (motion), NULL); - gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "button_press_event", - GTK_SIGNAL_FUNC (button_press), NULL); - - gtk_widget_show (g_pPreviewWidget); - gtk_container_add (GTK_CONTAINER (frame), g_pPreviewWidget); - - if (Preview) - gtk_widget_show (g_pWndPreview); - - UpdatePreview (true); -} - -//============================================================= -/* DrawPreview */ -void DrawPreview (RECT rc) -{ -#define COSXA 0.8660254037844 -#define SINXA 0.5 -#define COSYA 0.8660254037844 -#define SINYA 0.5 - - double L; - double x,y; - int i, j; - POINT pt[8]; - XYZ v[8]; - char axis[3][2] = {"X","Y","Z"}; - -#ifndef ISOMETRIC - evaluate(); -#endif - - XLo = xmin; - XHi = xmax; - YLo = ymin; - YHi = ymax; - ZLo = zmin; - ZHi = zmax; - switch (Plane) - { - case PLANE_XY1: - ZHi = backface; - break; - case PLANE_XZ0: - YLo = backface; - break; - case PLANE_XZ1: - YHi = backface; - break; - case PLANE_YZ0: - XLo = backface; - break; - case PLANE_YZ1: - XHi = backface; - break; - default: - ZLo = backface; - } - - - - GetScaleFactor(rc); - //PEN_GRID - g_GLTable.m_pfn_qglLineWidth (1); - g_GLTable.m_pfn_qglColor3f (0, 1, 0); - g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); - - if (Decimate > 0 && (Game != QUAKE3 || UsePatches==0) ) - { - XYZ *vv; - - vv = (XYZ *) malloc(gNumNodes * sizeof(XYZ)); - for(i=0; i 2) - x = Hll + dh * (int)(NH/2 + 1); - else - x = Hll + dh * (int)(NH/2); - if(NV > 2) - y = Vll + dv * (int)(NV/2 + 1); - else - y = Vll + dv * (int)(NV/2); - } - else - { - if(NH > 1) - x = Hll + dh * (int)(NH/2); - else - x = Hll + dh/2; - if(NV > 1) - y = Vll + dv * (int)(NV/2); - else - y = Vll + dv/2; - } -// x = (Hll+Hur)/2.; -// y = (Vll+Vur)/2.; - v[0].p[0] = x + PlayerBox[Game].x[0]; - v[0].p[1] = y + PlayerBox[Game].y[0]; - v[0].p[2] = PlayerStartZ(x,y) + PlayerBox[Game].z[0] + 8; // add 8 cuz I'm a pessimist - } - v[1].p[0] = v[0].p[0] + PlayerBox[Game].x[1] - PlayerBox[Game].x[0]; - v[1].p[1] = v[0].p[1]; - v[1].p[2] = v[0].p[2]; - v[2].p[0] = v[1].p[0]; - v[2].p[1] = v[1].p[1] + PlayerBox[Game].y[1] - PlayerBox[Game].y[0]; - v[2].p[2] = v[0].p[2]; - v[3].p[0] = v[0].p[0]; - v[3].p[1] = v[2].p[1]; - v[3].p[2] = v[0].p[2]; - VectorCopy(v[0].p,v[4].p); - VectorCopy(v[1].p,v[5].p); - VectorCopy(v[2].p,v[6].p); - VectorCopy(v[3].p,v[7].p); - v[4].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0]; - v[5].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0]; - v[6].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0]; - v[7].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0]; - for(i=0; i<=7; i++) - { -#ifndef ISOMETRIC - project(&v[i]); -#endif - Scale(rc,v[i],&pt[i]); - } - g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP); - g_GLTable.m_pfn_qglVertex2f (pt[3].x, pt[3].y); - for(i=0; i<=3; i++) - g_GLTable.m_pfn_qglVertex2f (pt[i].x, pt[i].y); - g_GLTable.m_pfn_qglEnd (); - g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP); - g_GLTable.m_pfn_qglVertex2f (pt[7].x, pt[7].y); - for(i=4; i<=7; i++) - g_GLTable.m_pfn_qglVertex2f (pt[i].x, pt[i].y); - g_GLTable.m_pfn_qglEnd (); - g_GLTable.m_pfn_qglBegin (GL_LINES); - for(i=0; i<=3; i++) - { - g_GLTable.m_pfn_qglVertex2f (pt[i].x,pt[i].y); - g_GLTable.m_pfn_qglVertex2f (pt[i+4].x,pt[i+4].y); - } - g_GLTable.m_pfn_qglEnd (); - - g_GLTable.m_pfn_qglLineWidth (1); - g_GLTable.m_pfn_qglColor3f (0, 1, 0); - g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); -} -//============================================================= -void DrawGrid(RECT rc) -{ - int i, j, k; - double h,w,x,y; - POINT pt[2]; - RECT rcBox; - - w = (double)(rc.right-rc.left+1) - cxChar; - h = (double)(rc.top-rc.bottom+1) - cxChar - cyChar; - - SFG = w/(Hur-Hll); - SFG = min(SFG, h/(Vur-Vll)); - - // Center drawing - X0G = (int)(rc.left + rc.right - (int)(SFG*(Hur-Hll)))/2; - Y0G = (int)(rc.top + rc.bottom + cyChar - (int)(SFG*(Vur-Vll)))/2; - - g_GLTable.m_pfn_qglLineWidth (2); - g_GLTable.m_pfn_qglColor3f (0, 1, 0); - g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); - - pt[0].y = Y0G; - pt[1].y = Y0G + (int)(SFG*(Vur-Vll)); - g_GLTable.m_pfn_qglBegin (GL_LINES); - for(i=0; i<=NH; i++) - { - x = Hll + i * dh; - pt[0].x = X0G + (int)(SFG*(x-Hll)); - g_GLTable.m_pfn_qglVertex2f(pt[0].x, pt[0].y); - g_GLTable.m_pfn_qglVertex2f(pt[0].x, pt[1].y); - } - g_GLTable.m_pfn_qglEnd (); - pt[0].x = X0G; - pt[1].x = X0G + (int)(SFG*(Hur-Hll)); - g_GLTable.m_pfn_qglBegin (GL_LINES); - for(i=0; i<=NV; i++) - { - y = Vll + i * dv; - pt[0].y = Y0G + (int)(SFG*(Vur-y)); - g_GLTable.m_pfn_qglVertex2f (pt[0].x,pt[0].y); - g_GLTable.m_pfn_qglVertex2f (pt[1].x,pt[0].y); - } - g_GLTable.m_pfn_qglEnd (); - - g_GLTable.m_pfn_qglLineWidth (1); - - // Draw axes - pt[0].x = rc.right - cyChar - cxChar - cyChar/2; - pt[0].y = rc.bottom + cyChar/2; - pt[1].x = pt[0].x + cyChar; - pt[1].y = pt[0].y; - g_GLTable.m_pfn_qglBegin (GL_LINES); - g_GLTable.m_pfn_qglVertex2f (pt[0].x,pt[0].y); - g_GLTable.m_pfn_qglVertex2f (pt[1].x,pt[1].y); - g_GLTable.m_pfn_qglEnd (); - switch(Plane) - { - case PLANE_YZ0: - case PLANE_YZ1: - texfont_write ("Y", pt[1].x, pt[1].y+cyChar/2); - break; - default: - texfont_write ("X", pt[1].x, pt[1].y+cyChar/2); - } - pt[1].x = pt[0].x; - pt[1].y = pt[0].y + cyChar; - g_GLTable.m_pfn_qglBegin (GL_LINES); - g_GLTable.m_pfn_qglVertex2f (pt[0].x,pt[0].y); - g_GLTable.m_pfn_qglVertex2f (pt[1].x,pt[1].y); - g_GLTable.m_pfn_qglEnd (); - switch(Plane) - { - case PLANE_XY0: - case PLANE_XY1: - texfont_write ("Y", pt[1].x-cyChar/2, pt[1].y+cyChar); - break; - default: - texfont_write ("Z", pt[1].x-cyChar/2, pt[1].y+cyChar); - } - - // Denote fixed points with a 5x5 red rectangle - for(i=0; i<=NH; i++) - { - for(j=0; j<=NV; j++) - { - if(xyz[i][j].fixed) - { - x = Hll + i*dh; - y = Vll + j*dv; - rcBox.left = X0G + (int)(SFG*(x-Hll)) - 2; - rcBox.top = Y0G + (int)(SFG*(Vur-y)) + 2; - rcBox.right = rcBox.left + 5; - rcBox.bottom = rcBox.top - 5; - - DRAW_QUAD (rcBox, 1,0,0); - } - } - } - - // Denote currently selected point with a 5x5 green rectangle - if (NumVerticesSelected) - { - for(k=0; kp[0]; - y = v->p[1]; - z = v->p[2]; - - // yaw - xa = ct[0]*x - st[0]*z; - za = st[0]*x + ct[0]*z; - - // roll - x = ct[1]*xa + st[1]*y; - ya = ct[1]*y - st[1]*xa; - - // azimuth - z = ct[2]*za - st[2]*ya; - y = ct[2]*ya + st[2]*za; - - // horizontal and vertical projections: -// v->pp[0] = D*x/z; -// v->pp[1] = D*y/z; - v->pp[0] = -y; - v->pp[1] = x; - v->pp[2] = z; - - // NOTE: if perspective transformation is desired, - // set "persp" to the range from the surface, - // then: - // v->projected_h = -v->projected_h * persp/(v->projected_z-persp); - // v->projected_v = -v->projected_v * persp/(v->projected_z-persp); -} -/*=======================================================================*/ -void evaluate() -{ - int i, j; - XYZ v[4]; - - if(elevation > PI) elevation -= 2.*PI; - roll = elevation * sin(azimuth); - yaw = 1.5*PI + elevation*cos(azimuth); - - // Find angles from midpoint to viewpoint: - st[0] = sin(yaw); - st[1] = sin(roll); - st[2] = sin(azimuth); - ct[0] = cos(yaw); - ct[1] = cos(roll); - ct[2] = cos(azimuth); - - for(i=0; i<=NH; i++) - { - for(j=0; j<=NV; j++) - { - project(&xyz[i][j]); - } - } - - Hhi = xyz[0][0].pp[0]; - Hlo = Hhi; - Vhi = xyz[0][0].pp[1]; - Vlo = Vhi; - for(i=0; i<=NH; i++) - { - for(j=0; j<=NV; j++) - { - Hlo = min(Hlo,xyz[i][j].pp[0]); - Hhi = max(Hhi,xyz[i][j].pp[0]); - Vlo = min(Vlo,xyz[i][j].pp[1]); - Vhi = max(Vhi,xyz[i][j].pp[1]); - } - } - - // Include backface in min-max - VectorCopy(xyz[ 0][ 0].p,v[0].p); - VectorCopy(xyz[NH][ 0].p,v[1].p); - VectorCopy(xyz[NH][NV].p,v[2].p); - VectorCopy(xyz[ 0][NV].p,v[3].p); - switch(Plane) - { - case PLANE_XZ0: - case PLANE_XZ1: - v[0].p[1] = backface; - v[1].p[1] = v[0].p[1]; - v[2].p[1] = v[0].p[1]; - v[3].p[1] = v[0].p[1]; - break; - case PLANE_YZ0: - case PLANE_YZ1: - v[0].p[0] = backface; - v[1].p[0] = v[0].p[0]; - v[2].p[0] = v[0].p[0]; - v[3].p[0] = v[0].p[0]; - break; - default: - v[0].p[2] = backface; - v[1].p[2] = v[0].p[2]; - v[2].p[2] = v[0].p[2]; - v[3].p[2] = v[0].p[2]; - } - for(i=0; i<=3; i++) - { - project(&v[i]); - Hlo = min(Hlo,v[i].pp[0]); - Hhi = max(Hhi,v[i].pp[0]); - Vlo = min(Vlo,v[i].pp[1]); - Vhi = max(Vhi,v[i].pp[1]); - } - -} -#endif +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +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 +*/ + +#include +#include +#include +#include "gensurf.h" + +#undef ISOMETRIC + +extern double backface; +extern double dh, dv; +extern double xmin,xmax,ymin,ymax,zmin,zmax; + +double SF, SFG; // Graphics scale factors +double XLo, XHi, YLo, YHi, ZLo, ZHi; +double yaw,roll; +double elevation,azimuth; +int cxChar = 10, cyChar = 16; +int X0, Y0; +int X0G, Y0G; + +static RECT rcCoord; // where X= Y= is drawn +static RECT rcGrid; // rectangle within rcLower that forms the border of the grid, plus + // a 3 pixel slop. +static RECT rcLower; // lower half of window, where plan view is drawn +static RECT rcUpper; // upper half or entire window, where isometric projection is drawn + +void vertex_selected (); +void texfont_init (); +void texfont_write (const char *text, float l, float t); + +#define PEN_GRID { \ + g_GLTable.m_pfn_qglLineWidth (1); \ + g_GLTable.m_pfn_qglColor3f (0, 1, 0); \ + g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); } + +#define PEN_RED { \ + g_GLTable.m_pfn_qglLineWidth (2); \ + g_GLTable.m_pfn_qglColor3f (1, 0, 0); \ + g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); } + +#define PEN_DASH { \ + g_GLTable.m_pfn_qglLineWidth (1); \ + g_GLTable.m_pfn_qglColor3f (0, 1, 0); \ + g_GLTable.m_pfn_qglLineStipple (1, 0xF0F0); \ + g_GLTable.m_pfn_qglEnable (GL_LINE_STIPPLE); } + +#define DRAW_QUAD(rc,r,g,b) { \ + g_GLTable.m_pfn_qglBegin (GL_QUADS); \ + g_GLTable.m_pfn_qglColor3f (0,1,0); \ + g_GLTable.m_pfn_qglVertex2f (rc.left-1, rc.bottom); \ + g_GLTable.m_pfn_qglVertex2f (rc.right, rc.bottom); \ + g_GLTable.m_pfn_qglVertex2f (rc.right, rc.top+1); \ + g_GLTable.m_pfn_qglVertex2f (rc.left-1, rc.top+1); \ + g_GLTable.m_pfn_qglColor3f (r,g,b); \ + g_GLTable.m_pfn_qglVertex2f (rc.left, rc.bottom+1); \ + g_GLTable.m_pfn_qglVertex2f (rc.right-1, rc.bottom+1); \ + g_GLTable.m_pfn_qglVertex2f (rc.right-1, rc.top); \ + g_GLTable.m_pfn_qglVertex2f (rc.left, rc.top); \ + g_GLTable.m_pfn_qglEnd (); } + + +#ifndef ISOMETRIC +double D=65536.; +double ct[3],st[3]; +double Hhi, Hlo, Vhi, Vlo; +#endif + +#define SUBDIVS 6 + + +void ShowPreview () +{ + if (Preview) + { + if (g_pWndPreview == NULL) + CreateViewWindow (); + gtk_widget_show (g_pWndPreview); + + UpdatePreview (true); + } + else + gtk_widget_hide (g_pWndPreview); +} + +static void draw_preview () +{ + int width = g_pPreviewWidget->allocation.width, height = g_pPreviewWidget->allocation.height; + + g_GLTable.m_pfn_qglClearColor (0, 0, 0, 1); + g_GLTable.m_pfn_qglViewport (0, 0, width, height); + g_GLTable.m_pfn_qglMatrixMode (GL_PROJECTION); + g_GLTable.m_pfn_qglLoadIdentity (); + g_GLTable.m_pfn_qglOrtho (0, width, 0, height, -1, 1); + g_GLTable.m_pfn_qglClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + + // ^Fishman - Antializing for the preview window. + if (Antialiasing) + { + g_GLTable.m_pfn_qglEnable(GL_BLEND); + g_GLTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + g_GLTable.m_pfn_qglEnable(GL_LINE_SMOOTH); + } + else + { + g_GLTable.m_pfn_qglDisable(GL_BLEND); + g_GLTable.m_pfn_qglDisable(GL_LINE_SMOOTH); + } + + texfont_init (); + + if (!ValidSurface ()) + return; + + rcUpper.left = 0; + rcUpper.right = width; + rcUpper.bottom = 0; + rcUpper.top = height; + rcLower.left = 0; + rcLower.right = width; + rcLower.bottom = 0; + rcLower.top = height; + + if (VertexMode) + { + rcUpper.bottom = rcUpper.top/2; + DrawPreview (rcUpper); + g_GLTable.m_pfn_qglBegin (GL_LINES); + g_GLTable.m_pfn_qglVertex2f (rcUpper.left, rcUpper.bottom); + g_GLTable.m_pfn_qglVertex2f (rcUpper.right, rcUpper.bottom); + g_GLTable.m_pfn_qglEnd (); + rcLower.top = rcUpper.bottom-1; + DrawGrid (rcLower); + rcCoord.left = rcLower.left; + rcCoord.right = rcLower.right; + rcCoord.bottom = rcLower.bottom; + rcCoord.top = rcLower.top; + rcCoord.top = rcCoord.bottom+cyChar; + rcCoord.right = rcCoord.left + 15*cxChar; + rcGrid.left = X0G - 3; + rcGrid.bottom = Y0G - 3; + rcGrid.right = X0G + (int)(SFG*(Hur-Hll)) + 3; + rcGrid.top = Y0G + (int)(SFG*(Vur-Vll)) + 3; + } + else + DrawPreview (rcUpper); +} + +static gint expose (GtkWidget *widget, GdkEventExpose *event, gpointer data) +{ + if (event->count > 0) + return TRUE; + + if (!g_UIGtkTable.m_pfn_glwidget_make_current (g_pPreviewWidget)) + { + g_FuncTable.m_pfnSysPrintf ("GtkGenSurf: glMakeCurrent failed\n"); + return TRUE; + } + + draw_preview (); + + g_UIGtkTable.m_pfn_glwidget_swap_buffers (g_pPreviewWidget); + g_GLTable.m_pfn_QE_CheckOpenGLForErrors (); + + return TRUE; +} + +static void button_press (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + POINT pt = { (long)event->x, widget->allocation.height - (long)event->y }; + bool Selected; + double x,y; + int i, j, k, ks; + int i0, i1, j0, j1; + + if ((!VertexMode) || (event->button != 1)) + return; + + if (!PtInRect (&rcGrid,pt)) + { + gdk_beep (); + return; + } + + x = Hll + (pt.x-X0G)/SFG; + y = Vur - (pt.y-Y0G)/SFG; + i = (int)(floor( (x-Hll)/dh - 0.5) + 1); + j = (int)(floor( (y-Vll)/dv - 0.5) + 1); + if (i < 0 || i > NH || j < 0 || j > NV) + { + gdk_beep (); + return; + } + + if(!CanEdit(i,j)) + { + gdk_beep (); + return; + } + + // Control key pressed - add this point, or remove it if already selected + if ((event->state & GDK_CONTROL_MASK) != 0) + { + Selected = FALSE; + if (NumVerticesSelected) + { + for (k=0; kstate & GDK_SHIFT_MASK) != 0) + { + if (NumVerticesSelected) + { + NumVerticesSelected = 1; + i0 = min(Vertex[0].i, i); + i1 = max(Vertex[0].i, i); + j0 = min(Vertex[0].j, j); + j1 = max(Vertex[0].j, j); + for(i=i0; i<=i1; i++) + { + for(j=j0; j<=j1; j++) + { + if(i==0 && j==0 ) continue; + if(i==NH && j==0 ) continue; + if(i==0 && j==NV) continue; + if(i==NH && j==NV) continue; + if(i != Vertex[0].i || j != Vertex[0].j) + { + Vertex[NumVerticesSelected].i = i; + Vertex[NumVerticesSelected].j = j; + NumVerticesSelected++; + } + } + } + } + else + { + Vertex[0].i = i; + Vertex[0].j = j; + NumVerticesSelected = 1; + } + } + else + { + Vertex[0].i = i; + Vertex[0].j = j; + NumVerticesSelected = 1; + } + + vertex_selected (); +} + +static void motion (GtkWidget *widget, GdkEventMotion *event, gpointer data) +{ + POINT pt = { (long)event->x, widget->allocation.height - (long)event->y }; + + if (!VertexMode) + return; + + if (!g_UIGtkTable.m_pfn_glwidget_make_current (g_pPreviewWidget)) + { + g_FuncTable.m_pfnSysPrintf ("GtkGenSurf: glMakeCurrent failed\n"); + return; + } + + g_GLTable.m_pfn_qglEnable (GL_SCISSOR_TEST); + g_GLTable.m_pfn_qglScissor (rcCoord.left, rcCoord.bottom, rcCoord.right-rcCoord.left, + rcCoord.top-rcCoord.bottom); + g_GLTable.m_pfn_qglClear (GL_COLOR_BUFFER_BIT); + + if (PtInRect(&rcGrid,pt)) + { + GdkCursor *cursor = gdk_cursor_new (GDK_CROSS); + gdk_window_set_cursor (g_pWndPreview->window, cursor); + gdk_cursor_unref (cursor); + + char Text[32]; + int x, y; + + x = (int)(Hll + (pt.x-X0G)/SFG); + y = (int)(Vur - (pt.y-Y0G)/SFG); + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + sprintf(Text," x=%d, z=%d ",(int)(floor(x-0.5)+1.) ,(int)(floor(y-0.5)+1.) ); + break; + case PLANE_YZ0: + case PLANE_YZ1: + sprintf(Text," y=%d, z=%d ",(int)(floor(x-0.5)+1.) ,(int)(floor(y-0.5)+1.) ); + break; + default: + sprintf(Text," x=%d, y=%d ",(int)(floor(x-0.5)+1.) ,(int)(floor(y-0.5)+1.) ); + } + + texfont_write (Text, rcCoord.left, rcCoord.top); + } + else + { + gdk_window_set_cursor (g_pWndPreview->window, NULL); + } + + g_UIGtkTable.m_pfn_glwidget_swap_buffers (g_pPreviewWidget); + g_GLTable.m_pfn_QE_CheckOpenGLForErrors (); + g_GLTable.m_pfn_qglDisable (GL_SCISSOR_TEST); +} + +static gint preview_close (GtkWidget *widget, gpointer data) +{ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "main_preview")), FALSE); + return TRUE; +} + +static void preview_focusout (GtkSpinButton *spin, GdkEventFocus *event, double *data) +{ + *data = DegreesToRadians ((double)(gtk_spin_button_get_value_as_int (spin) % 360)); + UpdatePreview (false); +} + +static gint doublevariable_spinfocusout(GtkWidget* widget, GdkEventFocus* event, gpointer data) +{ + preview_focusout(GTK_SPIN_BUTTON(widget), event, reinterpret_cast(data)); + return FALSE; +} + +static void preview_spin (GtkAdjustment *adj, double *data) +{ + *data = DegreesToRadians (adj->value); + UpdatePreview (false); +} + +void CreateViewWindow () +{ + GtkWidget *dlg, *vbox, *hbox, *label, *spin, *frame; + GtkObject *adj; + +#ifndef ISOMETRIC + elevation = PI/6.; + azimuth = PI/6.; +#endif + + g_pWndPreview = dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "GtkGenSurf Preview"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", GTK_SIGNAL_FUNC (preview_close), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pWnd)); + gtk_window_set_default_size (GTK_WINDOW (dlg), 300, 400); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + +#ifndef ISOMETRIC + hbox = gtk_hbox_new (TRUE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 3); + + label = gtk_label_new ("Elevation"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0); + + adj = gtk_adjustment_new (30, -90, 90, 1, 10, 10); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (preview_spin), &elevation); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_box_pack_start (GTK_BOX (hbox), spin, FALSE, TRUE, 0); + g_signal_connect (G_OBJECT (spin), "focus_out_event", G_CALLBACK (doublevariable_spinfocusout), &elevation); + + adj = gtk_adjustment_new (30, 0, 359, 1, 10, 10); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (preview_spin), &azimuth); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spin), TRUE); + gtk_box_pack_end (GTK_BOX (hbox), spin, FALSE, TRUE, 0); + + label = gtk_label_new ("Azimuth"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, TRUE, 0); + g_signal_connect (G_OBJECT (spin), "focus_out_event", G_CALLBACK (doublevariable_spinfocusout), &azimuth); +#endif + + frame = gtk_frame_new (NULL); + gtk_widget_show (frame); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); + + g_pPreviewWidget = g_UIGtkTable.m_pfn_glwidget_new (FALSE, NULL); + + gtk_widget_set_events (g_pPreviewWidget, GDK_EXPOSURE_MASK|GDK_BUTTON_PRESS_MASK|GDK_POINTER_MOTION_MASK); + gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "expose_event", GTK_SIGNAL_FUNC (expose), NULL); + gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "motion_notify_event", GTK_SIGNAL_FUNC (motion), NULL); + gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "button_press_event", + GTK_SIGNAL_FUNC (button_press), NULL); + + gtk_widget_show (g_pPreviewWidget); + gtk_container_add (GTK_CONTAINER (frame), g_pPreviewWidget); + + if (Preview) + gtk_widget_show (g_pWndPreview); + + UpdatePreview (true); +} + +//============================================================= +/* DrawPreview */ +void DrawPreview (RECT rc) +{ +#define COSXA 0.8660254037844 +#define SINXA 0.5 +#define COSYA 0.8660254037844 +#define SINYA 0.5 + + double L; + double x,y; + int i, j; + POINT pt[8]; + XYZ v[8]; + char axis[3][2] = {"X","Y","Z"}; + +#ifndef ISOMETRIC + evaluate(); +#endif + + XLo = xmin; + XHi = xmax; + YLo = ymin; + YHi = ymax; + ZLo = zmin; + ZHi = zmax; + switch (Plane) + { + case PLANE_XY1: + ZHi = backface; + break; + case PLANE_XZ0: + YLo = backface; + break; + case PLANE_XZ1: + YHi = backface; + break; + case PLANE_YZ0: + XLo = backface; + break; + case PLANE_YZ1: + XHi = backface; + break; + default: + ZLo = backface; + } + + + + GetScaleFactor(rc); + //PEN_GRID + g_GLTable.m_pfn_qglLineWidth (1); + g_GLTable.m_pfn_qglColor3f (0, 1, 0); + g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); + + if (Decimate > 0 && (Game != QUAKE3 || UsePatches==0) ) + { + XYZ *vv; + + vv = (XYZ *) malloc(gNumNodes * sizeof(XYZ)); + for(i=0; i 2) + x = Hll + dh * (int)(NH/2 + 1); + else + x = Hll + dh * (int)(NH/2); + if(NV > 2) + y = Vll + dv * (int)(NV/2 + 1); + else + y = Vll + dv * (int)(NV/2); + } + else + { + if(NH > 1) + x = Hll + dh * (int)(NH/2); + else + x = Hll + dh/2; + if(NV > 1) + y = Vll + dv * (int)(NV/2); + else + y = Vll + dv/2; + } +// x = (Hll+Hur)/2.; +// y = (Vll+Vur)/2.; + v[0].p[0] = x + PlayerBox[Game].x[0]; + v[0].p[1] = y + PlayerBox[Game].y[0]; + v[0].p[2] = PlayerStartZ(x,y) + PlayerBox[Game].z[0] + 8; // add 8 cuz I'm a pessimist + } + v[1].p[0] = v[0].p[0] + PlayerBox[Game].x[1] - PlayerBox[Game].x[0]; + v[1].p[1] = v[0].p[1]; + v[1].p[2] = v[0].p[2]; + v[2].p[0] = v[1].p[0]; + v[2].p[1] = v[1].p[1] + PlayerBox[Game].y[1] - PlayerBox[Game].y[0]; + v[2].p[2] = v[0].p[2]; + v[3].p[0] = v[0].p[0]; + v[3].p[1] = v[2].p[1]; + v[3].p[2] = v[0].p[2]; + VectorCopy(v[0].p,v[4].p); + VectorCopy(v[1].p,v[5].p); + VectorCopy(v[2].p,v[6].p); + VectorCopy(v[3].p,v[7].p); + v[4].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0]; + v[5].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0]; + v[6].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0]; + v[7].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0]; + for(i=0; i<=7; i++) + { +#ifndef ISOMETRIC + project(&v[i]); +#endif + Scale(rc,v[i],&pt[i]); + } + g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP); + g_GLTable.m_pfn_qglVertex2f (pt[3].x, pt[3].y); + for(i=0; i<=3; i++) + g_GLTable.m_pfn_qglVertex2f (pt[i].x, pt[i].y); + g_GLTable.m_pfn_qglEnd (); + g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP); + g_GLTable.m_pfn_qglVertex2f (pt[7].x, pt[7].y); + for(i=4; i<=7; i++) + g_GLTable.m_pfn_qglVertex2f (pt[i].x, pt[i].y); + g_GLTable.m_pfn_qglEnd (); + g_GLTable.m_pfn_qglBegin (GL_LINES); + for(i=0; i<=3; i++) + { + g_GLTable.m_pfn_qglVertex2f (pt[i].x,pt[i].y); + g_GLTable.m_pfn_qglVertex2f (pt[i+4].x,pt[i+4].y); + } + g_GLTable.m_pfn_qglEnd (); + + g_GLTable.m_pfn_qglLineWidth (1); + g_GLTable.m_pfn_qglColor3f (0, 1, 0); + g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); +} +//============================================================= +void DrawGrid(RECT rc) +{ + int i, j, k; + double h,w,x,y; + POINT pt[2]; + RECT rcBox; + + w = (double)(rc.right-rc.left+1) - cxChar; + h = (double)(rc.top-rc.bottom+1) - cxChar - cyChar; + + SFG = w/(Hur-Hll); + SFG = min(SFG, h/(Vur-Vll)); + + // Center drawing + X0G = (int)(rc.left + rc.right - (int)(SFG*(Hur-Hll)))/2; + Y0G = (int)(rc.top + rc.bottom + cyChar - (int)(SFG*(Vur-Vll)))/2; + + g_GLTable.m_pfn_qglLineWidth (2); + g_GLTable.m_pfn_qglColor3f (0, 1, 0); + g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); + + pt[0].y = Y0G; + pt[1].y = Y0G + (int)(SFG*(Vur-Vll)); + g_GLTable.m_pfn_qglBegin (GL_LINES); + for(i=0; i<=NH; i++) + { + x = Hll + i * dh; + pt[0].x = X0G + (int)(SFG*(x-Hll)); + g_GLTable.m_pfn_qglVertex2f(pt[0].x, pt[0].y); + g_GLTable.m_pfn_qglVertex2f(pt[0].x, pt[1].y); + } + g_GLTable.m_pfn_qglEnd (); + pt[0].x = X0G; + pt[1].x = X0G + (int)(SFG*(Hur-Hll)); + g_GLTable.m_pfn_qglBegin (GL_LINES); + for(i=0; i<=NV; i++) + { + y = Vll + i * dv; + pt[0].y = Y0G + (int)(SFG*(Vur-y)); + g_GLTable.m_pfn_qglVertex2f (pt[0].x,pt[0].y); + g_GLTable.m_pfn_qglVertex2f (pt[1].x,pt[0].y); + } + g_GLTable.m_pfn_qglEnd (); + + g_GLTable.m_pfn_qglLineWidth (1); + + // Draw axes + pt[0].x = rc.right - cyChar - cxChar - cyChar/2; + pt[0].y = rc.bottom + cyChar/2; + pt[1].x = pt[0].x + cyChar; + pt[1].y = pt[0].y; + g_GLTable.m_pfn_qglBegin (GL_LINES); + g_GLTable.m_pfn_qglVertex2f (pt[0].x,pt[0].y); + g_GLTable.m_pfn_qglVertex2f (pt[1].x,pt[1].y); + g_GLTable.m_pfn_qglEnd (); + switch(Plane) + { + case PLANE_YZ0: + case PLANE_YZ1: + texfont_write ("Y", pt[1].x, pt[1].y+cyChar/2); + break; + default: + texfont_write ("X", pt[1].x, pt[1].y+cyChar/2); + } + pt[1].x = pt[0].x; + pt[1].y = pt[0].y + cyChar; + g_GLTable.m_pfn_qglBegin (GL_LINES); + g_GLTable.m_pfn_qglVertex2f (pt[0].x,pt[0].y); + g_GLTable.m_pfn_qglVertex2f (pt[1].x,pt[1].y); + g_GLTable.m_pfn_qglEnd (); + switch(Plane) + { + case PLANE_XY0: + case PLANE_XY1: + texfont_write ("Y", pt[1].x-cyChar/2, pt[1].y+cyChar); + break; + default: + texfont_write ("Z", pt[1].x-cyChar/2, pt[1].y+cyChar); + } + + // Denote fixed points with a 5x5 red rectangle + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + if(xyz[i][j].fixed) + { + x = Hll + i*dh; + y = Vll + j*dv; + rcBox.left = X0G + (int)(SFG*(x-Hll)) - 2; + rcBox.top = Y0G + (int)(SFG*(Vur-y)) + 2; + rcBox.right = rcBox.left + 5; + rcBox.bottom = rcBox.top - 5; + + DRAW_QUAD (rcBox, 1,0,0); + } + } + } + + // Denote currently selected point with a 5x5 green rectangle + if (NumVerticesSelected) + { + for(k=0; kp[0]; + y = v->p[1]; + z = v->p[2]; + + // yaw + xa = ct[0]*x - st[0]*z; + za = st[0]*x + ct[0]*z; + + // roll + x = ct[1]*xa + st[1]*y; + ya = ct[1]*y - st[1]*xa; + + // azimuth + z = ct[2]*za - st[2]*ya; + y = ct[2]*ya + st[2]*za; + + // horizontal and vertical projections: +// v->pp[0] = D*x/z; +// v->pp[1] = D*y/z; + v->pp[0] = -y; + v->pp[1] = x; + v->pp[2] = z; + + // NOTE: if perspective transformation is desired, + // set "persp" to the range from the surface, + // then: + // v->projected_h = -v->projected_h * persp/(v->projected_z-persp); + // v->projected_v = -v->projected_v * persp/(v->projected_z-persp); +} +/*=======================================================================*/ +void evaluate() +{ + int i, j; + XYZ v[4]; + + if(elevation > PI) elevation -= 2.*PI; + roll = elevation * sin(azimuth); + yaw = 1.5*PI + elevation*cos(azimuth); + + // Find angles from midpoint to viewpoint: + st[0] = sin(yaw); + st[1] = sin(roll); + st[2] = sin(azimuth); + ct[0] = cos(yaw); + ct[1] = cos(roll); + ct[2] = cos(azimuth); + + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + project(&xyz[i][j]); + } + } + + Hhi = xyz[0][0].pp[0]; + Hlo = Hhi; + Vhi = xyz[0][0].pp[1]; + Vlo = Vhi; + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + Hlo = min(Hlo,xyz[i][j].pp[0]); + Hhi = max(Hhi,xyz[i][j].pp[0]); + Vlo = min(Vlo,xyz[i][j].pp[1]); + Vhi = max(Vhi,xyz[i][j].pp[1]); + } + } + + // Include backface in min-max + VectorCopy(xyz[ 0][ 0].p,v[0].p); + VectorCopy(xyz[NH][ 0].p,v[1].p); + VectorCopy(xyz[NH][NV].p,v[2].p); + VectorCopy(xyz[ 0][NV].p,v[3].p); + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + v[0].p[1] = backface; + v[1].p[1] = v[0].p[1]; + v[2].p[1] = v[0].p[1]; + v[3].p[1] = v[0].p[1]; + break; + case PLANE_YZ0: + case PLANE_YZ1: + v[0].p[0] = backface; + v[1].p[0] = v[0].p[0]; + v[2].p[0] = v[0].p[0]; + v[3].p[0] = v[0].p[0]; + break; + default: + v[0].p[2] = backface; + v[1].p[2] = v[0].p[2]; + v[2].p[2] = v[0].p[2]; + v[3].p[2] = v[0].p[2]; + } + for(i=0; i<=3; i++) + { + project(&v[i]); + Hlo = min(Hlo,v[i].pp[0]); + Hhi = max(Hhi,v[i].pp[0]); + Vlo = min(Vlo,v[i].pp[1]); + Vhi = max(Vhi,v[i].pp[1]); + } + +} +#endif diff --git a/contrib/hydratoolz/plugin.cpp b/contrib/hydratoolz/plugin.cpp index df97d494..1b8abd7d 100644 --- a/contrib/hydratoolz/plugin.cpp +++ b/contrib/hydratoolz/plugin.cpp @@ -1,417 +1,417 @@ -/* -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 -*/ - -#include "plugin.h" -#include "version.h" - -/*! \file plugin.cpp - \brief HydraToolz! - - HydraToolz by Dominic Clifton - Hydra (Hydra@Hydras-World.com) - - Overview - ======== - - This plugin allows the user to rebuild the "wad" key pair in the worldspawn - so that it has a list of all the .wad files in use. - - Version History - =============== - - v0.1 - 28/May/2002 - - Initial version. - - v1.0 - 10/March/2003 - - Added more console output - - Removed some old test code - - Tweaked dialog box. - - Fixed up for Radiant 1.3.5 - - - ToDo - ==== - - Nothing... - -*/ - -// ============================================================================= -// Globals - -_QERFuncTable_1 g_FuncTable; -_QERFileSystemTable g_FileSystemTable; -_QEREntityTable g_EntityTable; - - -// ============================================================================= -// Ripped from cmdlib.cpp - -/* -==================== -Extract file parts -==================== -*/ -void ExtractFilePath (const char *path, char *dest) -{ - const char *src; - - src = path + strlen(path) - 1; - -// -// back up until a \ or the start -// - while (src != path && *(src-1) != '/' && *(src-1) != '\\') - src--; - - memcpy (dest, path, src-path); - dest[src-path] = 0; -} - -void ExtractFileName (const char *path, char *dest) -{ - const char *src; - - src = path + strlen(path) - 1; - -// -// back up until a \ or the start -// - while (src != path && *(src-1) != '/' - && *(src-1) != '\\' ) - src--; - - while (*src) - { - *dest++ = *src++; - } - *dest = 0; -} - -void ConvertDOSToUnixName( char *dst, const char *src ) -{ - while ( *src ) - { - if ( *src == '\\' ) - *dst = '/'; - else - *dst = *src; - dst++; src++; - } - *dst = 0; -} - -// End of rip from cmdlib.cpp - -// ============================================================================= -// Actual Plugin Code - -// get the wad name from the shader name (or an actual wadname) and add to a list of wad names making -// sure we don't add duplicates. - -GSList *AddToWadList(GSList *wadlist, const char *shadername, const char *wad) -{ - char tmpstr[QER_MAX_NAMELEN]; - char *wadname; - if (!shadername && !wad) return wadlist; - - if (shadername) - { - if (strcmp(shadername,"color") == 0) - return wadlist; - ExtractFilePath(shadername,tmpstr); - // Sys_Printf("checking: %s\n",shadername); - - int l = strlen(tmpstr) - 1; - - if (tmpstr[l] == '/' || tmpstr[l] == '\\') - tmpstr[l] = 0; - else - { - Sys_Printf("HydraToolz: WARNING: Unknown wad file for shader %s\n",shadername); - return wadlist; - } - - ExtractFileName(tmpstr,tmpstr); - - wadname = (char *)malloc(strlen(tmpstr) + 5); - sprintf(wadname,"%s.wad",tmpstr); - } - else - { - wadname=strdup(wad); - } - - for (GSList *l = wadlist; l != NULL ; l = l->next) - { - if (!stricmp((char *)l->data,wadname)) - { - free( wadname ); - return wadlist; - } - } - - Sys_Printf("HydraToolz: Adding Wad File to WAD list: %s (reason: ",wadname); - if (shadername) - Sys_Printf("see shader \"%s\")\n", shadername); - else - Sys_Printf("already in WAD key. )\n"); - return ( g_slist_append (wadlist, wadname ) ); -} - -void UpdateWadKeyPair( void ) -{ - int i,nb; - - char wads[2048]; // change to CString usage ? - *wads = 0; - char *p1,*p2; - entity_t *pEntity; - epair_t *pEpair; - GSList *wadlist = NULL; - face_t *f; - brush_t *b; - char cleanwadname[QER_MAX_NAMELEN]; - char *actualwad; - - - pEntity = (entity_t *)g_FuncTable.m_pfnGetEntityHandle(0); // get the worldspawn ent - - Sys_Printf("HydraToolz: Searching for in-use wad files...\n"); - for(pEpair = pEntity->epairs; pEpair != NULL; pEpair = pEpair->next) - { - if (stricmp(pEpair->key,"wad") == 0) - { - strcpy(wads,pEpair->value); - ConvertDOSToUnixName(wads,wads); - - Sys_Printf("HydraToolz: Current wad key is \"%s\"!\n",wads); - - // ok, we got the list of ; delimited wads, now split it into a GSList that contains - // just the wad names themselves. - - p1 = wads; - - do - { - p2 = strchr(p1,';'); - if (p2) - *p2 = 0; // swap the ; with a null terminator - - if (strchr(p1,'/') || strchr(p1,'\\')) - { - ExtractFileName(p1,cleanwadname); - wadlist = AddToWadList (wadlist, NULL, cleanwadname); - } - else - { - wadlist = AddToWadList (wadlist, NULL, p1); - } - if (p2) - p1 = p2+1; // point back to the remainder of the string - else - p1 = NULL; // make it so we exit the loop. - - } while (p1); - - // ok, now we have a list of wads in GSList. - // now we need to add any new wadfiles (with their paths) to this list - // so scan all brushes and see what wads are in use - // FIXME: scan brushes only in the region ? - - break; // we don't need to process any more key/pairs. - } - } - - if (!*wads) - Sys_Printf("HydraToolz: No \"wad\" keypair wound in worldspawn\n"); - - - nb = g_FuncTable.m_pfnAllocateActiveBrushHandles(); - for( i = 0; i < nb; i++ ) - { - b = (brush_t *)g_FuncTable.m_pfnGetActiveBrushHandle(i); - if (b->patchBrush) // patches in halflife ? - { - wadlist = AddToWadList(wadlist, b->pPatch->pShader->getName(),NULL); - } else - { - for (f=b->brush_faces ; f ; f=f->next) - { - wadlist = AddToWadList(wadlist, f->pShader->getName(),NULL); - } - } - } - g_FuncTable.m_pfnReleaseActiveBrushHandles(); - - nb = g_FuncTable.m_pfnAllocateSelectedBrushHandles(); - for( i = 0; i < nb; i++ ) - { - b = (brush_t *)g_FuncTable.m_pfnGetSelectedBrushHandle(i); - if (b->patchBrush) // patches in halflife ? - { - wadlist = AddToWadList(wadlist, b->pPatch->pShader->getName(),NULL); - } else - { - for (f=b->brush_faces ; f ; f=f->next) - { - wadlist = AddToWadList(wadlist, f->pShader->getName(),NULL); - } - } - } - g_FuncTable.m_pfnReleaseSelectedBrushHandles(); - - Sys_Printf("HydraToolz: Rebuilding worldspawn's \"wad\" key-pair...\n"); - // Now we have a complete list of wadnames (without paths) so we just have to turn this - // back to a ; delimited list. - - *wads = 0; - while (wadlist) - { - // skip wad files if they start with "common-" - if (strnicmp((char *)wadlist->data,"common-",7) == 0) - { - Sys_Printf("HydraToolz: Skipping radiant/user-supplied wad file %s\n",(char *)wadlist->data); - } - else - { - if (wads[0]) - strcat(wads,";"); - - actualwad = vfsGetFullPath((char *)wadlist->data); - - if (actualwad) - { - strcat(wads, actualwad); - } - else - { - Sys_Printf("HydraToolz: WARNING: could not locate wad file %s\n",(char *)wadlist->data); - strcat(wads, (char *)wadlist->data); - } - } - - free (wadlist->data); - wadlist = g_slist_remove (wadlist, wadlist->data); - } - - // store the wad list back in the worldspawn. - if (*wads) - { - //free(pEpair->value); - //pEpair->value = strdup(wads); - SetKeyValue(pEntity, "wad", wads); - Sys_Printf("HydraToolz: Setting worldspawn \"wad\" key value to \"%s\"\n",wads); - - } - - Sys_Printf("HydraToolz: Finished rebuilding wad keypair!\n"); - -} - -// ============================================================================= -// PLUGIN INTERFACE STUFF - -// plugin name -const char *PLUGIN_NAME = "HydraToolz"; - -// commands in the menu -const char *PLUGIN_COMMANDS = "About...;Create/Update WAD keypair"; - -const char *PLUGIN_ABOUT = "HydraToolz v1.0 for GTKRadiant\n\n" - "By Hydra!"; - -extern "C" void* WINAPI QERPlug_GetFuncTable () -{ - return &g_FuncTable; -} - -const char* QERPlug_Init (void* hApp, void *pWidget) -{ - return "HydraToolz for GTKRadiant"; // do we need this ? hmmm -} - -const char* QERPlug_GetName() -{ - return (char*)PLUGIN_NAME; -} - -const char* QERPlug_GetCommandList() -{ - return PLUGIN_COMMANDS; -} - -extern "C" void QERPlug_Dispatch(const char* p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) -{ - if(!strcmp(p, "Create/Update WAD keypair")) - UpdateWadKeyPair(); - else if(!strcmp(p, "About...")) - g_FuncTable.m_pfnMessageBox(NULL, PLUGIN_ABOUT, "About", MB_OK, NULL); -} - -// ============================================================================= -// SYNAPSE - -CSynapseServer* g_pSynapseServer = NULL; -CSynapseClientHydraToolz 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(PLUGIN_MAJOR, "HydraToolz", sizeof(_QERPluginTable)); - g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable); - g_SynapseClient.AddAPI(VFS_MAJOR, "wad", sizeof(g_FileSystemTable), SYN_REQUIRE, &g_FileSystemTable); - g_SynapseClient.AddAPI(ENTITY_MAJOR, NULL, sizeof(g_EntityTable), SYN_REQUIRE, &g_EntityTable); - return &g_SynapseClient; -} - -bool CSynapseClientHydraToolz::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; - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -const char* CSynapseClientHydraToolz::GetInfo() -{ - return "HydraToolz plugin built " __DATE__ " " RADIANT_VERSION; -} +/* +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 +*/ + +#include "plugin.h" +#include "version.h" + +/*! \file plugin.cpp + \brief HydraToolz! + + HydraToolz by Dominic Clifton - Hydra (Hydra@Hydras-World.com) + + Overview + ======== + + This plugin allows the user to rebuild the "wad" key pair in the worldspawn + so that it has a list of all the .wad files in use. + + Version History + =============== + + v0.1 - 28/May/2002 + - Initial version. + + v1.0 - 10/March/2003 + - Added more console output + - Removed some old test code + - Tweaked dialog box. + - Fixed up for Radiant 1.3.5 + + + ToDo + ==== + + Nothing... + +*/ + +// ============================================================================= +// Globals + +_QERFuncTable_1 g_FuncTable; +_QERFileSystemTable g_FileSystemTable; +_QEREntityTable g_EntityTable; + + +// ============================================================================= +// Ripped from cmdlib.cpp + +/* +==================== +Extract file parts +==================== +*/ +void ExtractFilePath (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' && *(src-1) != '\\') + src--; + + memcpy (dest, path, src-path); + dest[src-path] = 0; +} + +void ExtractFileName (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' + && *(src-1) != '\\' ) + src--; + + while (*src) + { + *dest++ = *src++; + } + *dest = 0; +} + +void ConvertDOSToUnixName( char *dst, const char *src ) +{ + while ( *src ) + { + if ( *src == '\\' ) + *dst = '/'; + else + *dst = *src; + dst++; src++; + } + *dst = 0; +} + +// End of rip from cmdlib.cpp + +// ============================================================================= +// Actual Plugin Code + +// get the wad name from the shader name (or an actual wadname) and add to a list of wad names making +// sure we don't add duplicates. + +GSList *AddToWadList(GSList *wadlist, const char *shadername, const char *wad) +{ + char tmpstr[QER_MAX_NAMELEN]; + char *wadname; + if (!shadername && !wad) return wadlist; + + if (shadername) + { + if (strcmp(shadername,"color") == 0) + return wadlist; + ExtractFilePath(shadername,tmpstr); + // Sys_Printf("checking: %s\n",shadername); + + int l = strlen(tmpstr) - 1; + + if (tmpstr[l] == '/' || tmpstr[l] == '\\') + tmpstr[l] = 0; + else + { + Sys_Printf("HydraToolz: WARNING: Unknown wad file for shader %s\n",shadername); + return wadlist; + } + + ExtractFileName(tmpstr,tmpstr); + + wadname = (char *)malloc(strlen(tmpstr) + 5); + sprintf(wadname,"%s.wad",tmpstr); + } + else + { + wadname=strdup(wad); + } + + for (GSList *l = wadlist; l != NULL ; l = l->next) + { + if (!stricmp((char *)l->data,wadname)) + { + free( wadname ); + return wadlist; + } + } + + Sys_Printf("HydraToolz: Adding Wad File to WAD list: %s (reason: ",wadname); + if (shadername) + Sys_Printf("see shader \"%s\")\n", shadername); + else + Sys_Printf("already in WAD key. )\n"); + return ( g_slist_append (wadlist, wadname ) ); +} + +void UpdateWadKeyPair( void ) +{ + int i,nb; + + char wads[2048]; // change to CString usage ? + *wads = 0; + char *p1,*p2; + entity_t *pEntity; + epair_t *pEpair; + GSList *wadlist = NULL; + face_t *f; + brush_t *b; + char cleanwadname[QER_MAX_NAMELEN]; + char *actualwad; + + + pEntity = (entity_t *)g_FuncTable.m_pfnGetEntityHandle(0); // get the worldspawn ent + + Sys_Printf("HydraToolz: Searching for in-use wad files...\n"); + for(pEpair = pEntity->epairs; pEpair != NULL; pEpair = pEpair->next) + { + if (stricmp(pEpair->key,"wad") == 0) + { + strcpy(wads,pEpair->value); + ConvertDOSToUnixName(wads,wads); + + Sys_Printf("HydraToolz: Current wad key is \"%s\"!\n",wads); + + // ok, we got the list of ; delimited wads, now split it into a GSList that contains + // just the wad names themselves. + + p1 = wads; + + do + { + p2 = strchr(p1,';'); + if (p2) + *p2 = 0; // swap the ; with a null terminator + + if (strchr(p1,'/') || strchr(p1,'\\')) + { + ExtractFileName(p1,cleanwadname); + wadlist = AddToWadList (wadlist, NULL, cleanwadname); + } + else + { + wadlist = AddToWadList (wadlist, NULL, p1); + } + if (p2) + p1 = p2+1; // point back to the remainder of the string + else + p1 = NULL; // make it so we exit the loop. + + } while (p1); + + // ok, now we have a list of wads in GSList. + // now we need to add any new wadfiles (with their paths) to this list + // so scan all brushes and see what wads are in use + // FIXME: scan brushes only in the region ? + + break; // we don't need to process any more key/pairs. + } + } + + if (!*wads) + Sys_Printf("HydraToolz: No \"wad\" keypair wound in worldspawn\n"); + + + nb = g_FuncTable.m_pfnAllocateActiveBrushHandles(); + for( i = 0; i < nb; i++ ) + { + b = (brush_t *)g_FuncTable.m_pfnGetActiveBrushHandle(i); + if (b->patchBrush) // patches in halflife ? + { + wadlist = AddToWadList(wadlist, b->pPatch->pShader->getName(),NULL); + } else + { + for (f=b->brush_faces ; f ; f=f->next) + { + wadlist = AddToWadList(wadlist, f->pShader->getName(),NULL); + } + } + } + g_FuncTable.m_pfnReleaseActiveBrushHandles(); + + nb = g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + for( i = 0; i < nb; i++ ) + { + b = (brush_t *)g_FuncTable.m_pfnGetSelectedBrushHandle(i); + if (b->patchBrush) // patches in halflife ? + { + wadlist = AddToWadList(wadlist, b->pPatch->pShader->getName(),NULL); + } else + { + for (f=b->brush_faces ; f ; f=f->next) + { + wadlist = AddToWadList(wadlist, f->pShader->getName(),NULL); + } + } + } + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); + + Sys_Printf("HydraToolz: Rebuilding worldspawn's \"wad\" key-pair...\n"); + // Now we have a complete list of wadnames (without paths) so we just have to turn this + // back to a ; delimited list. + + *wads = 0; + while (wadlist) + { + // skip wad files if they start with "common-" + if (strnicmp((char *)wadlist->data,"common-",7) == 0) + { + Sys_Printf("HydraToolz: Skipping radiant/user-supplied wad file %s\n",(char *)wadlist->data); + } + else + { + if (wads[0]) + strcat(wads,";"); + + actualwad = vfsGetFullPath((char *)wadlist->data); + + if (actualwad) + { + strcat(wads, actualwad); + } + else + { + Sys_Printf("HydraToolz: WARNING: could not locate wad file %s\n",(char *)wadlist->data); + strcat(wads, (char *)wadlist->data); + } + } + + free (wadlist->data); + wadlist = g_slist_remove (wadlist, wadlist->data); + } + + // store the wad list back in the worldspawn. + if (*wads) + { + //free(pEpair->value); + //pEpair->value = strdup(wads); + SetKeyValue(pEntity, "wad", wads); + Sys_Printf("HydraToolz: Setting worldspawn \"wad\" key value to \"%s\"\n",wads); + + } + + Sys_Printf("HydraToolz: Finished rebuilding wad keypair!\n"); + +} + +// ============================================================================= +// PLUGIN INTERFACE STUFF + +// plugin name +const char *PLUGIN_NAME = "HydraToolz"; + +// commands in the menu +const char *PLUGIN_COMMANDS = "About...;Create/Update WAD keypair"; + +const char *PLUGIN_ABOUT = "HydraToolz v1.0 for GTKRadiant\n\n" + "By Hydra!"; + +extern "C" void* WINAPI QERPlug_GetFuncTable () +{ + return &g_FuncTable; +} + +const char* QERPlug_Init (void* hApp, void *pWidget) +{ + return "HydraToolz for GTKRadiant"; // do we need this ? hmmm +} + +const char* QERPlug_GetName() +{ + return (char*)PLUGIN_NAME; +} + +const char* QERPlug_GetCommandList() +{ + return PLUGIN_COMMANDS; +} + +extern "C" void QERPlug_Dispatch(const char* p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) +{ + if(!strcmp(p, "Create/Update WAD keypair")) + UpdateWadKeyPair(); + else if(!strcmp(p, "About...")) + g_FuncTable.m_pfnMessageBox(NULL, PLUGIN_ABOUT, "About", MB_OK, NULL); +} + +// ============================================================================= +// SYNAPSE + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientHydraToolz 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(PLUGIN_MAJOR, "HydraToolz", sizeof(_QERPluginTable)); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(VFS_MAJOR, "wad", sizeof(g_FileSystemTable), SYN_REQUIRE, &g_FileSystemTable); + g_SynapseClient.AddAPI(ENTITY_MAJOR, NULL, sizeof(g_EntityTable), SYN_REQUIRE, &g_EntityTable); + return &g_SynapseClient; +} + +bool CSynapseClientHydraToolz::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; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +const char* CSynapseClientHydraToolz::GetInfo() +{ + return "HydraToolz plugin built " __DATE__ " " RADIANT_VERSION; +} diff --git a/contrib/prtview/AboutDialog.cpp b/contrib/prtview/AboutDialog.cpp index b82a7a49..3bb3a33a 100644 --- a/contrib/prtview/AboutDialog.cpp +++ b/contrib/prtview/AboutDialog.cpp @@ -1,139 +1,139 @@ -/* -PrtView plugin for GtkRadiant -Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com - -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 -*/ - -// AboutDialog.cpp : implementation file -// - -#include "stdafx.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -//static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CAboutDialog dialog - -#ifdef GTK_PLUGIN - -static void dialog_button_callback (GtkWidget *widget, gpointer data) -{ - GtkWidget *parent; - int *loop, *ret; - - parent = gtk_widget_get_toplevel (widget); - loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); - ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); - - *loop = 0; - *ret = (int)data; -} - -static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) -{ - int *loop; - - gtk_widget_hide (widget); - loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); - *loop = 0; - - return TRUE; -} - -void DoAboutDlg () -{ - GtkWidget *dlg, *hbox, *vbox, *button, *label; - int loop = 1, ret = IDCANCEL; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "About Portal Viewer"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - hbox = gtk_hbox_new (FALSE, 10); - gtk_widget_show (hbox); - gtk_container_add (GTK_CONTAINER (dlg), hbox); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 10); - - label = gtk_label_new ("Version 1.000\n\n" - "Gtk port by Leonardo Zide\nleo@lokigames.com\n\n" - "Written by Geoffrey DeWan\ngdewan@prairienet.org\n\n" - "Built against GtkRadiant " RADIANT_VERSION "\n" - __DATE__ - ); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - - vbox = gtk_vbox_new (FALSE, 0); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); -} - -#else // GTK_PLUGIN - -CAboutDialog::CAboutDialog(CWnd* pParent /*=NULL*/) - : CDialog(CAboutDialog::IDD, pParent) -{ - //{{AFX_DATA_INIT(CAboutDialog) - // NOTE: the ClassWizard will add member initialization here - //}}AFX_DATA_INIT -} - - -void CAboutDialog::DoDataExchange(CDataExchange* pDX) -{ - CDialog::DoDataExchange(pDX); - //{{AFX_DATA_MAP(CAboutDialog) - // NOTE: the ClassWizard will add DDX and DDV calls here - //}}AFX_DATA_MAP -} - - -BEGIN_MESSAGE_MAP(CAboutDialog, CDialog) - //{{AFX_MSG_MAP(CAboutDialog) - // NOTE: the ClassWizard will add message map macros here - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - -#endif // GTK_PLUGIN - -///////////////////////////////////////////////////////////////////////////// -// CAboutDialog message handlers +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +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 +*/ + +// AboutDialog.cpp : implementation file +// + +#include "stdafx.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +//static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CAboutDialog dialog + +#ifdef GTK_PLUGIN + +static void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} + +void DoAboutDlg () +{ + GtkWidget *dlg, *hbox, *vbox, *button, *label; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "About Portal Viewer"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 10); + + label = gtk_label_new ("Version 1.000\n\n" + "Gtk port by Leonardo Zide\nleo@lokigames.com\n\n" + "Written by Geoffrey DeWan\ngdewan@prairienet.org\n\n" + "Built against GtkRadiant " RADIANT_VERSION "\n" + __DATE__ + ); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + vbox = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +#else // GTK_PLUGIN + +CAboutDialog::CAboutDialog(CWnd* pParent /*=NULL*/) + : CDialog(CAboutDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CAboutDialog) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT +} + + +void CAboutDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAboutDialog) + // NOTE: the ClassWizard will add DDX and DDV calls here + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CAboutDialog, CDialog) + //{{AFX_MSG_MAP(CAboutDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +#endif // GTK_PLUGIN + +///////////////////////////////////////////////////////////////////////////// +// CAboutDialog message handlers diff --git a/contrib/prtview/ConfigDialog.cpp b/contrib/prtview/ConfigDialog.cpp index ced949bb..3f0b272c 100644 --- a/contrib/prtview/ConfigDialog.cpp +++ b/contrib/prtview/ConfigDialog.cpp @@ -1,925 +1,925 @@ -/* -PrtView plugin for GtkRadiant -Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com - -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 -*/ - -// ConfigDialog.cpp : implementation file -// - -#include "stdafx.h" -#include - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -//static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CConfigDialog dialog - -#ifdef GTK_PLUGIN - -static void dialog_button_callback (GtkWidget *widget, gpointer data) -{ - GtkWidget *parent; - int *loop, *ret; - - parent = gtk_widget_get_toplevel (widget); - loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); - ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); - - *loop = 0; - *ret = (int)data; -} - -static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) -{ - int *loop; - - gtk_widget_hide (widget); - loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); - *loop = 0; - - return TRUE; -} - -// ============================================================================= -// Color selection dialog - -static int DoColor (COLORREF *c) -{ - GtkWidget* dlg; - double clr[3]; - int loop = 1, ret = IDCANCEL; - - clr[0] = ((double)GetRValue (*c)) / 255.0; - clr[1] = ((double)GetGValue (*c)) / 255.0; - clr[2] = ((double)GetBValue (*c)) / 255.0; - - dlg = gtk_color_selection_dialog_new ("Choose Color"); - gtk_color_selection_set_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), clr); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->ok_button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->cancel_button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - gtk_widget_show(dlg); - gtk_grab_add(dlg); - - while (loop) - gtk_main_iteration (); - - gtk_color_selection_get_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), clr); - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); - - if (ret == IDOK) - { - *c = RGB (clr[0]*255, clr[1]*255, clr[2]*255); - } - - return ret; -} - -static void Set2DText (GtkWidget* label) -{ - char s[40]; - - sprintf(s, "Line Width = %6.3f", portals.width_2d * 0.5f); - - gtk_label_set_text (GTK_LABEL (label), s); -} - -static void Set3DText (GtkWidget* label) -{ - char s[40]; - - sprintf(s, "Line Width = %6.3f", portals.width_3d * 0.5f); - - gtk_label_set_text (GTK_LABEL (label), s); -} - -static void Set3DTransText (GtkWidget* label) -{ - char s[40]; - - sprintf(s, "Polygon transparency = %d%%", (int)portals.trans_3d); - - gtk_label_set_text (GTK_LABEL (label), s); -} - -static void SetClipText (GtkWidget* label) -{ - char s[40]; - - sprintf(s, "Cubic clip range = %d", (int)portals.clip_range * 64); - - gtk_label_set_text (GTK_LABEL (label), s); -} - -static void OnScroll2d (GtkAdjustment *adj, gpointer data) -{ - portals.width_2d = adj->value; - Set2DText (GTK_WIDGET (data)); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); -} - -static void OnScroll3d (GtkAdjustment *adj, gpointer data) -{ - portals.width_3d = adj->value; - Set3DText (GTK_WIDGET (data)); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -static void OnScrollTrans (GtkAdjustment *adj, gpointer data) -{ - portals.trans_3d = adj->value; - Set3DTransText (GTK_WIDGET (data)); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -static void OnScrollClip (GtkAdjustment *adj, gpointer data) -{ - portals.clip_range = adj->value; - SetClipText (GTK_WIDGET (data)); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -static void OnAntiAlias2d (GtkWidget *widget, gpointer data) -{ - portals.aa_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); -} - -static void OnConfig2d (GtkWidget *widget, gpointer data) -{ - portals.show_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); -} - -static void OnColor2d (GtkWidget *widget, gpointer data) -{ - if (DoColor (&portals.color_2d) == IDOK) - { - portals.FixColors(); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); - } -} - -static void OnConfig3d (GtkWidget *widget, gpointer data) -{ - portals.show_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - - -static void OnAntiAlias3d (GtkWidget *widget, gpointer data) -{ - portals.aa_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -static void OnColor3d (GtkWidget *widget, gpointer data) -{ - if (DoColor (&portals.color_3d) == IDOK) - { - portals.FixColors(); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); - } -} - -static void OnColorFog (GtkWidget *widget, gpointer data) -{ - if (DoColor (&portals.color_fog) == IDOK) - { - portals.FixColors(); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); - } -} - -static void OnFog (GtkWidget *widget, gpointer data) -{ - portals.fog = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -static void OnSelchangeZbuffer (GtkWidget *widget, gpointer data) -{ - portals.zbuffer = GPOINTER_TO_INT (data); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -static void OnPoly (GtkWidget *widget, gpointer data) -{ - portals.polygons = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -static void OnLines (GtkWidget *widget, gpointer data) -{ - portals.lines = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -static void OnClip (GtkWidget *widget, gpointer data) -{ - portals.clip = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -void DoConfigDialog () -{ - GtkWidget *dlg, *hbox, *vbox, *vbox2, *button, *table, *frame; - GtkWidget *lw3slider, *lw3label, *lw2slider, *lw2label, *zlist, *menu, *item; - GtkWidget *aa2check, *aa3check, *depthcheck, *linescheck, *polyscheck; - GtkWidget *transslider, *translabel, *clipslider, *cliplabel; - GtkWidget *show2check, *show3check, *portalcheck; - int loop = 1, ret = IDCANCEL; - GtkObject *adj; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "Portal Viewer Configuration"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_container_add (GTK_CONTAINER (dlg), vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - - frame = gtk_frame_new ("3D View"); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); - - vbox2 = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox2); - gtk_container_add (GTK_CONTAINER (frame), vbox2); - gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, TRUE, 0); - - adj = gtk_adjustment_new (portals.width_3d, 2, 40, 1, 1, 1); - lw3slider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); - gtk_widget_show (lw3slider); - gtk_box_pack_start (GTK_BOX (hbox), lw3slider, TRUE, TRUE, 0); - gtk_scale_set_draw_value (GTK_SCALE (lw3slider), FALSE); - - lw3label = gtk_label_new (""); - gtk_widget_show (lw3label); - gtk_box_pack_start (GTK_BOX (hbox), lw3label, FALSE, TRUE, 0); - gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScroll3d), lw3label); - - table = gtk_table_new (2, 4, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - button = gtk_button_new_with_label ("Color"); - gtk_widget_show (button); - gtk_table_attach (GTK_TABLE (table), button, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColor3d), NULL); - - button = gtk_button_new_with_label ("Depth Color"); - gtk_widget_show (button); - gtk_table_attach (GTK_TABLE (table), button, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColorFog), NULL); - - aa3check = gtk_check_button_new_with_label ("Anti-Alias (May not work on some video cards)"); - gtk_widget_show (aa3check); - gtk_table_attach (GTK_TABLE (table), aa3check, 1, 4, 0, 1, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_signal_connect (GTK_OBJECT (aa3check), "toggled", GTK_SIGNAL_FUNC (OnAntiAlias3d), NULL); - - depthcheck = gtk_check_button_new_with_label ("Depth Cue"); - gtk_widget_show (depthcheck); - gtk_table_attach (GTK_TABLE (table), depthcheck, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_signal_connect (GTK_OBJECT (depthcheck), "toggled", GTK_SIGNAL_FUNC (OnFog), NULL); - - linescheck = gtk_check_button_new_with_label ("Lines"); - gtk_widget_show (linescheck); - gtk_table_attach (GTK_TABLE (table), linescheck, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_signal_connect (GTK_OBJECT (linescheck), "toggled", GTK_SIGNAL_FUNC (OnLines), NULL); - - polyscheck = gtk_check_button_new_with_label ("Polygons"); - gtk_widget_show (polyscheck); - gtk_table_attach (GTK_TABLE (table), polyscheck, 3, 4, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_signal_connect (GTK_OBJECT (polyscheck), "toggled", GTK_SIGNAL_FUNC (OnPoly), NULL); - - zlist = gtk_option_menu_new (); - gtk_widget_show (zlist); - gtk_box_pack_start (GTK_BOX (vbox2), zlist, TRUE, FALSE, 0); - - menu = gtk_menu_new (); - gtk_widget_show (menu); - gtk_option_menu_set_menu (GTK_OPTION_MENU (zlist), menu); - - item = gtk_menu_item_new_with_label ("Z-Buffer Test and Write (recommended for solid or no polygons)"); - gtk_widget_show (item); - gtk_signal_connect (GTK_OBJECT (item), "activate", - GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (0)); - gtk_menu_append (GTK_MENU (menu), item); - - item = gtk_menu_item_new_with_label ("Z-Buffer Test Only (recommended for transparent polygons)"); - gtk_widget_show (item); - gtk_signal_connect (GTK_OBJECT (item), "activate", - GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (1)); - gtk_menu_append (GTK_MENU (menu), item); - - item = gtk_menu_item_new_with_label ("Z-Buffer Off"); - gtk_widget_show (item); - gtk_signal_connect (GTK_OBJECT (item), "activate", - GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (2)); - gtk_menu_append (GTK_MENU (menu), item); - - table = gtk_table_new (2, 2, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - adj = gtk_adjustment_new (portals.trans_3d, 0, 100, 1, 1, 1); - transslider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); - gtk_widget_show (transslider); - gtk_table_attach (GTK_TABLE (table), transslider, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_scale_set_draw_value (GTK_SCALE (transslider), FALSE); - - translabel = gtk_label_new (""); - gtk_widget_show (translabel); - gtk_table_attach (GTK_TABLE (table), translabel, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (translabel), 0.0, 0.0); - gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScrollTrans), translabel); - - adj = gtk_adjustment_new (portals.clip_range, 1, 128, 1, 1, 1); - clipslider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); - gtk_widget_show (clipslider); - gtk_table_attach (GTK_TABLE (table), clipslider, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_scale_set_draw_value (GTK_SCALE (clipslider), FALSE); - - cliplabel = gtk_label_new (""); - gtk_widget_show (cliplabel); - gtk_table_attach (GTK_TABLE (table), cliplabel, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (cliplabel), 0.0, 0.0); - gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScrollClip), cliplabel); - - hbox = gtk_hbox_new (TRUE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); - - show3check = gtk_check_button_new_with_label ("Show"); - gtk_widget_show (show3check); - gtk_box_pack_start (GTK_BOX (hbox), show3check, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (show3check), "toggled", GTK_SIGNAL_FUNC (OnConfig3d), NULL); - - portalcheck = gtk_check_button_new_with_label ("Portal cubic clipper"); - gtk_widget_show (portalcheck); - gtk_box_pack_start (GTK_BOX (hbox), portalcheck, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (portalcheck), "toggled", GTK_SIGNAL_FUNC (OnClip), NULL); - - frame = gtk_frame_new ("2D View"); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); - - vbox2 = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox2); - gtk_container_add (GTK_CONTAINER (frame), vbox2); - gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); - - adj = gtk_adjustment_new (portals.width_2d, 2, 40, 1, 1, 1); - lw2slider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); - gtk_widget_show (lw2slider); - gtk_box_pack_start (GTK_BOX (hbox), lw2slider, TRUE, TRUE, 0); - gtk_scale_set_draw_value (GTK_SCALE (lw2slider), FALSE); - - lw2label = gtk_label_new (""); - gtk_widget_show (lw2label); - gtk_box_pack_start (GTK_BOX (hbox), lw2label, FALSE, TRUE, 0); - gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScroll2d), lw2label); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); - - button = gtk_button_new_with_label ("Color"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColor2d), NULL); - gtk_widget_set_usize (button, 60, -2); - - aa2check = gtk_check_button_new_with_label ("Anti-Alias (May not work on some video cards)"); - gtk_widget_show (aa2check); - gtk_box_pack_start (GTK_BOX (hbox), aa2check, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (aa2check), "toggled", GTK_SIGNAL_FUNC (OnAntiAlias2d), NULL); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); - - show2check = gtk_check_button_new_with_label ("Show"); - gtk_widget_show (show2check); - gtk_box_pack_start (GTK_BOX (hbox), show2check, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (show2check), "toggled", GTK_SIGNAL_FUNC (OnConfig2d), NULL); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - // initialize dialog - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (show2check), portals.show_2d); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aa2check), portals.aa_2d); - Set2DText (lw2label); - - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (show3check), portals.show_3d); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (depthcheck), portals.fog); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (polyscheck), portals.polygons); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (linescheck), portals.lines); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aa3check), portals.aa_3d); - gtk_option_menu_set_history (GTK_OPTION_MENU (zlist), portals.zbuffer); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (portalcheck), portals.clip); - - Set3DText (lw3label); - Set3DTransText (translabel); - SetClipText (cliplabel); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); -} - -#else // GTK_PLUGIN - -CConfigDialog::CConfigDialog(CWnd* pParent /*=NULL*/) - : CDialog(CConfigDialog::IDD, pParent) -{ - //{{AFX_DATA_INIT(CConfigDialog) - //}}AFX_DATA_INIT -} - - -void CConfigDialog::DoDataExchange(CDataExchange* pDX) -{ - CDialog::DoDataExchange(pDX); - //{{AFX_DATA_MAP(CConfigDialog) - DDX_Control(pDX, IDC_CLIP, m_clip_ctrl); - DDX_Control(pDX, IDC_CUBIC, m_cubic_ctrl); - DDX_Control(pDX, IDC_SCROLL_CUBIC, m_scroll_cubic_ctrl); - DDX_Control(pDX, IDC_LINES, m_line_ctrl); - DDX_Control(pDX, IDC_SCROLL_3D_TRANS, m_scroll_3d_trans_ctrl); - DDX_Control(pDX, IDC_3D_TRANS, m_3d_trans_ctrl); - DDX_Control(pDX, IDC_POLY, m_poly_ctrl); - DDX_Control(pDX, IDC_FOG, m_fog_ctrl); - DDX_Control(pDX, IDC_ZBUFFER, m_z_ctrl); - DDX_Control(pDX, IDC_SCROLL_3D_WIDTH, m_scroll_3d_width_ctrl); - DDX_Control(pDX, IDC_ANTI_ALIAS_3D, m_aa_3d_ctrl); - DDX_Control(pDX, IDC_3D_WIDTH, m_3d_width_ctrl); - DDX_Control(pDX, IDC_ANTI_ALIAS_2D, m_aa_2d_ctrl); - DDX_Control(pDX, IDC_SCROLL_2D_WIDTH, m_scroll_2d_width_ctrl); - DDX_Control(pDX, IDC_2D_WIDTH, m_2d_width_ctrl); - DDX_Control(pDX, IDC_CONFIG_3D, m_3d_ctrl); - DDX_Control(pDX, IDC_CONFIG_2D, m_2d_ctrl); - //}}AFX_DATA_MAP -} - - -BEGIN_MESSAGE_MAP(CConfigDialog, CDialog) - //{{AFX_MSG_MAP(CConfigDialog) - ON_WM_HSCROLL() - ON_BN_CLICKED(IDC_ANTI_ALIAS_2D, OnAntiAlias2d) - ON_BN_CLICKED(IDC_CONFIG_2D, OnConfig2d) - ON_BN_CLICKED(IDC_CONFIG_3D, OnConfig3d) - ON_BN_CLICKED(IDC_COLOR_2D, OnColor2d) - ON_BN_CLICKED(IDC_ANTI_ALIAS_3D, OnAntiAlias3d) - ON_BN_CLICKED(IDC_COLOR_3D, OnColor3d) - ON_BN_CLICKED(IDC_COLOR_FOG, OnColorFog) - ON_BN_CLICKED(IDC_FOG, OnFog) - ON_CBN_SELCHANGE(IDC_ZBUFFER, OnSelchangeZbuffer) - ON_BN_CLICKED(IDC_POLY, OnPoly) - ON_BN_CLICKED(IDC_LINES, OnLines) - ON_BN_CLICKED(IDC_CLIP, OnClip) - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CConfigDialog message handlers - -void CConfigDialog::Set2DText() -{ - char s[40]; - - sprintf(s, "Line Width = %6.3f", portals.width_2d * 0.5f); - - m_2d_width_ctrl.SetWindowText(s); -} - -void CConfigDialog::Set3DText() -{ - char s[40]; - - sprintf(s, "Line Width = %6.3f", portals.width_3d * 0.5f); - - m_3d_width_ctrl.SetWindowText(s); -} - -void CConfigDialog::Set3DTransText() -{ - char s[40]; - - sprintf(s, "Polygon transparency = %d%%", (int)portals.trans_3d); - - m_3d_trans_ctrl.SetWindowText(s); -} - -void CConfigDialog::SetClipText() -{ - char s[40]; - - sprintf(s, "Cubic clip range = %d", (int)portals.clip_range * 64); - - m_cubic_ctrl.SetWindowText(s); -} - -qboolean CConfigDialog::OnInitDialog() -{ - CDialog::OnInitDialog(); - - m_2d_ctrl.SetCheck(portals.show_2d); - m_aa_2d_ctrl.SetCheck(portals.aa_2d); - Set2DText(); - - m_scroll_2d_width_ctrl.SetScrollRange(2, 40, FALSE); - m_scroll_2d_width_ctrl.SetScrollPos((int)portals.width_2d, TRUE); - - m_3d_ctrl.SetCheck(portals.show_3d); - m_fog_ctrl.SetCheck(portals.fog); - m_poly_ctrl.SetCheck(portals.polygons); - m_line_ctrl.SetCheck(portals.lines); - m_aa_3d_ctrl.SetCheck(portals.aa_3d); - m_z_ctrl.SetCurSel(portals.zbuffer); - m_clip_ctrl.SetCheck(portals.clip); - - Set3DText(); - Set3DTransText(); - SetClipText(); - - m_scroll_3d_width_ctrl.SetScrollRange(2, 40, FALSE); - m_scroll_3d_width_ctrl.SetScrollPos((int)portals.width_3d, TRUE); - m_scroll_3d_trans_ctrl.SetScrollRange(0, 100, FALSE); - m_scroll_3d_trans_ctrl.SetScrollPos((int)portals.trans_3d, TRUE); - m_scroll_cubic_ctrl.SetScrollRange(1, 128, FALSE); - m_scroll_cubic_ctrl.SetScrollPos((int)portals.clip_range, TRUE); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -void CConfigDialog::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) -{ - float *adj; - float scr_min, scr_max, scr_big; - - if(nSBCode == SB_THUMBPOSITION) - { - CDialog::OnHScroll(nSBCode, nPos, pScrollBar); - return; - } - - if(pScrollBar == &m_scroll_2d_width_ctrl) - { - scr_min = 2.0f; - scr_max = 40.0f; - scr_big = 4.0f; - - adj = &portals.width_2d; - } - else if(pScrollBar == &m_scroll_3d_width_ctrl) - { - scr_min = 2.0f; - scr_max = 40.0f; - scr_big = 4.0f; - - adj = &portals.width_3d; - } - else if(pScrollBar == &m_scroll_3d_trans_ctrl) - { - scr_min = 0.0f; - scr_max = 100.0f; - scr_big = 10.0f; - - adj = &portals.trans_3d; - } - else if(pScrollBar == &m_scroll_cubic_ctrl) - { - scr_min = 1.0f; - scr_max = 128.0f; - scr_big = 8.0f; - - adj = &portals.clip_range; - } - else - { - CDialog::OnHScroll(nSBCode, nPos, pScrollBar); - return; - } - - switch(nSBCode) - { - case SB_LEFT: - *adj = scr_min; - pScrollBar->SetScrollPos((int)scr_min, TRUE); - break; - case SB_RIGHT: - *adj = scr_max; - pScrollBar->SetScrollPos((int)scr_max, TRUE); - break; - case SB_LINELEFT: - *adj -= 1.0f; - - if(*adj < scr_min) - *adj = scr_min; - - pScrollBar->SetScrollPos((int)(*adj), TRUE); - - break; - case SB_LINERIGHT: - *adj += 1.0f; - - if(*adj > scr_max) - *adj = scr_max; - - pScrollBar->SetScrollPos((int)(*adj), TRUE); - - break; - case SB_PAGELEFT: - *adj -= scr_big; - - if(*adj < scr_min) - *adj = scr_min; - - pScrollBar->SetScrollPos((int)(*adj), TRUE); - - break; - case SB_PAGERIGHT: - *adj += scr_big; - - if(*adj > scr_max) - *adj = scr_max; - - pScrollBar->SetScrollPos((int)(*adj), TRUE); - - break; - case SB_THUMBTRACK: - *adj = (float)nPos; - - break; - case SB_ENDSCROLL: - pScrollBar->SetScrollPos((int)(*adj), TRUE); - - break; - default: - CDialog::OnHScroll(nSBCode, nPos, pScrollBar); - } - - if(pScrollBar == &m_scroll_2d_width_ctrl) - { - Set2DText(); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); - } - else if(pScrollBar == &m_scroll_3d_width_ctrl) - { - Set3DText(); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); - } - else if(pScrollBar == &m_scroll_3d_trans_ctrl) - { - Set3DTransText(); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); - } - else if(pScrollBar == &m_scroll_cubic_ctrl) - { - SetClipText(); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); - } -} - -void CConfigDialog::OnAntiAlias2d() -{ - portals.aa_2d = m_aa_2d_ctrl.GetCheck(); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); -} - -void CConfigDialog::OnConfig2d() -{ - portals.show_2d = m_2d_ctrl.GetCheck(); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); -} - -void CConfigDialog::OnColor2d() -{ - CColorDialog dlg(portals.color_2d, CC_ANYCOLOR, this); - - if(dlg.DoModal() == IDOK) - { - portals.color_2d = dlg.GetColor(); - - portals.FixColors(); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); - } -} - -void CConfigDialog::OnConfig3d() -{ - portals.show_3d = m_3d_ctrl.GetCheck(); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - - -void CConfigDialog::OnAntiAlias3d() -{ - portals.aa_3d = m_aa_3d_ctrl.GetCheck(); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -void CConfigDialog::OnColor3d() -{ - CColorDialog dlg(portals.color_3d, CC_ANYCOLOR, this); - - if(dlg.DoModal() == IDOK) - { - portals.color_3d = dlg.GetColor(); - - portals.FixColors(); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); - } -} - -void CConfigDialog::OnColorFog() -{ - CColorDialog dlg(portals.color_fog, CC_ANYCOLOR, this); - - if(dlg.DoModal() == IDOK) - { - portals.color_fog = dlg.GetColor(); - - portals.FixColors(); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); - } -} - -void CConfigDialog::OnFog() -{ - portals.fog = m_fog_ctrl.GetCheck(); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -void CConfigDialog::OnSelchangeZbuffer() -{ - portals.zbuffer = m_z_ctrl.GetCurSel(); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -void CConfigDialog::OnPoly() -{ - portals.polygons = m_poly_ctrl.GetCheck(); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -void CConfigDialog::OnLines() -{ - portals.lines = m_line_ctrl.GetCheck(); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -void CConfigDialog::OnClip() -{ - portals.clip = m_clip_ctrl.GetCheck(); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -#endif // GTK_PLUGIN +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +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 +*/ + +// ConfigDialog.cpp : implementation file +// + +#include "stdafx.h" +#include + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +//static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CConfigDialog dialog + +#ifdef GTK_PLUGIN + +static void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} + +// ============================================================================= +// Color selection dialog + +static int DoColor (COLORREF *c) +{ + GtkWidget* dlg; + double clr[3]; + int loop = 1, ret = IDCANCEL; + + clr[0] = ((double)GetRValue (*c)) / 255.0; + clr[1] = ((double)GetGValue (*c)) / 255.0; + clr[2] = ((double)GetBValue (*c)) / 255.0; + + dlg = gtk_color_selection_dialog_new ("Choose Color"); + gtk_color_selection_set_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), clr); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->ok_button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->cancel_button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + gtk_widget_show(dlg); + gtk_grab_add(dlg); + + while (loop) + gtk_main_iteration (); + + gtk_color_selection_get_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), clr); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + if (ret == IDOK) + { + *c = RGB (clr[0]*255, clr[1]*255, clr[2]*255); + } + + return ret; +} + +static void Set2DText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Line Width = %6.3f", portals.width_2d * 0.5f); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void Set3DText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Line Width = %6.3f", portals.width_3d * 0.5f); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void Set3DTransText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Polygon transparency = %d%%", (int)portals.trans_3d); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void SetClipText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Cubic clip range = %d", (int)portals.clip_range * 64); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void OnScroll2d (GtkAdjustment *adj, gpointer data) +{ + portals.width_2d = adj->value; + Set2DText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +static void OnScroll3d (GtkAdjustment *adj, gpointer data) +{ + portals.width_3d = adj->value; + Set3DText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnScrollTrans (GtkAdjustment *adj, gpointer data) +{ + portals.trans_3d = adj->value; + Set3DTransText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnScrollClip (GtkAdjustment *adj, gpointer data) +{ + portals.clip_range = adj->value; + SetClipText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnAntiAlias2d (GtkWidget *widget, gpointer data) +{ + portals.aa_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +static void OnConfig2d (GtkWidget *widget, gpointer data) +{ + portals.show_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +static void OnColor2d (GtkWidget *widget, gpointer data) +{ + if (DoColor (&portals.color_2d) == IDOK) + { + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); + } +} + +static void OnConfig3d (GtkWidget *widget, gpointer data) +{ + portals.show_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + + +static void OnAntiAlias3d (GtkWidget *widget, gpointer data) +{ + portals.aa_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnColor3d (GtkWidget *widget, gpointer data) +{ + if (DoColor (&portals.color_3d) == IDOK) + { + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } +} + +static void OnColorFog (GtkWidget *widget, gpointer data) +{ + if (DoColor (&portals.color_fog) == IDOK) + { + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } +} + +static void OnFog (GtkWidget *widget, gpointer data) +{ + portals.fog = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnSelchangeZbuffer (GtkWidget *widget, gpointer data) +{ + portals.zbuffer = GPOINTER_TO_INT (data); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnPoly (GtkWidget *widget, gpointer data) +{ + portals.polygons = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnLines (GtkWidget *widget, gpointer data) +{ + portals.lines = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnClip (GtkWidget *widget, gpointer data) +{ + portals.clip = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +void DoConfigDialog () +{ + GtkWidget *dlg, *hbox, *vbox, *vbox2, *button, *table, *frame; + GtkWidget *lw3slider, *lw3label, *lw2slider, *lw2label, *zlist, *menu, *item; + GtkWidget *aa2check, *aa3check, *depthcheck, *linescheck, *polyscheck; + GtkWidget *transslider, *translabel, *clipslider, *cliplabel; + GtkWidget *show2check, *show3check, *portalcheck; + int loop = 1, ret = IDCANCEL; + GtkObject *adj; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Portal Viewer Configuration"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + frame = gtk_frame_new ("3D View"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (frame), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, TRUE, 0); + + adj = gtk_adjustment_new (portals.width_3d, 2, 40, 1, 1, 1); + lw3slider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (lw3slider); + gtk_box_pack_start (GTK_BOX (hbox), lw3slider, TRUE, TRUE, 0); + gtk_scale_set_draw_value (GTK_SCALE (lw3slider), FALSE); + + lw3label = gtk_label_new (""); + gtk_widget_show (lw3label); + gtk_box_pack_start (GTK_BOX (hbox), lw3label, FALSE, TRUE, 0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScroll3d), lw3label); + + table = gtk_table_new (2, 4, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + button = gtk_button_new_with_label ("Color"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColor3d), NULL); + + button = gtk_button_new_with_label ("Depth Color"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColorFog), NULL); + + aa3check = gtk_check_button_new_with_label ("Anti-Alias (May not work on some video cards)"); + gtk_widget_show (aa3check); + gtk_table_attach (GTK_TABLE (table), aa3check, 1, 4, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (aa3check), "toggled", GTK_SIGNAL_FUNC (OnAntiAlias3d), NULL); + + depthcheck = gtk_check_button_new_with_label ("Depth Cue"); + gtk_widget_show (depthcheck); + gtk_table_attach (GTK_TABLE (table), depthcheck, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (depthcheck), "toggled", GTK_SIGNAL_FUNC (OnFog), NULL); + + linescheck = gtk_check_button_new_with_label ("Lines"); + gtk_widget_show (linescheck); + gtk_table_attach (GTK_TABLE (table), linescheck, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (linescheck), "toggled", GTK_SIGNAL_FUNC (OnLines), NULL); + + polyscheck = gtk_check_button_new_with_label ("Polygons"); + gtk_widget_show (polyscheck); + gtk_table_attach (GTK_TABLE (table), polyscheck, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (polyscheck), "toggled", GTK_SIGNAL_FUNC (OnPoly), NULL); + + zlist = gtk_option_menu_new (); + gtk_widget_show (zlist); + gtk_box_pack_start (GTK_BOX (vbox2), zlist, TRUE, FALSE, 0); + + menu = gtk_menu_new (); + gtk_widget_show (menu); + gtk_option_menu_set_menu (GTK_OPTION_MENU (zlist), menu); + + item = gtk_menu_item_new_with_label ("Z-Buffer Test and Write (recommended for solid or no polygons)"); + gtk_widget_show (item); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (0)); + gtk_menu_append (GTK_MENU (menu), item); + + item = gtk_menu_item_new_with_label ("Z-Buffer Test Only (recommended for transparent polygons)"); + gtk_widget_show (item); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (1)); + gtk_menu_append (GTK_MENU (menu), item); + + item = gtk_menu_item_new_with_label ("Z-Buffer Off"); + gtk_widget_show (item); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (2)); + gtk_menu_append (GTK_MENU (menu), item); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + adj = gtk_adjustment_new (portals.trans_3d, 0, 100, 1, 1, 1); + transslider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (transslider); + gtk_table_attach (GTK_TABLE (table), transslider, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_scale_set_draw_value (GTK_SCALE (transslider), FALSE); + + translabel = gtk_label_new (""); + gtk_widget_show (translabel); + gtk_table_attach (GTK_TABLE (table), translabel, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (translabel), 0.0, 0.0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScrollTrans), translabel); + + adj = gtk_adjustment_new (portals.clip_range, 1, 128, 1, 1, 1); + clipslider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (clipslider); + gtk_table_attach (GTK_TABLE (table), clipslider, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_scale_set_draw_value (GTK_SCALE (clipslider), FALSE); + + cliplabel = gtk_label_new (""); + gtk_widget_show (cliplabel); + gtk_table_attach (GTK_TABLE (table), cliplabel, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (cliplabel), 0.0, 0.0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScrollClip), cliplabel); + + hbox = gtk_hbox_new (TRUE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + show3check = gtk_check_button_new_with_label ("Show"); + gtk_widget_show (show3check); + gtk_box_pack_start (GTK_BOX (hbox), show3check, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (show3check), "toggled", GTK_SIGNAL_FUNC (OnConfig3d), NULL); + + portalcheck = gtk_check_button_new_with_label ("Portal cubic clipper"); + gtk_widget_show (portalcheck); + gtk_box_pack_start (GTK_BOX (hbox), portalcheck, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (portalcheck), "toggled", GTK_SIGNAL_FUNC (OnClip), NULL); + + frame = gtk_frame_new ("2D View"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (frame), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + adj = gtk_adjustment_new (portals.width_2d, 2, 40, 1, 1, 1); + lw2slider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (lw2slider); + gtk_box_pack_start (GTK_BOX (hbox), lw2slider, TRUE, TRUE, 0); + gtk_scale_set_draw_value (GTK_SCALE (lw2slider), FALSE); + + lw2label = gtk_label_new (""); + gtk_widget_show (lw2label); + gtk_box_pack_start (GTK_BOX (hbox), lw2label, FALSE, TRUE, 0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScroll2d), lw2label); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + button = gtk_button_new_with_label ("Color"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColor2d), NULL); + gtk_widget_set_usize (button, 60, -2); + + aa2check = gtk_check_button_new_with_label ("Anti-Alias (May not work on some video cards)"); + gtk_widget_show (aa2check); + gtk_box_pack_start (GTK_BOX (hbox), aa2check, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (aa2check), "toggled", GTK_SIGNAL_FUNC (OnAntiAlias2d), NULL); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + show2check = gtk_check_button_new_with_label ("Show"); + gtk_widget_show (show2check); + gtk_box_pack_start (GTK_BOX (hbox), show2check, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (show2check), "toggled", GTK_SIGNAL_FUNC (OnConfig2d), NULL); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + // initialize dialog + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (show2check), portals.show_2d); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aa2check), portals.aa_2d); + Set2DText (lw2label); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (show3check), portals.show_3d); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (depthcheck), portals.fog); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (polyscheck), portals.polygons); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (linescheck), portals.lines); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aa3check), portals.aa_3d); + gtk_option_menu_set_history (GTK_OPTION_MENU (zlist), portals.zbuffer); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (portalcheck), portals.clip); + + Set3DText (lw3label); + Set3DTransText (translabel); + SetClipText (cliplabel); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +#else // GTK_PLUGIN + +CConfigDialog::CConfigDialog(CWnd* pParent /*=NULL*/) + : CDialog(CConfigDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CConfigDialog) + //}}AFX_DATA_INIT +} + + +void CConfigDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CConfigDialog) + DDX_Control(pDX, IDC_CLIP, m_clip_ctrl); + DDX_Control(pDX, IDC_CUBIC, m_cubic_ctrl); + DDX_Control(pDX, IDC_SCROLL_CUBIC, m_scroll_cubic_ctrl); + DDX_Control(pDX, IDC_LINES, m_line_ctrl); + DDX_Control(pDX, IDC_SCROLL_3D_TRANS, m_scroll_3d_trans_ctrl); + DDX_Control(pDX, IDC_3D_TRANS, m_3d_trans_ctrl); + DDX_Control(pDX, IDC_POLY, m_poly_ctrl); + DDX_Control(pDX, IDC_FOG, m_fog_ctrl); + DDX_Control(pDX, IDC_ZBUFFER, m_z_ctrl); + DDX_Control(pDX, IDC_SCROLL_3D_WIDTH, m_scroll_3d_width_ctrl); + DDX_Control(pDX, IDC_ANTI_ALIAS_3D, m_aa_3d_ctrl); + DDX_Control(pDX, IDC_3D_WIDTH, m_3d_width_ctrl); + DDX_Control(pDX, IDC_ANTI_ALIAS_2D, m_aa_2d_ctrl); + DDX_Control(pDX, IDC_SCROLL_2D_WIDTH, m_scroll_2d_width_ctrl); + DDX_Control(pDX, IDC_2D_WIDTH, m_2d_width_ctrl); + DDX_Control(pDX, IDC_CONFIG_3D, m_3d_ctrl); + DDX_Control(pDX, IDC_CONFIG_2D, m_2d_ctrl); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CConfigDialog, CDialog) + //{{AFX_MSG_MAP(CConfigDialog) + ON_WM_HSCROLL() + ON_BN_CLICKED(IDC_ANTI_ALIAS_2D, OnAntiAlias2d) + ON_BN_CLICKED(IDC_CONFIG_2D, OnConfig2d) + ON_BN_CLICKED(IDC_CONFIG_3D, OnConfig3d) + ON_BN_CLICKED(IDC_COLOR_2D, OnColor2d) + ON_BN_CLICKED(IDC_ANTI_ALIAS_3D, OnAntiAlias3d) + ON_BN_CLICKED(IDC_COLOR_3D, OnColor3d) + ON_BN_CLICKED(IDC_COLOR_FOG, OnColorFog) + ON_BN_CLICKED(IDC_FOG, OnFog) + ON_CBN_SELCHANGE(IDC_ZBUFFER, OnSelchangeZbuffer) + ON_BN_CLICKED(IDC_POLY, OnPoly) + ON_BN_CLICKED(IDC_LINES, OnLines) + ON_BN_CLICKED(IDC_CLIP, OnClip) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CConfigDialog message handlers + +void CConfigDialog::Set2DText() +{ + char s[40]; + + sprintf(s, "Line Width = %6.3f", portals.width_2d * 0.5f); + + m_2d_width_ctrl.SetWindowText(s); +} + +void CConfigDialog::Set3DText() +{ + char s[40]; + + sprintf(s, "Line Width = %6.3f", portals.width_3d * 0.5f); + + m_3d_width_ctrl.SetWindowText(s); +} + +void CConfigDialog::Set3DTransText() +{ + char s[40]; + + sprintf(s, "Polygon transparency = %d%%", (int)portals.trans_3d); + + m_3d_trans_ctrl.SetWindowText(s); +} + +void CConfigDialog::SetClipText() +{ + char s[40]; + + sprintf(s, "Cubic clip range = %d", (int)portals.clip_range * 64); + + m_cubic_ctrl.SetWindowText(s); +} + +qboolean CConfigDialog::OnInitDialog() +{ + CDialog::OnInitDialog(); + + m_2d_ctrl.SetCheck(portals.show_2d); + m_aa_2d_ctrl.SetCheck(portals.aa_2d); + Set2DText(); + + m_scroll_2d_width_ctrl.SetScrollRange(2, 40, FALSE); + m_scroll_2d_width_ctrl.SetScrollPos((int)portals.width_2d, TRUE); + + m_3d_ctrl.SetCheck(portals.show_3d); + m_fog_ctrl.SetCheck(portals.fog); + m_poly_ctrl.SetCheck(portals.polygons); + m_line_ctrl.SetCheck(portals.lines); + m_aa_3d_ctrl.SetCheck(portals.aa_3d); + m_z_ctrl.SetCurSel(portals.zbuffer); + m_clip_ctrl.SetCheck(portals.clip); + + Set3DText(); + Set3DTransText(); + SetClipText(); + + m_scroll_3d_width_ctrl.SetScrollRange(2, 40, FALSE); + m_scroll_3d_width_ctrl.SetScrollPos((int)portals.width_3d, TRUE); + m_scroll_3d_trans_ctrl.SetScrollRange(0, 100, FALSE); + m_scroll_3d_trans_ctrl.SetScrollPos((int)portals.trans_3d, TRUE); + m_scroll_cubic_ctrl.SetScrollRange(1, 128, FALSE); + m_scroll_cubic_ctrl.SetScrollPos((int)portals.clip_range, TRUE); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CConfigDialog::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + float *adj; + float scr_min, scr_max, scr_big; + + if(nSBCode == SB_THUMBPOSITION) + { + CDialog::OnHScroll(nSBCode, nPos, pScrollBar); + return; + } + + if(pScrollBar == &m_scroll_2d_width_ctrl) + { + scr_min = 2.0f; + scr_max = 40.0f; + scr_big = 4.0f; + + adj = &portals.width_2d; + } + else if(pScrollBar == &m_scroll_3d_width_ctrl) + { + scr_min = 2.0f; + scr_max = 40.0f; + scr_big = 4.0f; + + adj = &portals.width_3d; + } + else if(pScrollBar == &m_scroll_3d_trans_ctrl) + { + scr_min = 0.0f; + scr_max = 100.0f; + scr_big = 10.0f; + + adj = &portals.trans_3d; + } + else if(pScrollBar == &m_scroll_cubic_ctrl) + { + scr_min = 1.0f; + scr_max = 128.0f; + scr_big = 8.0f; + + adj = &portals.clip_range; + } + else + { + CDialog::OnHScroll(nSBCode, nPos, pScrollBar); + return; + } + + switch(nSBCode) + { + case SB_LEFT: + *adj = scr_min; + pScrollBar->SetScrollPos((int)scr_min, TRUE); + break; + case SB_RIGHT: + *adj = scr_max; + pScrollBar->SetScrollPos((int)scr_max, TRUE); + break; + case SB_LINELEFT: + *adj -= 1.0f; + + if(*adj < scr_min) + *adj = scr_min; + + pScrollBar->SetScrollPos((int)(*adj), TRUE); + + break; + case SB_LINERIGHT: + *adj += 1.0f; + + if(*adj > scr_max) + *adj = scr_max; + + pScrollBar->SetScrollPos((int)(*adj), TRUE); + + break; + case SB_PAGELEFT: + *adj -= scr_big; + + if(*adj < scr_min) + *adj = scr_min; + + pScrollBar->SetScrollPos((int)(*adj), TRUE); + + break; + case SB_PAGERIGHT: + *adj += scr_big; + + if(*adj > scr_max) + *adj = scr_max; + + pScrollBar->SetScrollPos((int)(*adj), TRUE); + + break; + case SB_THUMBTRACK: + *adj = (float)nPos; + + break; + case SB_ENDSCROLL: + pScrollBar->SetScrollPos((int)(*adj), TRUE); + + break; + default: + CDialog::OnHScroll(nSBCode, nPos, pScrollBar); + } + + if(pScrollBar == &m_scroll_2d_width_ctrl) + { + Set2DText(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); + } + else if(pScrollBar == &m_scroll_3d_width_ctrl) + { + Set3DText(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } + else if(pScrollBar == &m_scroll_3d_trans_ctrl) + { + Set3DTransText(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } + else if(pScrollBar == &m_scroll_cubic_ctrl) + { + SetClipText(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } +} + +void CConfigDialog::OnAntiAlias2d() +{ + portals.aa_2d = m_aa_2d_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +void CConfigDialog::OnConfig2d() +{ + portals.show_2d = m_2d_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +void CConfigDialog::OnColor2d() +{ + CColorDialog dlg(portals.color_2d, CC_ANYCOLOR, this); + + if(dlg.DoModal() == IDOK) + { + portals.color_2d = dlg.GetColor(); + + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); + } +} + +void CConfigDialog::OnConfig3d() +{ + portals.show_3d = m_3d_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + + +void CConfigDialog::OnAntiAlias3d() +{ + portals.aa_3d = m_aa_3d_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +void CConfigDialog::OnColor3d() +{ + CColorDialog dlg(portals.color_3d, CC_ANYCOLOR, this); + + if(dlg.DoModal() == IDOK) + { + portals.color_3d = dlg.GetColor(); + + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } +} + +void CConfigDialog::OnColorFog() +{ + CColorDialog dlg(portals.color_fog, CC_ANYCOLOR, this); + + if(dlg.DoModal() == IDOK) + { + portals.color_fog = dlg.GetColor(); + + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } +} + +void CConfigDialog::OnFog() +{ + portals.fog = m_fog_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +void CConfigDialog::OnSelchangeZbuffer() +{ + portals.zbuffer = m_z_ctrl.GetCurSel(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +void CConfigDialog::OnPoly() +{ + portals.polygons = m_poly_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +void CConfigDialog::OnLines() +{ + portals.lines = m_line_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +void CConfigDialog::OnClip() +{ + portals.clip = m_clip_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +#endif // GTK_PLUGIN diff --git a/contrib/prtview/LoadPortalFileDialog.cpp b/contrib/prtview/LoadPortalFileDialog.cpp index ed7d9de1..0dda214c 100644 --- a/contrib/prtview/LoadPortalFileDialog.cpp +++ b/contrib/prtview/LoadPortalFileDialog.cpp @@ -1,288 +1,288 @@ -/* -PrtView plugin for GtkRadiant -Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com - -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 -*/ - -// LoadPortalFileDialog.cpp : implementation file -// - -#include "stdafx.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -//static char THIS_FILE[] = __FILE__; -#endif - -#ifdef GTK_PLUGIN - -static void dialog_button_callback (GtkWidget *widget, gpointer data) -{ - GtkWidget *parent; - int *loop, *ret; - - parent = gtk_widget_get_toplevel (widget); - loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); - ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); - - *loop = 0; - *ret = (int)data; -} - -static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) -{ - int *loop; - - gtk_widget_hide (widget); - loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); - *loop = 0; - - return TRUE; -} - -static void file_sel_callback (GtkWidget *widget, gpointer data) -{ - GtkWidget *parent; - int *loop; - char **filename; - - parent = gtk_widget_get_toplevel (widget); - loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); - filename = (char**)g_object_get_data (G_OBJECT (parent), "filename"); - - *loop = 0; - if ((int)data == IDOK) - *filename = g_strdup (gtk_file_selection_get_filename (GTK_FILE_SELECTION (parent))); -} - -static void change_clicked (GtkWidget *widget, gpointer data) -{ - GtkWidget* file_sel; - char* filename = NULL; - int loop = 1; - - file_sel = gtk_file_selection_new ("Locate portal (.prt) file"); - gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked", - GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDOK)); - gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked", - GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_signal_connect (GTK_OBJECT (file_sel), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (file_sel)); - - g_object_set_data (G_OBJECT (file_sel), "loop", &loop); - g_object_set_data (G_OBJECT (file_sel), "filename", &filename); - gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_sel), portals.fn); - - gtk_grab_add (file_sel); - gtk_widget_show (file_sel); - - while (loop) - gtk_main_iteration (); - - gtk_grab_remove (file_sel); - gtk_widget_destroy (file_sel); - - if (filename != NULL) - { - strcpy (portals.fn, filename); - gtk_entry_set_text (GTK_ENTRY (data), filename); - g_free (filename); - } -} - -int DoLoadPortalFileDialog () -{ - GtkWidget *dlg, *vbox, *hbox, *button, *entry, *check2d, *check3d; - int loop = 1, ret = IDCANCEL; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "Load .prt"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_container_add (GTK_CONTAINER (dlg), vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_entry_set_editable (GTK_ENTRY (entry), FALSE); - gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); - - check3d = gtk_check_button_new_with_label ("Show 3D"); - gtk_widget_show (check3d); - gtk_box_pack_start (GTK_BOX (hbox), check3d, FALSE, FALSE, 0); - - check2d = gtk_check_button_new_with_label ("Show 2D"); - gtk_widget_show (check2d); - gtk_box_pack_start (GTK_BOX (hbox), check2d, FALSE, FALSE, 0); - - button = gtk_button_new_with_label ("Change"); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (change_clicked), entry); - gtk_widget_set_usize (button, 60, -2); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); - - button = gtk_button_new_with_label ("Cancel"); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - char *fn = g_FuncTable.m_pfnGetMapName(); - strcpy (portals.fn, fn); - fn = strrchr (portals.fn, '.'); - if (fn != NULL) - { - *fn = '\0'; - strcat (portals.fn, ".prt"); - } - - gtk_entry_set_text (GTK_ENTRY (entry), portals.fn); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check2d), portals.show_2d); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check3d), portals.show_3d); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - if (ret == IDOK) - { - portals.Purge(); - - portals.show_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check3d)) ? true : false; - portals.show_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check2d)) ? true : false; - } - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); - - return ret; -} - -#else // GTK_PLUGIN - -///////////////////////////////////////////////////////////////////////////// -// CLoadPortalFileDialog dialog - -CLoadPortalFileDialog::CLoadPortalFileDialog(CWnd* pParent /*=NULL*/) - : CDialog(CLoadPortalFileDialog::IDD, pParent) -{ - //{{AFX_DATA_INIT(CLoadPortalFileDialog) - // NOTE: the ClassWizard will add member initialization here - //}}AFX_DATA_INIT -} - - -void CLoadPortalFileDialog::DoDataExchange(CDataExchange* pDX) -{ - CDialog::DoDataExchange(pDX); - //{{AFX_DATA_MAP(CLoadPortalFileDialog) - DDX_Control(pDX, IDC_LOAD_3D, m_3d_ctrl); - DDX_Control(pDX, IDC_LOAD_2D, m_2d_ctrl); - DDX_Control(pDX, IDC_LOAD_FILE_NAME, m_fn_ctrl); - //}}AFX_DATA_MAP -} - - -BEGIN_MESSAGE_MAP(CLoadPortalFileDialog, CDialog) - //{{AFX_MSG_MAP(CLoadPortalFileDialog) - ON_BN_CLICKED(IDC_LOAD_OTHER, OnLoadOther) - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - - -///////////////////////////////////////////////////////////////////////////// -// CLoadPortalFileDialog message handlers - -qboolean CLoadPortalFileDialog::OnInitDialog() -{ - CDialog::OnInitDialog(); - - char fn_drive[_MAX_DRIVE]; - char fn_dir[_MAX_DIR]; - char fn_name[_MAX_FNAME]; - char fn_ext[_MAX_EXT]; - - char *fn = g_IBSPTable.m_pfnGetMapName(); - - _fullpath(portals.fn, fn, _MAX_PATH); - _splitpath(fn, fn_drive, fn_dir, fn_name, fn_ext); - - strcpy(portals.fn, fn_drive); - strcat(portals.fn, fn_dir); - strcat(portals.fn, fn_name); - strcat(portals.fn, ".prt"); - - m_fn_ctrl.SetWindowText(portals.fn); - - m_2d_ctrl.SetCheck(portals.show_2d); - m_3d_ctrl.SetCheck(portals.show_3d); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -void CLoadPortalFileDialog::OnOK() -{ - portals.Purge(); - - portals.show_3d = m_3d_ctrl.GetCheck(); - portals.show_2d = m_2d_ctrl.GetCheck(); - - CDialog::OnOK(); -} - -void CLoadPortalFileDialog::OnLoadOther() -{ - CFileDialog dlg(TRUE, "prt", portals.fn, OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_LONGNAMES | OFN_FILEMUSTEXIST, - "Portal files (*.prt)|*.prt|All Files (*.*)|*.*||", NULL); - - dlg.m_ofn.lpstrTitle = "Locate portal file"; - - if(IDOK == dlg.DoModal()) - { - _fullpath(portals.fn, dlg.GetPathName().GetBuffer(1), _MAX_PATH); - m_fn_ctrl.SetWindowText(portals.fn); - } -} - -#endif // GTK_PLUGIN +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +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 +*/ + +// LoadPortalFileDialog.cpp : implementation file +// + +#include "stdafx.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +//static char THIS_FILE[] = __FILE__; +#endif + +#ifdef GTK_PLUGIN + +static void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} + +static void file_sel_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop; + char **filename; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + filename = (char**)g_object_get_data (G_OBJECT (parent), "filename"); + + *loop = 0; + if ((int)data == IDOK) + *filename = g_strdup (gtk_file_selection_get_filename (GTK_FILE_SELECTION (parent))); +} + +static void change_clicked (GtkWidget *widget, gpointer data) +{ + GtkWidget* file_sel; + char* filename = NULL; + int loop = 1; + + file_sel = gtk_file_selection_new ("Locate portal (.prt) file"); + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked", + GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDOK)); + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked", + GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_signal_connect (GTK_OBJECT (file_sel), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (file_sel)); + + g_object_set_data (G_OBJECT (file_sel), "loop", &loop); + g_object_set_data (G_OBJECT (file_sel), "filename", &filename); + gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_sel), portals.fn); + + gtk_grab_add (file_sel); + gtk_widget_show (file_sel); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (file_sel); + gtk_widget_destroy (file_sel); + + if (filename != NULL) + { + strcpy (portals.fn, filename); + gtk_entry_set_text (GTK_ENTRY (data), filename); + g_free (filename); + } +} + +int DoLoadPortalFileDialog () +{ + GtkWidget *dlg, *vbox, *hbox, *button, *entry, *check2d, *check3d; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Load .prt"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_entry_set_editable (GTK_ENTRY (entry), FALSE); + gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + check3d = gtk_check_button_new_with_label ("Show 3D"); + gtk_widget_show (check3d); + gtk_box_pack_start (GTK_BOX (hbox), check3d, FALSE, FALSE, 0); + + check2d = gtk_check_button_new_with_label ("Show 2D"); + gtk_widget_show (check2d); + gtk_box_pack_start (GTK_BOX (hbox), check2d, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Change"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (change_clicked), entry); + gtk_widget_set_usize (button, 60, -2); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + char *fn = g_FuncTable.m_pfnGetMapName(); + strcpy (portals.fn, fn); + fn = strrchr (portals.fn, '.'); + if (fn != NULL) + { + *fn = '\0'; + strcat (portals.fn, ".prt"); + } + + gtk_entry_set_text (GTK_ENTRY (entry), portals.fn); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check2d), portals.show_2d); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check3d), portals.show_3d); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + portals.Purge(); + + portals.show_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check3d)) ? true : false; + portals.show_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check2d)) ? true : false; + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + return ret; +} + +#else // GTK_PLUGIN + +///////////////////////////////////////////////////////////////////////////// +// CLoadPortalFileDialog dialog + +CLoadPortalFileDialog::CLoadPortalFileDialog(CWnd* pParent /*=NULL*/) + : CDialog(CLoadPortalFileDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CLoadPortalFileDialog) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT +} + + +void CLoadPortalFileDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CLoadPortalFileDialog) + DDX_Control(pDX, IDC_LOAD_3D, m_3d_ctrl); + DDX_Control(pDX, IDC_LOAD_2D, m_2d_ctrl); + DDX_Control(pDX, IDC_LOAD_FILE_NAME, m_fn_ctrl); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CLoadPortalFileDialog, CDialog) + //{{AFX_MSG_MAP(CLoadPortalFileDialog) + ON_BN_CLICKED(IDC_LOAD_OTHER, OnLoadOther) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + +///////////////////////////////////////////////////////////////////////////// +// CLoadPortalFileDialog message handlers + +qboolean CLoadPortalFileDialog::OnInitDialog() +{ + CDialog::OnInitDialog(); + + char fn_drive[_MAX_DRIVE]; + char fn_dir[_MAX_DIR]; + char fn_name[_MAX_FNAME]; + char fn_ext[_MAX_EXT]; + + char *fn = g_IBSPTable.m_pfnGetMapName(); + + _fullpath(portals.fn, fn, _MAX_PATH); + _splitpath(fn, fn_drive, fn_dir, fn_name, fn_ext); + + strcpy(portals.fn, fn_drive); + strcat(portals.fn, fn_dir); + strcat(portals.fn, fn_name); + strcat(portals.fn, ".prt"); + + m_fn_ctrl.SetWindowText(portals.fn); + + m_2d_ctrl.SetCheck(portals.show_2d); + m_3d_ctrl.SetCheck(portals.show_3d); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CLoadPortalFileDialog::OnOK() +{ + portals.Purge(); + + portals.show_3d = m_3d_ctrl.GetCheck(); + portals.show_2d = m_2d_ctrl.GetCheck(); + + CDialog::OnOK(); +} + +void CLoadPortalFileDialog::OnLoadOther() +{ + CFileDialog dlg(TRUE, "prt", portals.fn, OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_LONGNAMES | OFN_FILEMUSTEXIST, + "Portal files (*.prt)|*.prt|All Files (*.*)|*.*||", NULL); + + dlg.m_ofn.lpstrTitle = "Locate portal file"; + + if(IDOK == dlg.DoModal()) + { + _fullpath(portals.fn, dlg.GetPathName().GetBuffer(1), _MAX_PATH); + m_fn_ctrl.SetWindowText(portals.fn); + } +} + +#endif // GTK_PLUGIN diff --git a/contrib/prtview/gtkdlgs.cpp b/contrib/prtview/gtkdlgs.cpp index d19dd39b..f33c79b2 100644 --- a/contrib/prtview/gtkdlgs.cpp +++ b/contrib/prtview/gtkdlgs.cpp @@ -1,732 +1,732 @@ -/* -PrtView plugin for GtkRadiant -Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com - -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 -*/ - -// -// PrtView dialogs done with GTK+ -// - -#include -#include "stdafx.h" - -// ============================================================================= -// Static functions - -static void dialog_button_callback (GtkWidget *widget, gpointer data) -{ - GtkWidget *parent; - int *loop, *ret; - - parent = gtk_widget_get_toplevel (widget); - loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); - ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); - - *loop = 0; - *ret = (int)data; -} - -static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) -{ - int *loop; - - gtk_widget_hide (widget); - loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); - *loop = 0; - - return TRUE; -} - -static void file_sel_callback (GtkWidget *widget, gpointer data) -{ - GtkWidget *parent; - int *loop; - char **filename; - - parent = gtk_widget_get_toplevel (widget); - loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); - filename = (char**)g_object_get_data (G_OBJECT (parent), "filename"); - - *loop = 0; - if ((int)data == IDOK) - *filename = g_strdup (gtk_file_selection_get_filename (GTK_FILE_SELECTION (parent))); -} - -static void change_clicked (GtkWidget *widget, gpointer data) -{ - GtkWidget* file_sel; - char* filename = NULL; - int loop = 1; - - file_sel = gtk_file_selection_new ("Locate portal (.prt) file"); - gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked", - GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDOK)); - gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked", - GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_signal_connect (GTK_OBJECT (file_sel), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (file_sel)); - - g_object_set_data (G_OBJECT (file_sel), "loop", &loop); - g_object_set_data (G_OBJECT (file_sel), "filename", &filename); - gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_sel), portals.fn); - - gtk_grab_add (file_sel); - gtk_widget_show (file_sel); - - while (loop) - gtk_main_iteration (); - - gtk_grab_remove (file_sel); - gtk_widget_destroy (file_sel); - - if (filename != NULL) - { - strcpy (portals.fn, filename); - gtk_entry_set_text (GTK_ENTRY (data), filename); - g_free (filename); - } -} - -// ============================================================================= -// LoadPortalFile dialog - -int DoLoadPortalFileDialog () -{ - GtkWidget *dlg, *vbox, *hbox, *button, *entry, *check2d, *check3d; - int loop = 1, ret = IDCANCEL; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "Load .prt"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_container_add (GTK_CONTAINER (dlg), vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_entry_set_editable (GTK_ENTRY (entry), FALSE); - gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); - - check3d = gtk_check_button_new_with_label ("Show 3D"); - gtk_widget_show (check3d); - gtk_box_pack_start (GTK_BOX (hbox), check3d, FALSE, FALSE, 0); - - check2d = gtk_check_button_new_with_label ("Show 2D"); - gtk_widget_show (check2d); - gtk_box_pack_start (GTK_BOX (hbox), check2d, FALSE, FALSE, 0); - - button = gtk_button_new_with_label ("Change"); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (change_clicked), entry); - gtk_widget_set_usize (button, 60, -2); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); - - button = gtk_button_new_with_label ("Cancel"); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - char *fn = g_IBSPTable.m_pfnGetMapName(); - strcpy (portals.fn, fn); - fn = strrchr (portals.fn, '.'); - if (fn != NULL) - { - *fn = '\0'; - strcat (portals.fn, ".prt"); - } - - gtk_entry_set_text (GTK_ENTRY (entry), portals.fn); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check2d), portals.show_2d); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check3d), portals.show_3d); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - if (ret == IDOK) - { - portals.Purge(); - - portals.show_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check3d)); - portals.show_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check2d)); - } - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); - - return ret; -} - -// ============================================================================= -// About dialog - -void DoAboutDlg () -{ - GtkWidget *dlg, *hbox, *vbox, *button, *label; - int loop = 1, ret = IDCANCEL; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "About Portal Viewer"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - hbox = gtk_hbox_new (FALSE, 10); - gtk_widget_show (hbox); - gtk_container_add (GTK_CONTAINER (dlg), hbox); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 10); - - label = gtk_label_new ("Version 1.000\n\n" - "Gtk port by Leonardo Zide\nleo@lokigames.com\n\n" - "Written by Geoffrey DeWan\ngdewan@prairienet.org"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - - vbox = gtk_vbox_new (FALSE, 0); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); -} - -// ============================================================================= -// Config dialog - -static int DoColor (COLORREF *c) -{ - GtkWidget* dlg; - double clr[3]; - int loop = 1, ret = IDCANCEL; - - clr[0] = ((double)GetRValue (*c)) / 255.0; - clr[1] = ((double)GetGValue (*c)) / 255.0; - clr[2] = ((double)GetBValue (*c)) / 255.0; - - dlg = gtk_color_selection_dialog_new ("Choose Color"); - gtk_color_selection_set_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), clr); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->ok_button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->cancel_button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - gtk_widget_show(dlg); - gtk_grab_add(dlg); - - while (loop) - gtk_main_iteration (); - - gtk_color_selection_get_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), clr); - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); - - if (ret == IDOK) - { - *c = RGB (clr[0]*255, clr[1]*255, clr[2]*255); - } - - return ret; -} - -static void Set2DText (GtkWidget* label) -{ - char s[40]; - - sprintf(s, "Line Width = %6.3f", portals.width_2d * 0.5f); - - gtk_label_set_text (GTK_LABEL (label), s); -} - -static void Set3DText (GtkWidget* label) -{ - char s[40]; - - sprintf(s, "Line Width = %6.3f", portals.width_3d * 0.5f); - - gtk_label_set_text (GTK_LABEL (label), s); -} - -static void Set3DTransText (GtkWidget* label) -{ - char s[40]; - - sprintf(s, "Polygon transparency = %d%%", (int)portals.trans_3d); - - gtk_label_set_text (GTK_LABEL (label), s); -} - -static void SetClipText (GtkWidget* label) -{ - char s[40]; - - sprintf(s, "Cubic clip range = %d", (int)portals.clip_range * 64); - - gtk_label_set_text (GTK_LABEL (label), s); -} - -static void OnScroll2d (GtkAdjustment *adj, gpointer data) -{ - portals.width_2d = adj->value; - Set2DText (GTK_WIDGET (data)); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); -} - -static void OnScroll3d (GtkAdjustment *adj, gpointer data) -{ - portals.width_3d = adj->value; - Set3DText (GTK_WIDGET (data)); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -static void OnScrollTrans (GtkAdjustment *adj, gpointer data) -{ - portals.trans_3d = adj->value; - Set3DTransText (GTK_WIDGET (data)); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -static void OnScrollClip (GtkAdjustment *adj, gpointer data) -{ - portals.clip_range = adj->value; - SetClipText (GTK_WIDGET (data)); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -static void OnAntiAlias2d (GtkWidget *widget, gpointer data) -{ - portals.aa_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); -} - -static void OnConfig2d (GtkWidget *widget, gpointer data) -{ - portals.show_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); -} - -static void OnColor2d (GtkWidget *widget, gpointer data) -{ - if (DoColor (&portals.color_2d) == IDOK) - { - portals.FixColors(); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); - } -} - -static void OnConfig3d (GtkWidget *widget, gpointer data) -{ - portals.show_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - - -static void OnAntiAlias3d (GtkWidget *widget, gpointer data) -{ - portals.aa_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -static void OnColor3d (GtkWidget *widget, gpointer data) -{ - if (DoColor (&portals.color_3d) == IDOK) - { - portals.FixColors(); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); - } -} - -static void OnColorFog (GtkWidget *widget, gpointer data) -{ - if (DoColor (&portals.color_fog) == IDOK) - { - portals.FixColors(); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); - } -} - -static void OnFog (GtkWidget *widget, gpointer data) -{ - portals.fog = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -static void OnSelchangeZbuffer (GtkWidget *widget, gpointer data) -{ - portals.zbuffer = GPOINTER_TO_INT (data); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -static void OnPoly (GtkWidget *widget, gpointer data) -{ - portals.polygons = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -static void OnLines (GtkWidget *widget, gpointer data) -{ - portals.lines = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -static void OnClip (GtkWidget *widget, gpointer data) -{ - portals.clip = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); -} - -void DoConfigDialog () -{ - GtkWidget *dlg, *hbox, *vbox, *vbox2, *button, *table, *frame; - GtkWidget *lw3slider, *lw3label, *lw2slider, *lw2label, *zlist, *menu, *item; - GtkWidget *aa2check, *aa3check, *depthcheck, *linescheck, *polyscheck; - GtkWidget *transslider, *translabel, *clipslider, *cliplabel; - GtkWidget *show2check, *show3check, *portalcheck; - int loop = 1, ret = IDCANCEL; - GtkObject *adj; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "Portal Viewer Configuration"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_container_add (GTK_CONTAINER (dlg), vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - - frame = gtk_frame_new ("3D View"); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); - - vbox2 = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox2); - gtk_container_add (GTK_CONTAINER (frame), vbox2); - gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, TRUE, 0); - - adj = gtk_adjustment_new (portals.width_3d, 2, 40, 1, 1, 1); - lw3slider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); - gtk_widget_show (lw3slider); - gtk_box_pack_start (GTK_BOX (hbox), lw3slider, TRUE, TRUE, 0); - gtk_scale_set_draw_value (GTK_SCALE (lw3slider), FALSE); - - lw3label = gtk_label_new (""); - gtk_widget_show (lw3label); - gtk_box_pack_start (GTK_BOX (hbox), lw3label, FALSE, TRUE, 0); - gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScroll3d), lw3label); - - table = gtk_table_new (2, 4, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - button = gtk_button_new_with_label ("Color"); - gtk_widget_show (button); - gtk_table_attach (GTK_TABLE (table), button, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColor3d), NULL); - - button = gtk_button_new_with_label ("Depth Color"); - gtk_widget_show (button); - gtk_table_attach (GTK_TABLE (table), button, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColorFog), NULL); - - aa3check = gtk_check_button_new_with_label ("Anti-Alias (May not work on some video cards)"); - gtk_widget_show (aa3check); - gtk_table_attach (GTK_TABLE (table), aa3check, 1, 4, 0, 1, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_signal_connect (GTK_OBJECT (aa3check), "toggled", GTK_SIGNAL_FUNC (OnAntiAlias3d), NULL); - - depthcheck = gtk_check_button_new_with_label ("Depth Cue"); - gtk_widget_show (depthcheck); - gtk_table_attach (GTK_TABLE (table), depthcheck, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_signal_connect (GTK_OBJECT (depthcheck), "toggled", GTK_SIGNAL_FUNC (OnFog), NULL); - - linescheck = gtk_check_button_new_with_label ("Lines"); - gtk_widget_show (linescheck); - gtk_table_attach (GTK_TABLE (table), linescheck, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_signal_connect (GTK_OBJECT (linescheck), "toggled", GTK_SIGNAL_FUNC (OnLines), NULL); - - polyscheck = gtk_check_button_new_with_label ("Polygons"); - gtk_widget_show (polyscheck); - gtk_table_attach (GTK_TABLE (table), polyscheck, 3, 4, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_signal_connect (GTK_OBJECT (polyscheck), "toggled", GTK_SIGNAL_FUNC (OnPoly), NULL); - - zlist = gtk_option_menu_new (); - gtk_widget_show (zlist); - gtk_box_pack_start (GTK_BOX (vbox2), zlist, TRUE, FALSE, 0); - - menu = gtk_menu_new (); - gtk_widget_show (menu); - gtk_option_menu_set_menu (GTK_OPTION_MENU (zlist), menu); - - item = gtk_menu_item_new_with_label ("Z-Buffer Test and Write (recommended for solid or no polygons)"); - gtk_widget_show (item); - gtk_signal_connect (GTK_OBJECT (item), "activate", - GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (0)); - gtk_menu_append (GTK_MENU (menu), item); - - item = gtk_menu_item_new_with_label ("Z-Buffer Test Only (recommended for transparent polygons)"); - gtk_widget_show (item); - gtk_signal_connect (GTK_OBJECT (item), "activate", - GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (1)); - gtk_menu_append (GTK_MENU (menu), item); - - item = gtk_menu_item_new_with_label ("Z-Buffer Off"); - gtk_widget_show (item); - gtk_signal_connect (GTK_OBJECT (item), "activate", - GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (2)); - gtk_menu_append (GTK_MENU (menu), item); - - table = gtk_table_new (2, 2, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - adj = gtk_adjustment_new (portals.trans_3d, 0, 100, 1, 1, 1); - transslider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); - gtk_widget_show (transslider); - gtk_table_attach (GTK_TABLE (table), transslider, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_scale_set_draw_value (GTK_SCALE (transslider), FALSE); - - translabel = gtk_label_new (""); - gtk_widget_show (translabel); - gtk_table_attach (GTK_TABLE (table), translabel, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (translabel), 0.0, 0.0); - gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScrollTrans), translabel); - - adj = gtk_adjustment_new (portals.clip_range, 1, 128, 1, 1, 1); - clipslider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); - gtk_widget_show (clipslider); - gtk_table_attach (GTK_TABLE (table), clipslider, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_scale_set_draw_value (GTK_SCALE (clipslider), FALSE); - - cliplabel = gtk_label_new (""); - gtk_widget_show (cliplabel); - gtk_table_attach (GTK_TABLE (table), cliplabel, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (cliplabel), 0.0, 0.0); - gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScrollClip), cliplabel); - - hbox = gtk_hbox_new (TRUE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); - - show3check = gtk_check_button_new_with_label ("Show"); - gtk_widget_show (show3check); - gtk_box_pack_start (GTK_BOX (hbox), show3check, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (show3check), "toggled", GTK_SIGNAL_FUNC (OnConfig3d), NULL); - - portalcheck = gtk_check_button_new_with_label ("Portal cubic clipper"); - gtk_widget_show (portalcheck); - gtk_box_pack_start (GTK_BOX (hbox), portalcheck, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (portalcheck), "toggled", GTK_SIGNAL_FUNC (OnClip), NULL); - - frame = gtk_frame_new ("2D View"); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); - - vbox2 = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox2); - gtk_container_add (GTK_CONTAINER (frame), vbox2); - gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); - - adj = gtk_adjustment_new (portals.width_2d, 2, 40, 1, 1, 1); - lw2slider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); - gtk_widget_show (lw2slider); - gtk_box_pack_start (GTK_BOX (hbox), lw2slider, TRUE, TRUE, 0); - gtk_scale_set_draw_value (GTK_SCALE (lw2slider), FALSE); - - lw2label = gtk_label_new (""); - gtk_widget_show (lw2label); - gtk_box_pack_start (GTK_BOX (hbox), lw2label, FALSE, TRUE, 0); - gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScroll2d), lw2label); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); - - button = gtk_button_new_with_label ("Color"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColor2d), NULL); - gtk_widget_set_usize (button, 60, -2); - - aa2check = gtk_check_button_new_with_label ("Anti-Alias (May not work on some video cards)"); - gtk_widget_show (aa2check); - gtk_box_pack_start (GTK_BOX (hbox), aa2check, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (aa2check), "toggled", GTK_SIGNAL_FUNC (OnAntiAlias2d), NULL); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); - - show2check = gtk_check_button_new_with_label ("Show"); - gtk_widget_show (show2check); - gtk_box_pack_start (GTK_BOX (hbox), show2check, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (show2check), "toggled", GTK_SIGNAL_FUNC (OnConfig2d), NULL); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - // initialize dialog - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (show2check), portals.show_2d); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aa2check), portals.aa_2d); - Set2DText (lw2label); - - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (show3check), portals.show_3d); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (depthcheck), portals.fog); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (polyscheck), portals.polygons); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (linescheck), portals.lines); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aa3check), portals.aa_3d); - gtk_option_menu_set_history (GTK_OPTION_MENU (zlist), portals.zbuffer); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (portalcheck), portals.clip); - - Set3DText (lw3label); - Set3DTransText (translabel); - SetClipText (cliplabel); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); -} +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +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 +*/ + +// +// PrtView dialogs done with GTK+ +// + +#include +#include "stdafx.h" + +// ============================================================================= +// Static functions + +static void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} + +static void file_sel_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop; + char **filename; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + filename = (char**)g_object_get_data (G_OBJECT (parent), "filename"); + + *loop = 0; + if ((int)data == IDOK) + *filename = g_strdup (gtk_file_selection_get_filename (GTK_FILE_SELECTION (parent))); +} + +static void change_clicked (GtkWidget *widget, gpointer data) +{ + GtkWidget* file_sel; + char* filename = NULL; + int loop = 1; + + file_sel = gtk_file_selection_new ("Locate portal (.prt) file"); + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked", + GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDOK)); + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked", + GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_signal_connect (GTK_OBJECT (file_sel), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (file_sel)); + + g_object_set_data (G_OBJECT (file_sel), "loop", &loop); + g_object_set_data (G_OBJECT (file_sel), "filename", &filename); + gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_sel), portals.fn); + + gtk_grab_add (file_sel); + gtk_widget_show (file_sel); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (file_sel); + gtk_widget_destroy (file_sel); + + if (filename != NULL) + { + strcpy (portals.fn, filename); + gtk_entry_set_text (GTK_ENTRY (data), filename); + g_free (filename); + } +} + +// ============================================================================= +// LoadPortalFile dialog + +int DoLoadPortalFileDialog () +{ + GtkWidget *dlg, *vbox, *hbox, *button, *entry, *check2d, *check3d; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Load .prt"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_entry_set_editable (GTK_ENTRY (entry), FALSE); + gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + check3d = gtk_check_button_new_with_label ("Show 3D"); + gtk_widget_show (check3d); + gtk_box_pack_start (GTK_BOX (hbox), check3d, FALSE, FALSE, 0); + + check2d = gtk_check_button_new_with_label ("Show 2D"); + gtk_widget_show (check2d); + gtk_box_pack_start (GTK_BOX (hbox), check2d, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Change"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (change_clicked), entry); + gtk_widget_set_usize (button, 60, -2); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + char *fn = g_IBSPTable.m_pfnGetMapName(); + strcpy (portals.fn, fn); + fn = strrchr (portals.fn, '.'); + if (fn != NULL) + { + *fn = '\0'; + strcat (portals.fn, ".prt"); + } + + gtk_entry_set_text (GTK_ENTRY (entry), portals.fn); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check2d), portals.show_2d); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check3d), portals.show_3d); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + portals.Purge(); + + portals.show_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check3d)); + portals.show_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check2d)); + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + return ret; +} + +// ============================================================================= +// About dialog + +void DoAboutDlg () +{ + GtkWidget *dlg, *hbox, *vbox, *button, *label; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "About Portal Viewer"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 10); + + label = gtk_label_new ("Version 1.000\n\n" + "Gtk port by Leonardo Zide\nleo@lokigames.com\n\n" + "Written by Geoffrey DeWan\ngdewan@prairienet.org"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + vbox = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// Config dialog + +static int DoColor (COLORREF *c) +{ + GtkWidget* dlg; + double clr[3]; + int loop = 1, ret = IDCANCEL; + + clr[0] = ((double)GetRValue (*c)) / 255.0; + clr[1] = ((double)GetGValue (*c)) / 255.0; + clr[2] = ((double)GetBValue (*c)) / 255.0; + + dlg = gtk_color_selection_dialog_new ("Choose Color"); + gtk_color_selection_set_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), clr); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->ok_button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->cancel_button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + gtk_widget_show(dlg); + gtk_grab_add(dlg); + + while (loop) + gtk_main_iteration (); + + gtk_color_selection_get_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), clr); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + if (ret == IDOK) + { + *c = RGB (clr[0]*255, clr[1]*255, clr[2]*255); + } + + return ret; +} + +static void Set2DText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Line Width = %6.3f", portals.width_2d * 0.5f); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void Set3DText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Line Width = %6.3f", portals.width_3d * 0.5f); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void Set3DTransText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Polygon transparency = %d%%", (int)portals.trans_3d); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void SetClipText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Cubic clip range = %d", (int)portals.clip_range * 64); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void OnScroll2d (GtkAdjustment *adj, gpointer data) +{ + portals.width_2d = adj->value; + Set2DText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +static void OnScroll3d (GtkAdjustment *adj, gpointer data) +{ + portals.width_3d = adj->value; + Set3DText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnScrollTrans (GtkAdjustment *adj, gpointer data) +{ + portals.trans_3d = adj->value; + Set3DTransText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnScrollClip (GtkAdjustment *adj, gpointer data) +{ + portals.clip_range = adj->value; + SetClipText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnAntiAlias2d (GtkWidget *widget, gpointer data) +{ + portals.aa_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +static void OnConfig2d (GtkWidget *widget, gpointer data) +{ + portals.show_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +static void OnColor2d (GtkWidget *widget, gpointer data) +{ + if (DoColor (&portals.color_2d) == IDOK) + { + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); + } +} + +static void OnConfig3d (GtkWidget *widget, gpointer data) +{ + portals.show_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + + +static void OnAntiAlias3d (GtkWidget *widget, gpointer data) +{ + portals.aa_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnColor3d (GtkWidget *widget, gpointer data) +{ + if (DoColor (&portals.color_3d) == IDOK) + { + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } +} + +static void OnColorFog (GtkWidget *widget, gpointer data) +{ + if (DoColor (&portals.color_fog) == IDOK) + { + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } +} + +static void OnFog (GtkWidget *widget, gpointer data) +{ + portals.fog = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnSelchangeZbuffer (GtkWidget *widget, gpointer data) +{ + portals.zbuffer = GPOINTER_TO_INT (data); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnPoly (GtkWidget *widget, gpointer data) +{ + portals.polygons = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnLines (GtkWidget *widget, gpointer data) +{ + portals.lines = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnClip (GtkWidget *widget, gpointer data) +{ + portals.clip = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +void DoConfigDialog () +{ + GtkWidget *dlg, *hbox, *vbox, *vbox2, *button, *table, *frame; + GtkWidget *lw3slider, *lw3label, *lw2slider, *lw2label, *zlist, *menu, *item; + GtkWidget *aa2check, *aa3check, *depthcheck, *linescheck, *polyscheck; + GtkWidget *transslider, *translabel, *clipslider, *cliplabel; + GtkWidget *show2check, *show3check, *portalcheck; + int loop = 1, ret = IDCANCEL; + GtkObject *adj; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Portal Viewer Configuration"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + frame = gtk_frame_new ("3D View"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (frame), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, TRUE, 0); + + adj = gtk_adjustment_new (portals.width_3d, 2, 40, 1, 1, 1); + lw3slider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (lw3slider); + gtk_box_pack_start (GTK_BOX (hbox), lw3slider, TRUE, TRUE, 0); + gtk_scale_set_draw_value (GTK_SCALE (lw3slider), FALSE); + + lw3label = gtk_label_new (""); + gtk_widget_show (lw3label); + gtk_box_pack_start (GTK_BOX (hbox), lw3label, FALSE, TRUE, 0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScroll3d), lw3label); + + table = gtk_table_new (2, 4, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + button = gtk_button_new_with_label ("Color"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColor3d), NULL); + + button = gtk_button_new_with_label ("Depth Color"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColorFog), NULL); + + aa3check = gtk_check_button_new_with_label ("Anti-Alias (May not work on some video cards)"); + gtk_widget_show (aa3check); + gtk_table_attach (GTK_TABLE (table), aa3check, 1, 4, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (aa3check), "toggled", GTK_SIGNAL_FUNC (OnAntiAlias3d), NULL); + + depthcheck = gtk_check_button_new_with_label ("Depth Cue"); + gtk_widget_show (depthcheck); + gtk_table_attach (GTK_TABLE (table), depthcheck, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (depthcheck), "toggled", GTK_SIGNAL_FUNC (OnFog), NULL); + + linescheck = gtk_check_button_new_with_label ("Lines"); + gtk_widget_show (linescheck); + gtk_table_attach (GTK_TABLE (table), linescheck, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (linescheck), "toggled", GTK_SIGNAL_FUNC (OnLines), NULL); + + polyscheck = gtk_check_button_new_with_label ("Polygons"); + gtk_widget_show (polyscheck); + gtk_table_attach (GTK_TABLE (table), polyscheck, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (polyscheck), "toggled", GTK_SIGNAL_FUNC (OnPoly), NULL); + + zlist = gtk_option_menu_new (); + gtk_widget_show (zlist); + gtk_box_pack_start (GTK_BOX (vbox2), zlist, TRUE, FALSE, 0); + + menu = gtk_menu_new (); + gtk_widget_show (menu); + gtk_option_menu_set_menu (GTK_OPTION_MENU (zlist), menu); + + item = gtk_menu_item_new_with_label ("Z-Buffer Test and Write (recommended for solid or no polygons)"); + gtk_widget_show (item); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (0)); + gtk_menu_append (GTK_MENU (menu), item); + + item = gtk_menu_item_new_with_label ("Z-Buffer Test Only (recommended for transparent polygons)"); + gtk_widget_show (item); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (1)); + gtk_menu_append (GTK_MENU (menu), item); + + item = gtk_menu_item_new_with_label ("Z-Buffer Off"); + gtk_widget_show (item); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (2)); + gtk_menu_append (GTK_MENU (menu), item); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + adj = gtk_adjustment_new (portals.trans_3d, 0, 100, 1, 1, 1); + transslider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (transslider); + gtk_table_attach (GTK_TABLE (table), transslider, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_scale_set_draw_value (GTK_SCALE (transslider), FALSE); + + translabel = gtk_label_new (""); + gtk_widget_show (translabel); + gtk_table_attach (GTK_TABLE (table), translabel, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (translabel), 0.0, 0.0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScrollTrans), translabel); + + adj = gtk_adjustment_new (portals.clip_range, 1, 128, 1, 1, 1); + clipslider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (clipslider); + gtk_table_attach (GTK_TABLE (table), clipslider, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_scale_set_draw_value (GTK_SCALE (clipslider), FALSE); + + cliplabel = gtk_label_new (""); + gtk_widget_show (cliplabel); + gtk_table_attach (GTK_TABLE (table), cliplabel, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (cliplabel), 0.0, 0.0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScrollClip), cliplabel); + + hbox = gtk_hbox_new (TRUE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + show3check = gtk_check_button_new_with_label ("Show"); + gtk_widget_show (show3check); + gtk_box_pack_start (GTK_BOX (hbox), show3check, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (show3check), "toggled", GTK_SIGNAL_FUNC (OnConfig3d), NULL); + + portalcheck = gtk_check_button_new_with_label ("Portal cubic clipper"); + gtk_widget_show (portalcheck); + gtk_box_pack_start (GTK_BOX (hbox), portalcheck, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (portalcheck), "toggled", GTK_SIGNAL_FUNC (OnClip), NULL); + + frame = gtk_frame_new ("2D View"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (frame), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + adj = gtk_adjustment_new (portals.width_2d, 2, 40, 1, 1, 1); + lw2slider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (lw2slider); + gtk_box_pack_start (GTK_BOX (hbox), lw2slider, TRUE, TRUE, 0); + gtk_scale_set_draw_value (GTK_SCALE (lw2slider), FALSE); + + lw2label = gtk_label_new (""); + gtk_widget_show (lw2label); + gtk_box_pack_start (GTK_BOX (hbox), lw2label, FALSE, TRUE, 0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScroll2d), lw2label); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + button = gtk_button_new_with_label ("Color"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColor2d), NULL); + gtk_widget_set_usize (button, 60, -2); + + aa2check = gtk_check_button_new_with_label ("Anti-Alias (May not work on some video cards)"); + gtk_widget_show (aa2check); + gtk_box_pack_start (GTK_BOX (hbox), aa2check, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (aa2check), "toggled", GTK_SIGNAL_FUNC (OnAntiAlias2d), NULL); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + show2check = gtk_check_button_new_with_label ("Show"); + gtk_widget_show (show2check); + gtk_box_pack_start (GTK_BOX (hbox), show2check, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (show2check), "toggled", GTK_SIGNAL_FUNC (OnConfig2d), NULL); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + // initialize dialog + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (show2check), portals.show_2d); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aa2check), portals.aa_2d); + Set2DText (lw2label); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (show3check), portals.show_3d); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (depthcheck), portals.fog); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (polyscheck), portals.polygons); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (linescheck), portals.lines); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aa3check), portals.aa_3d); + gtk_option_menu_set_history (GTK_OPTION_MENU (zlist), portals.zbuffer); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (portalcheck), portals.clip); + + Set3DText (lw3label); + Set3DTransText (translabel); + SetClipText (cliplabel); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} diff --git a/contrib/prtview/portals.cpp b/contrib/prtview/portals.cpp index 378bb85d..0c57d214 100644 --- a/contrib/prtview/portals.cpp +++ b/contrib/prtview/portals.cpp @@ -1,802 +1,802 @@ -/* -PrtView plugin for GtkRadiant -Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com - -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 -*/ - -#include "stdafx.h" -#include -#include -#ifndef __APPLE__ -#include -#endif -#include - -#define LINE_BUF 1000 - -CPortals portals; -CPortalsRender render; - -int compare( const void *arg1, const void *arg2 ) -{ - - if(portals.portal[*((int *)arg1)].dist > portals.portal[*((int *)arg2)].dist) - return -1; - else if(portals.portal[*((int *)arg1)].dist < portals.portal[*((int *)arg2)].dist) - return 1; - - return 0; -} - - -CBspPortal::CBspPortal() -{ - memset(this, 0, sizeof(CBspPortal)); -} - -CBspPortal::~CBspPortal() -{ - delete[] point; - delete[] inner_point; -} - -qboolean CBspPortal::Build(char *def) -{ - char *c = def; - unsigned int n; - int dummy1, dummy2; - int res_cnt, i; - - if(portals.hint_flags) - { - res_cnt = sscanf(def, "%u %d %d %d", &point_count, &dummy1, &dummy2, (int *)&hint); - } - else - { - sscanf(def, "%u", &point_count); - hint = FALSE; - } - - if(point_count < 3 || (portals.hint_flags && res_cnt < 4)) - return FALSE; - - point = new CBspPoint[point_count]; - inner_point = new CBspPoint[point_count]; - - for(n = 0; n < point_count; n++) - { - for(; *c != 0 && *c != '('; c++); - - if(*c == 0) - return FALSE; - - c++; - - sscanf(c, "%f %f %f", point[n].p, point[n].p+1, point[n].p+2); - - center.p[0] += point[n].p[0]; - center.p[1] += point[n].p[1]; - center.p[2] += point[n].p[2]; - - if(n == 0) - { - for(i = 0; i < 3; i++) - { - min[i] = point[n].p[i]; - max[i] = point[n].p[i]; - } - } - else - { - for(i = 0; i < 3; i++) - { - if(min[i] > point[n].p[i]) - min[i] = point[n].p[i]; - if(max[i] < point[n].p[i]) - max[i] = point[n].p[i]; - } - } - } - - center.p[0] /= (float)point_count; - center.p[1] /= (float)point_count; - center.p[2] /= (float)point_count; - - for(n = 0; n < point_count; n++) - { - inner_point[n].p[0] = (0.01f * center.p[0]) + (0.99f * point[n].p[0]); - inner_point[n].p[1] = (0.01f * center.p[1]) + (0.99f * point[n].p[1]); - inner_point[n].p[2] = (0.01f * center.p[2]) + (0.99f * point[n].p[2]); - } - - fp_color_random[0] = (float)(rand() & 0xff) / 255.0f; - fp_color_random[1] = (float)(rand() & 0xff) / 255.0f; - fp_color_random[2] = (float)(rand() & 0xff) / 255.0f; - fp_color_random[3] = 1.0f; - - return TRUE; -} - -CPortals::CPortals() -{ - memset(this, 0, sizeof(CPortals)); -} - -CPortals::~CPortals() -{ - Purge(); -} - -void CPortals::Purge() -{ - delete[] portal; - delete[] portal_sort; - portal = NULL; - portal_sort = NULL; - portal_count = 0; - - /* - delete[] node; - node = NULL; - node_count = 0; - */ -} - -void CPortals::Load() -{ - char buf[LINE_BUF+1]; - - memset(buf, 0, LINE_BUF + 1); - - Purge(); - - Sys_Printf(MSG_PREFIX "Loading portal file %s.\n", fn); - - FILE *in; - - in = fopen(fn, "rt"); - - if(in == NULL) - { - Sys_Printf(" ERROR - could not open file.\n"); - - return; - } - - if(!fgets(buf, LINE_BUF, in)) - { - fclose(in); - - Sys_Printf(" ERROR - File ended prematurely.\n"); - - return; - } - - if(strncmp("PRT1", buf, 4) != 0) - { - fclose(in); - - Sys_Printf(" ERROR - File header indicates wrong file type (should be \"PRT1\").\n"); - - return; - } - - if(!fgets(buf, LINE_BUF, in)) - { - fclose(in); - - Sys_Printf(" ERROR - File ended prematurely.\n"); - - return; - } - - sscanf(buf, "%u", &node_count); -/* - if(node_count > 0xFFFF) - { - fclose(in); - - node_count = 0; - - Sys_Printf(" ERROR - Extreme number of nodes, aborting.\n"); - - return; - } - */ - - if(!fgets(buf, LINE_BUF, in)) - { - fclose(in); - - node_count = 0; - - Sys_Printf(" ERROR - File ended prematurely.\n"); - - return; - } - - sscanf(buf, "%u", &portal_count); - - if(portal_count > 0xFFFF) - { - fclose(in); - - portal_count = 0; - node_count = 0; - - Sys_Printf(" ERROR - Extreme number of portals, aborting.\n"); - - return; - } - - if(portal_count < 0) - { - fclose(in); - - portal_count = 0; - node_count = 0; - - Sys_Printf(" ERROR - number of portals equals 0, aborting.\n"); - - return; - } - -// node = new CBspNode[node_count]; - portal = new CBspPortal[portal_count]; - portal_sort = new int[portal_count]; - - unsigned int n; - qboolean first = TRUE; - unsigned test_vals_1, test_vals_2; - - hint_flags = FALSE; - - for(n = 0; n < portal_count; ) - { - if(!fgets(buf, LINE_BUF, in)) - { - fclose(in); - - Purge(); - - Sys_Printf(" ERROR - Could not find information for portal number %d of %d.\n", n + 1, portal_count); - - return; - } - - if(!portal[n].Build(buf)) - { - if(first && sscanf(buf, "%d %d", &test_vals_1, &test_vals_2) == 1) // skip additional counts of later data, not needed - { - // We can count on hint flags being in the file - hint_flags = TRUE; - continue; - } - - first = FALSE; - - fclose(in); - - Purge(); - - Sys_Printf(" ERROR - Information for portal number %d of %d is not formatted correctly.\n", n + 1, portal_count); - - return; - } - - n++; - } - - fclose(in); - - Sys_Printf(" %u portals read in.\n", node_count, portal_count); -} - -void CPortals::FixColors() -{ - fp_color_2d[0] = (float)GetRValue(color_2d) / 255.0f; - fp_color_2d[1] = (float)GetGValue(color_2d) / 255.0f; - fp_color_2d[2] = (float)GetBValue(color_2d) / 255.0f; - fp_color_2d[3] = 1.0f; - - fp_color_3d[0] = (float)GetRValue(color_3d) / 255.0f; - fp_color_3d[1] = (float)GetGValue(color_3d) / 255.0f; - fp_color_3d[2] = (float)GetBValue(color_3d) / 255.0f; - fp_color_3d[3] = 1.0f; - - fp_color_fog[0] = 0.0f;//(float)GetRValue(color_fog) / 255.0f; - fp_color_fog[1] = 0.0f;//(float)GetGValue(color_fog) / 255.0f; - fp_color_fog[2] = 0.0f;//(float)GetBValue(color_fog) / 255.0f; - fp_color_fog[3] = 1.0f; -} - -CPortalsRender::CPortalsRender() -{ - refCount = 1; -} - -CPortalsRender::~CPortalsRender() -{ -} - -void CPortalsRender::Register() -{ - g_QglTable.m_pfnHookGL2DWindow( this ); - g_QglTable.m_pfnHookGL3DWindow( this ); -} - -void CPortalsRender::Draw2D( VIEWTYPE vt ) -{ - if(!portals.show_2d || portals.portal_count < 1) - return; - - g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); - - if(portals.aa_2d) - { - g_QglTable.m_pfn_qglEnable(GL_BLEND); - g_QglTable.m_pfn_qglEnable(GL_LINE_SMOOTH); - } - else - { - g_QglTable.m_pfn_qglDisable(GL_BLEND); - g_QglTable.m_pfn_qglEnable(GL_LINE_SMOOTH); - } - - 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(portals.width_2d * 0.5f); - - g_QglTable.m_pfn_qglColor4fv(portals.fp_color_2d); - - unsigned int n, p; - - for(n = 0; n < portals.portal_count; n++) - { - g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP); - - for(p = 0; p < portals.portal[n].point_count; p++) - g_QglTable.m_pfn_qglVertex3fv(portals.portal[n].point[p].p); - - g_QglTable.m_pfn_qglEnd(); - } - - g_QglTable.m_pfn_qglPopAttrib(); -} - -/* - * Transform a point (column vector) by a 4x4 matrix. I.e. out = m * in - * Input: m - the 4x4 matrix - * in - the 4x1 vector - * Output: out - the resulting 4x1 vector. - */ -static void transform_point( GLdouble out[4], const GLdouble m[16], - const GLdouble in[4] ) -{ -#define M(row,col) m[col*4+row] - out[0] = M(0,0) * in[0] + M(0,1) * in[1] + M(0,2) * in[2] + M(0,3) * in[3]; - out[1] = M(1,0) * in[0] + M(1,1) * in[1] + M(1,2) * in[2] + M(1,3) * in[3]; - out[2] = M(2,0) * in[0] + M(2,1) * in[1] + M(2,2) * in[2] + M(2,3) * in[3]; - out[3] = M(3,0) * in[0] + M(3,1) * in[1] + M(3,2) * in[2] + M(3,3) * in[3]; -#undef M -} - -#include - - -/* - * Perform a 4x4 matrix multiplication (product = a x b). - * Input: a, b - matrices to multiply - * Output: product - product of a and b - */ -static void matmul( GLdouble *product, const GLdouble *a, const GLdouble *b ) -{ - /* This matmul was contributed by Thomas Malik */ - GLdouble temp[16]; - GLint i; - -#define A(row,col) a[(col<<2)+row] -#define B(row,col) b[(col<<2)+row] -#define T(row,col) temp[(col<<2)+row] - - /* i-te Zeile */ - for (i = 0; i < 4; i++) - { - T(i, 0) = A(i, 0) * B(0, 0) + A(i, 1) * B(1, 0) + A(i, 2) * B(2, 0) + A(i, 3) * B(3, 0); - T(i, 1) = A(i, 0) * B(0, 1) + A(i, 1) * B(1, 1) + A(i, 2) * B(2, 1) + A(i, 3) * B(3, 1); - T(i, 2) = A(i, 0) * B(0, 2) + A(i, 1) * B(1, 2) + A(i, 2) * B(2, 2) + A(i, 3) * B(3, 2); - T(i, 3) = A(i, 0) * B(0, 3) + A(i, 1) * B(1, 3) + A(i, 2) * B(2, 3) + A(i, 3) * B(3, 3); - } - -#undef A -#undef B -#undef T - memcpy ( product, temp, 16*sizeof(GLdouble) ); -} - - - -/* - * Compute inverse of 4x4 transformation matrix. - * Code contributed by Jacques Leroy jle@star.be - * Return GL_TRUE for success, GL_FALSE for failure (singular matrix) - */ -static GLboolean invert_matrix( const GLdouble *m, GLdouble *out ) -{ -/* NB. OpenGL Matrices are COLUMN major. */ -#define SWAP_ROWS(a, b) { GLdouble *_tmp = a; (a)=(b); (b)=_tmp; } -#define MAT(m,r,c) (m)[(c)*4+(r)] - - GLdouble wtmp[4][8]; - GLdouble m0, m1, m2, m3, s; - GLdouble *r0, *r1, *r2, *r3; - - r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3]; - - r0[0] = MAT(m,0,0), r0[1] = MAT(m,0,1), - r0[2] = MAT(m,0,2), r0[3] = MAT(m,0,3), - r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0, - - r1[0] = MAT(m,1,0), r1[1] = MAT(m,1,1), - r1[2] = MAT(m,1,2), r1[3] = MAT(m,1,3), - r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0, - - r2[0] = MAT(m,2,0), r2[1] = MAT(m,2,1), - r2[2] = MAT(m,2,2), r2[3] = MAT(m,2,3), - r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0, - - r3[0] = MAT(m,3,0), r3[1] = MAT(m,3,1), - r3[2] = MAT(m,3,2), r3[3] = MAT(m,3,3), - r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0; - - /* choose pivot - or die */ - if (fabs(r3[0])>fabs(r2[0])) SWAP_ROWS(r3, r2); - if (fabs(r2[0])>fabs(r1[0])) SWAP_ROWS(r2, r1); - if (fabs(r1[0])>fabs(r0[0])) SWAP_ROWS(r1, r0); - if (0.0 == r0[0]) return GL_FALSE; - - /* eliminate first variable */ - m1 = r1[0]/r0[0]; m2 = r2[0]/r0[0]; m3 = r3[0]/r0[0]; - s = r0[1]; r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s; - s = r0[2]; r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s; - s = r0[3]; r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s; - s = r0[4]; - if (s != 0.0) { r1[4] -= m1 * s; r2[4] -= m2 * s; r3[4] -= m3 * s; } - s = r0[5]; - if (s != 0.0) { r1[5] -= m1 * s; r2[5] -= m2 * s; r3[5] -= m3 * s; } - s = r0[6]; - if (s != 0.0) { r1[6] -= m1 * s; r2[6] -= m2 * s; r3[6] -= m3 * s; } - s = r0[7]; - if (s != 0.0) { r1[7] -= m1 * s; r2[7] -= m2 * s; r3[7] -= m3 * s; } - - /* choose pivot - or die */ - if (fabs(r3[1])>fabs(r2[1])) SWAP_ROWS(r3, r2); - if (fabs(r2[1])>fabs(r1[1])) SWAP_ROWS(r2, r1); - if (0.0 == r1[1]) return GL_FALSE; - - /* eliminate second variable */ - m2 = r2[1]/r1[1]; m3 = r3[1]/r1[1]; - r2[2] -= m2 * r1[2]; r3[2] -= m3 * r1[2]; - r2[3] -= m2 * r1[3]; r3[3] -= m3 * r1[3]; - s = r1[4]; if (0.0 != s) { r2[4] -= m2 * s; r3[4] -= m3 * s; } - s = r1[5]; if (0.0 != s) { r2[5] -= m2 * s; r3[5] -= m3 * s; } - s = r1[6]; if (0.0 != s) { r2[6] -= m2 * s; r3[6] -= m3 * s; } - s = r1[7]; if (0.0 != s) { r2[7] -= m2 * s; r3[7] -= m3 * s; } - - /* choose pivot - or die */ - if (fabs(r3[2])>fabs(r2[2])) SWAP_ROWS(r3, r2); - if (0.0 == r2[2]) return GL_FALSE; - - /* eliminate third variable */ - m3 = r3[2]/r2[2]; - r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4], - r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6], - r3[7] -= m3 * r2[7]; - - /* last check */ - if (0.0 == r3[3]) return GL_FALSE; - - s = 1.0/r3[3]; /* now back substitute row 3 */ - r3[4] *= s; r3[5] *= s; r3[6] *= s; r3[7] *= s; - - m2 = r2[3]; /* now back substitute row 2 */ - s = 1.0/r2[2]; - r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2), - r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2); - m1 = r1[3]; - r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1, - r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1; - m0 = r0[3]; - r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0, - r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0; - - m1 = r1[2]; /* now back substitute row 1 */ - s = 1.0/r1[1]; - r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1), - r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1); - m0 = r0[2]; - r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0, - r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0; - - m0 = r0[1]; /* now back substitute row 0 */ - s = 1.0/r0[0]; - r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0), - r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0); - - MAT(out,0,0) = r0[4]; MAT(out,0,1) = r0[5], - MAT(out,0,2) = r0[6]; MAT(out,0,3) = r0[7], - MAT(out,1,0) = r1[4]; MAT(out,1,1) = r1[5], - MAT(out,1,2) = r1[6]; MAT(out,1,3) = r1[7], - MAT(out,2,0) = r2[4]; MAT(out,2,1) = r2[5], - MAT(out,2,2) = r2[6]; MAT(out,2,3) = r2[7], - MAT(out,3,0) = r3[4]; MAT(out,3,1) = r3[5], - MAT(out,3,2) = r3[6]; MAT(out,3,3) = r3[7]; - - return GL_TRUE; - -#undef MAT -#undef SWAP_ROWS -} - -GLint UnProject(GLdouble winx,GLdouble winy,GLdouble winz, - const GLdouble model[16],const GLdouble proj[16], - const GLint viewport[4], - GLdouble *objx,GLdouble *objy,GLdouble *objz) -{ - /* matrice de transformation */ - GLdouble m[16], A[16]; - GLdouble in[4],out[4]; - - /* transformation coordonnees normalisees entre -1 et 1 */ - in[0]=(winx-viewport[0])*2/viewport[2] - 1.0; - in[1]=(winy-viewport[1])*2/viewport[3] - 1.0; - in[2]=2*winz - 1.0; - in[3]=1.0; - - /* calcul transformation inverse */ - matmul(A,proj,model); - invert_matrix(A,m); - - /* d'ou les coordonnees objets */ - transform_point(out,m,in); - if (out[3]==0.0) - return GL_FALSE; - *objx=out[0]/out[3]; - *objy=out[1]/out[3]; - *objz=out[2]/out[3]; - return GL_TRUE; -} - -void CPortalsRender::Draw3D() -{ - if(!portals.show_3d || portals.portal_count < 1) - return; - - g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); - - double cam[3]; - double proj_m[16]; - double model_m[16]; - float min_check[3]; - float max_check[3]; - float trans = (100.0f - portals.trans_3d) / 100.0f; - int view[4]; - - g_QglTable.m_pfn_qglGetDoublev(GL_PROJECTION_MATRIX, proj_m); - g_QglTable.m_pfn_qglGetDoublev(GL_MODELVIEW_MATRIX, model_m); - g_QglTable.m_pfn_qglGetIntegerv(GL_VIEWPORT, view); - - UnProject(0.5 * (double)view[2], 0.5 * (double)view[3], 0.0, model_m, proj_m, view, cam, cam+1, cam+2); - - min_check[0] = (float)cam[0] + (portals.clip_range * 64.0f); - min_check[1] = (float)cam[1] + (portals.clip_range * 64.0f); - min_check[2] = (float)cam[2] + (portals.clip_range * 64.0f); - max_check[0] = (float)cam[0] - (portals.clip_range * 64.0f); - max_check[1] = (float)cam[1] - (portals.clip_range * 64.0f); - max_check[2] = (float)cam[2] - (portals.clip_range * 64.0f); - - g_QglTable.m_pfn_qglHint(GL_FOG_HINT, GL_NICEST); - - g_QglTable.m_pfn_qglDisable(GL_CULL_FACE); - - g_QglTable.m_pfn_qglDisable(GL_LINE_SMOOTH); - g_QglTable.m_pfn_qglDisable(GL_POLYGON_SMOOTH); - - g_QglTable.m_pfn_qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - g_QglTable.m_pfn_qglShadeModel(GL_SMOOTH); - - g_QglTable.m_pfn_qglEnable(GL_BLEND); - g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - g_QglTable.m_pfn_qglEnable(GL_POLYGON_SMOOTH); - - if(portals.aa_3d) - g_QglTable.m_pfn_qglEnable(GL_LINE_SMOOTH); - else - g_QglTable.m_pfn_qglDisable(GL_LINE_SMOOTH); - - if(portals.fog) - { - g_QglTable.m_pfn_qglEnable(GL_FOG); - - g_QglTable.m_pfn_qglFogi(GL_FOG_MODE, GL_EXP); - g_QglTable.m_pfn_qglFogf(GL_FOG_DENSITY, 0.001f); - g_QglTable.m_pfn_qglFogf(GL_FOG_START, 10.0f); - g_QglTable.m_pfn_qglFogf(GL_FOG_END, 10000.0f); - g_QglTable.m_pfn_qglFogi(GL_FOG_INDEX, 0); - g_QglTable.m_pfn_qglFogfv(GL_FOG_COLOR, portals.fp_color_fog); - } - else - { - g_QglTable.m_pfn_qglDisable(GL_FOG); - } - - switch(portals.zbuffer) - { - case 1: - g_QglTable.m_pfn_qglEnable(GL_DEPTH_TEST); - g_QglTable.m_pfn_qglDepthMask(GL_FALSE); - break; - case 2: - g_QglTable.m_pfn_qglDisable(GL_DEPTH_TEST); - break; - default: - g_QglTable.m_pfn_qglEnable(GL_DEPTH_TEST); - g_QglTable.m_pfn_qglDepthMask(GL_TRUE); - } - - g_QglTable.m_pfn_qglLineWidth(portals.width_3d * 0.5f); - - unsigned int n, p; - - if(portals.polygons) - { - if(portals.zbuffer != 0) - { - float d; - - for(n = 0; n < portals.portal_count; n++) - { - d = (float)cam[0] - portals.portal[n].center.p[0]; - portals.portal[n].dist = d * d; - - d = (float)cam[1] - portals.portal[n].center.p[1]; - portals.portal[n].dist += d * d; - - d = (float)cam[2] - portals.portal[n].center.p[2]; - portals.portal[n].dist += d * d; - - portals.portal_sort[n] = n; - } - - qsort(portals.portal_sort, portals.portal_count, 4, compare); - - for(n = 0; n < portals.portal_count; n++) - { - if(portals.polygons == 2 && !portals.portal[portals.portal_sort[n]].hint) - continue; - - if(portals.clip) - { - if(min_check[0] < portals.portal[portals.portal_sort[n]].min[0]) - continue; - else if(min_check[1] < portals.portal[portals.portal_sort[n]].min[1]) - continue; - else if(min_check[2] < portals.portal[portals.portal_sort[n]].min[2]) - continue; - else if(max_check[0] > portals.portal[portals.portal_sort[n]].max[0]) - continue; - else if(max_check[1] > portals.portal[portals.portal_sort[n]].max[1]) - continue; - else if(max_check[2] > portals.portal[portals.portal_sort[n]].max[2]) - continue; - } - - g_QglTable.m_pfn_qglColor4f(portals.portal[portals.portal_sort[n]].fp_color_random[0], portals.portal[portals.portal_sort[n]].fp_color_random[1], - portals.portal[portals.portal_sort[n]].fp_color_random[2], trans); - - g_QglTable.m_pfn_qglBegin(GL_POLYGON); - - for(p = 0; p < portals.portal[portals.portal_sort[n]].point_count; p++) - g_QglTable.m_pfn_qglVertex3fv(portals.portal[portals.portal_sort[n]].point[p].p); - - g_QglTable.m_pfn_qglEnd(); - } - } - else - { - for(n = 0; n < portals.portal_count; n++) - { - if(portals.polygons == 2 && !portals.portal[n].hint) - continue; - - if(portals.clip) - { - if(min_check[0] < portals.portal[n].min[0]) - continue; - else if(min_check[1] < portals.portal[n].min[1]) - continue; - else if(min_check[2] < portals.portal[n].min[2]) - continue; - else if(max_check[0] > portals.portal[n].max[0]) - continue; - else if(max_check[1] > portals.portal[n].max[1]) - continue; - else if(max_check[2] > portals.portal[n].max[2]) - continue; - } - - g_QglTable.m_pfn_qglColor4f(portals.portal[n].fp_color_random[0], portals.portal[n].fp_color_random[1], - portals.portal[n].fp_color_random[2], trans); - - g_QglTable.m_pfn_qglBegin(GL_POLYGON); - - for(p = 0; p < portals.portal[n].point_count; p++) - g_QglTable.m_pfn_qglVertex3fv(portals.portal[n].point[p].p); - - g_QglTable.m_pfn_qglEnd(); - } - } - } - - if(portals.lines) - { - g_QglTable.m_pfn_qglColor4fv(portals.fp_color_3d); - - for(n = 0; n < portals.portal_count; n++) - { - if(portals.lines == 2 && !portals.portal[n].hint) - continue; - - if(portals.clip) - { - if(min_check[0] < portals.portal[n].min[0]) - continue; - else if(min_check[1] < portals.portal[n].min[1]) - continue; - else if(min_check[2] < portals.portal[n].min[2]) - continue; - else if(max_check[0] > portals.portal[n].max[0]) - continue; - else if(max_check[1] > portals.portal[n].max[1]) - continue; - else if(max_check[2] > portals.portal[n].max[2]) - continue; - } - - g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP); - - for(p = 0; p < portals.portal[n].point_count; p++) - g_QglTable.m_pfn_qglVertex3fv(portals.portal[n].inner_point[p].p); - - g_QglTable.m_pfn_qglEnd(); - } - } - - g_QglTable.m_pfn_qglPopAttrib(); -} - +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +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 +*/ + +#include "stdafx.h" +#include +#include +#ifndef __APPLE__ +#include +#endif +#include + +#define LINE_BUF 1000 + +CPortals portals; +CPortalsRender render; + +int compare( const void *arg1, const void *arg2 ) +{ + + if(portals.portal[*((int *)arg1)].dist > portals.portal[*((int *)arg2)].dist) + return -1; + else if(portals.portal[*((int *)arg1)].dist < portals.portal[*((int *)arg2)].dist) + return 1; + + return 0; +} + + +CBspPortal::CBspPortal() +{ + memset(this, 0, sizeof(CBspPortal)); +} + +CBspPortal::~CBspPortal() +{ + delete[] point; + delete[] inner_point; +} + +qboolean CBspPortal::Build(char *def) +{ + char *c = def; + unsigned int n; + int dummy1, dummy2; + int res_cnt, i; + + if(portals.hint_flags) + { + res_cnt = sscanf(def, "%u %d %d %d", &point_count, &dummy1, &dummy2, (int *)&hint); + } + else + { + sscanf(def, "%u", &point_count); + hint = FALSE; + } + + if(point_count < 3 || (portals.hint_flags && res_cnt < 4)) + return FALSE; + + point = new CBspPoint[point_count]; + inner_point = new CBspPoint[point_count]; + + for(n = 0; n < point_count; n++) + { + for(; *c != 0 && *c != '('; c++); + + if(*c == 0) + return FALSE; + + c++; + + sscanf(c, "%f %f %f", point[n].p, point[n].p+1, point[n].p+2); + + center.p[0] += point[n].p[0]; + center.p[1] += point[n].p[1]; + center.p[2] += point[n].p[2]; + + if(n == 0) + { + for(i = 0; i < 3; i++) + { + min[i] = point[n].p[i]; + max[i] = point[n].p[i]; + } + } + else + { + for(i = 0; i < 3; i++) + { + if(min[i] > point[n].p[i]) + min[i] = point[n].p[i]; + if(max[i] < point[n].p[i]) + max[i] = point[n].p[i]; + } + } + } + + center.p[0] /= (float)point_count; + center.p[1] /= (float)point_count; + center.p[2] /= (float)point_count; + + for(n = 0; n < point_count; n++) + { + inner_point[n].p[0] = (0.01f * center.p[0]) + (0.99f * point[n].p[0]); + inner_point[n].p[1] = (0.01f * center.p[1]) + (0.99f * point[n].p[1]); + inner_point[n].p[2] = (0.01f * center.p[2]) + (0.99f * point[n].p[2]); + } + + fp_color_random[0] = (float)(rand() & 0xff) / 255.0f; + fp_color_random[1] = (float)(rand() & 0xff) / 255.0f; + fp_color_random[2] = (float)(rand() & 0xff) / 255.0f; + fp_color_random[3] = 1.0f; + + return TRUE; +} + +CPortals::CPortals() +{ + memset(this, 0, sizeof(CPortals)); +} + +CPortals::~CPortals() +{ + Purge(); +} + +void CPortals::Purge() +{ + delete[] portal; + delete[] portal_sort; + portal = NULL; + portal_sort = NULL; + portal_count = 0; + + /* + delete[] node; + node = NULL; + node_count = 0; + */ +} + +void CPortals::Load() +{ + char buf[LINE_BUF+1]; + + memset(buf, 0, LINE_BUF + 1); + + Purge(); + + Sys_Printf(MSG_PREFIX "Loading portal file %s.\n", fn); + + FILE *in; + + in = fopen(fn, "rt"); + + if(in == NULL) + { + Sys_Printf(" ERROR - could not open file.\n"); + + return; + } + + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + if(strncmp("PRT1", buf, 4) != 0) + { + fclose(in); + + Sys_Printf(" ERROR - File header indicates wrong file type (should be \"PRT1\").\n"); + + return; + } + + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + sscanf(buf, "%u", &node_count); +/* + if(node_count > 0xFFFF) + { + fclose(in); + + node_count = 0; + + Sys_Printf(" ERROR - Extreme number of nodes, aborting.\n"); + + return; + } + */ + + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + node_count = 0; + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + sscanf(buf, "%u", &portal_count); + + if(portal_count > 0xFFFF) + { + fclose(in); + + portal_count = 0; + node_count = 0; + + Sys_Printf(" ERROR - Extreme number of portals, aborting.\n"); + + return; + } + + if(portal_count < 0) + { + fclose(in); + + portal_count = 0; + node_count = 0; + + Sys_Printf(" ERROR - number of portals equals 0, aborting.\n"); + + return; + } + +// node = new CBspNode[node_count]; + portal = new CBspPortal[portal_count]; + portal_sort = new int[portal_count]; + + unsigned int n; + qboolean first = TRUE; + unsigned test_vals_1, test_vals_2; + + hint_flags = FALSE; + + for(n = 0; n < portal_count; ) + { + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + Purge(); + + Sys_Printf(" ERROR - Could not find information for portal number %d of %d.\n", n + 1, portal_count); + + return; + } + + if(!portal[n].Build(buf)) + { + if(first && sscanf(buf, "%d %d", &test_vals_1, &test_vals_2) == 1) // skip additional counts of later data, not needed + { + // We can count on hint flags being in the file + hint_flags = TRUE; + continue; + } + + first = FALSE; + + fclose(in); + + Purge(); + + Sys_Printf(" ERROR - Information for portal number %d of %d is not formatted correctly.\n", n + 1, portal_count); + + return; + } + + n++; + } + + fclose(in); + + Sys_Printf(" %u portals read in.\n", node_count, portal_count); +} + +void CPortals::FixColors() +{ + fp_color_2d[0] = (float)GetRValue(color_2d) / 255.0f; + fp_color_2d[1] = (float)GetGValue(color_2d) / 255.0f; + fp_color_2d[2] = (float)GetBValue(color_2d) / 255.0f; + fp_color_2d[3] = 1.0f; + + fp_color_3d[0] = (float)GetRValue(color_3d) / 255.0f; + fp_color_3d[1] = (float)GetGValue(color_3d) / 255.0f; + fp_color_3d[2] = (float)GetBValue(color_3d) / 255.0f; + fp_color_3d[3] = 1.0f; + + fp_color_fog[0] = 0.0f;//(float)GetRValue(color_fog) / 255.0f; + fp_color_fog[1] = 0.0f;//(float)GetGValue(color_fog) / 255.0f; + fp_color_fog[2] = 0.0f;//(float)GetBValue(color_fog) / 255.0f; + fp_color_fog[3] = 1.0f; +} + +CPortalsRender::CPortalsRender() +{ + refCount = 1; +} + +CPortalsRender::~CPortalsRender() +{ +} + +void CPortalsRender::Register() +{ + g_QglTable.m_pfnHookGL2DWindow( this ); + g_QglTable.m_pfnHookGL3DWindow( this ); +} + +void CPortalsRender::Draw2D( VIEWTYPE vt ) +{ + if(!portals.show_2d || portals.portal_count < 1) + return; + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + if(portals.aa_2d) + { + g_QglTable.m_pfn_qglEnable(GL_BLEND); + g_QglTable.m_pfn_qglEnable(GL_LINE_SMOOTH); + } + else + { + g_QglTable.m_pfn_qglDisable(GL_BLEND); + g_QglTable.m_pfn_qglEnable(GL_LINE_SMOOTH); + } + + 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(portals.width_2d * 0.5f); + + g_QglTable.m_pfn_qglColor4fv(portals.fp_color_2d); + + unsigned int n, p; + + for(n = 0; n < portals.portal_count; n++) + { + g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP); + + for(p = 0; p < portals.portal[n].point_count; p++) + g_QglTable.m_pfn_qglVertex3fv(portals.portal[n].point[p].p); + + g_QglTable.m_pfn_qglEnd(); + } + + g_QglTable.m_pfn_qglPopAttrib(); +} + +/* + * Transform a point (column vector) by a 4x4 matrix. I.e. out = m * in + * Input: m - the 4x4 matrix + * in - the 4x1 vector + * Output: out - the resulting 4x1 vector. + */ +static void transform_point( GLdouble out[4], const GLdouble m[16], + const GLdouble in[4] ) +{ +#define M(row,col) m[col*4+row] + out[0] = M(0,0) * in[0] + M(0,1) * in[1] + M(0,2) * in[2] + M(0,3) * in[3]; + out[1] = M(1,0) * in[0] + M(1,1) * in[1] + M(1,2) * in[2] + M(1,3) * in[3]; + out[2] = M(2,0) * in[0] + M(2,1) * in[1] + M(2,2) * in[2] + M(2,3) * in[3]; + out[3] = M(3,0) * in[0] + M(3,1) * in[1] + M(3,2) * in[2] + M(3,3) * in[3]; +#undef M +} + +#include + + +/* + * Perform a 4x4 matrix multiplication (product = a x b). + * Input: a, b - matrices to multiply + * Output: product - product of a and b + */ +static void matmul( GLdouble *product, const GLdouble *a, const GLdouble *b ) +{ + /* This matmul was contributed by Thomas Malik */ + GLdouble temp[16]; + GLint i; + +#define A(row,col) a[(col<<2)+row] +#define B(row,col) b[(col<<2)+row] +#define T(row,col) temp[(col<<2)+row] + + /* i-te Zeile */ + for (i = 0; i < 4; i++) + { + T(i, 0) = A(i, 0) * B(0, 0) + A(i, 1) * B(1, 0) + A(i, 2) * B(2, 0) + A(i, 3) * B(3, 0); + T(i, 1) = A(i, 0) * B(0, 1) + A(i, 1) * B(1, 1) + A(i, 2) * B(2, 1) + A(i, 3) * B(3, 1); + T(i, 2) = A(i, 0) * B(0, 2) + A(i, 1) * B(1, 2) + A(i, 2) * B(2, 2) + A(i, 3) * B(3, 2); + T(i, 3) = A(i, 0) * B(0, 3) + A(i, 1) * B(1, 3) + A(i, 2) * B(2, 3) + A(i, 3) * B(3, 3); + } + +#undef A +#undef B +#undef T + memcpy ( product, temp, 16*sizeof(GLdouble) ); +} + + + +/* + * Compute inverse of 4x4 transformation matrix. + * Code contributed by Jacques Leroy jle@star.be + * Return GL_TRUE for success, GL_FALSE for failure (singular matrix) + */ +static GLboolean invert_matrix( const GLdouble *m, GLdouble *out ) +{ +/* NB. OpenGL Matrices are COLUMN major. */ +#define SWAP_ROWS(a, b) { GLdouble *_tmp = a; (a)=(b); (b)=_tmp; } +#define MAT(m,r,c) (m)[(c)*4+(r)] + + GLdouble wtmp[4][8]; + GLdouble m0, m1, m2, m3, s; + GLdouble *r0, *r1, *r2, *r3; + + r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3]; + + r0[0] = MAT(m,0,0), r0[1] = MAT(m,0,1), + r0[2] = MAT(m,0,2), r0[3] = MAT(m,0,3), + r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0, + + r1[0] = MAT(m,1,0), r1[1] = MAT(m,1,1), + r1[2] = MAT(m,1,2), r1[3] = MAT(m,1,3), + r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0, + + r2[0] = MAT(m,2,0), r2[1] = MAT(m,2,1), + r2[2] = MAT(m,2,2), r2[3] = MAT(m,2,3), + r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0, + + r3[0] = MAT(m,3,0), r3[1] = MAT(m,3,1), + r3[2] = MAT(m,3,2), r3[3] = MAT(m,3,3), + r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0; + + /* choose pivot - or die */ + if (fabs(r3[0])>fabs(r2[0])) SWAP_ROWS(r3, r2); + if (fabs(r2[0])>fabs(r1[0])) SWAP_ROWS(r2, r1); + if (fabs(r1[0])>fabs(r0[0])) SWAP_ROWS(r1, r0); + if (0.0 == r0[0]) return GL_FALSE; + + /* eliminate first variable */ + m1 = r1[0]/r0[0]; m2 = r2[0]/r0[0]; m3 = r3[0]/r0[0]; + s = r0[1]; r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s; + s = r0[2]; r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s; + s = r0[3]; r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s; + s = r0[4]; + if (s != 0.0) { r1[4] -= m1 * s; r2[4] -= m2 * s; r3[4] -= m3 * s; } + s = r0[5]; + if (s != 0.0) { r1[5] -= m1 * s; r2[5] -= m2 * s; r3[5] -= m3 * s; } + s = r0[6]; + if (s != 0.0) { r1[6] -= m1 * s; r2[6] -= m2 * s; r3[6] -= m3 * s; } + s = r0[7]; + if (s != 0.0) { r1[7] -= m1 * s; r2[7] -= m2 * s; r3[7] -= m3 * s; } + + /* choose pivot - or die */ + if (fabs(r3[1])>fabs(r2[1])) SWAP_ROWS(r3, r2); + if (fabs(r2[1])>fabs(r1[1])) SWAP_ROWS(r2, r1); + if (0.0 == r1[1]) return GL_FALSE; + + /* eliminate second variable */ + m2 = r2[1]/r1[1]; m3 = r3[1]/r1[1]; + r2[2] -= m2 * r1[2]; r3[2] -= m3 * r1[2]; + r2[3] -= m2 * r1[3]; r3[3] -= m3 * r1[3]; + s = r1[4]; if (0.0 != s) { r2[4] -= m2 * s; r3[4] -= m3 * s; } + s = r1[5]; if (0.0 != s) { r2[5] -= m2 * s; r3[5] -= m3 * s; } + s = r1[6]; if (0.0 != s) { r2[6] -= m2 * s; r3[6] -= m3 * s; } + s = r1[7]; if (0.0 != s) { r2[7] -= m2 * s; r3[7] -= m3 * s; } + + /* choose pivot - or die */ + if (fabs(r3[2])>fabs(r2[2])) SWAP_ROWS(r3, r2); + if (0.0 == r2[2]) return GL_FALSE; + + /* eliminate third variable */ + m3 = r3[2]/r2[2]; + r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4], + r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6], + r3[7] -= m3 * r2[7]; + + /* last check */ + if (0.0 == r3[3]) return GL_FALSE; + + s = 1.0/r3[3]; /* now back substitute row 3 */ + r3[4] *= s; r3[5] *= s; r3[6] *= s; r3[7] *= s; + + m2 = r2[3]; /* now back substitute row 2 */ + s = 1.0/r2[2]; + r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2), + r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2); + m1 = r1[3]; + r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1, + r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1; + m0 = r0[3]; + r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0, + r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0; + + m1 = r1[2]; /* now back substitute row 1 */ + s = 1.0/r1[1]; + r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1), + r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1); + m0 = r0[2]; + r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0, + r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0; + + m0 = r0[1]; /* now back substitute row 0 */ + s = 1.0/r0[0]; + r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0), + r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0); + + MAT(out,0,0) = r0[4]; MAT(out,0,1) = r0[5], + MAT(out,0,2) = r0[6]; MAT(out,0,3) = r0[7], + MAT(out,1,0) = r1[4]; MAT(out,1,1) = r1[5], + MAT(out,1,2) = r1[6]; MAT(out,1,3) = r1[7], + MAT(out,2,0) = r2[4]; MAT(out,2,1) = r2[5], + MAT(out,2,2) = r2[6]; MAT(out,2,3) = r2[7], + MAT(out,3,0) = r3[4]; MAT(out,3,1) = r3[5], + MAT(out,3,2) = r3[6]; MAT(out,3,3) = r3[7]; + + return GL_TRUE; + +#undef MAT +#undef SWAP_ROWS +} + +GLint UnProject(GLdouble winx,GLdouble winy,GLdouble winz, + const GLdouble model[16],const GLdouble proj[16], + const GLint viewport[4], + GLdouble *objx,GLdouble *objy,GLdouble *objz) +{ + /* matrice de transformation */ + GLdouble m[16], A[16]; + GLdouble in[4],out[4]; + + /* transformation coordonnees normalisees entre -1 et 1 */ + in[0]=(winx-viewport[0])*2/viewport[2] - 1.0; + in[1]=(winy-viewport[1])*2/viewport[3] - 1.0; + in[2]=2*winz - 1.0; + in[3]=1.0; + + /* calcul transformation inverse */ + matmul(A,proj,model); + invert_matrix(A,m); + + /* d'ou les coordonnees objets */ + transform_point(out,m,in); + if (out[3]==0.0) + return GL_FALSE; + *objx=out[0]/out[3]; + *objy=out[1]/out[3]; + *objz=out[2]/out[3]; + return GL_TRUE; +} + +void CPortalsRender::Draw3D() +{ + if(!portals.show_3d || portals.portal_count < 1) + return; + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + double cam[3]; + double proj_m[16]; + double model_m[16]; + float min_check[3]; + float max_check[3]; + float trans = (100.0f - portals.trans_3d) / 100.0f; + int view[4]; + + g_QglTable.m_pfn_qglGetDoublev(GL_PROJECTION_MATRIX, proj_m); + g_QglTable.m_pfn_qglGetDoublev(GL_MODELVIEW_MATRIX, model_m); + g_QglTable.m_pfn_qglGetIntegerv(GL_VIEWPORT, view); + + UnProject(0.5 * (double)view[2], 0.5 * (double)view[3], 0.0, model_m, proj_m, view, cam, cam+1, cam+2); + + min_check[0] = (float)cam[0] + (portals.clip_range * 64.0f); + min_check[1] = (float)cam[1] + (portals.clip_range * 64.0f); + min_check[2] = (float)cam[2] + (portals.clip_range * 64.0f); + max_check[0] = (float)cam[0] - (portals.clip_range * 64.0f); + max_check[1] = (float)cam[1] - (portals.clip_range * 64.0f); + max_check[2] = (float)cam[2] - (portals.clip_range * 64.0f); + + g_QglTable.m_pfn_qglHint(GL_FOG_HINT, GL_NICEST); + + g_QglTable.m_pfn_qglDisable(GL_CULL_FACE); + + g_QglTable.m_pfn_qglDisable(GL_LINE_SMOOTH); + g_QglTable.m_pfn_qglDisable(GL_POLYGON_SMOOTH); + + g_QglTable.m_pfn_qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + g_QglTable.m_pfn_qglShadeModel(GL_SMOOTH); + + g_QglTable.m_pfn_qglEnable(GL_BLEND); + g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + g_QglTable.m_pfn_qglEnable(GL_POLYGON_SMOOTH); + + if(portals.aa_3d) + g_QglTable.m_pfn_qglEnable(GL_LINE_SMOOTH); + else + g_QglTable.m_pfn_qglDisable(GL_LINE_SMOOTH); + + if(portals.fog) + { + g_QglTable.m_pfn_qglEnable(GL_FOG); + + g_QglTable.m_pfn_qglFogi(GL_FOG_MODE, GL_EXP); + g_QglTable.m_pfn_qglFogf(GL_FOG_DENSITY, 0.001f); + g_QglTable.m_pfn_qglFogf(GL_FOG_START, 10.0f); + g_QglTable.m_pfn_qglFogf(GL_FOG_END, 10000.0f); + g_QglTable.m_pfn_qglFogi(GL_FOG_INDEX, 0); + g_QglTable.m_pfn_qglFogfv(GL_FOG_COLOR, portals.fp_color_fog); + } + else + { + g_QglTable.m_pfn_qglDisable(GL_FOG); + } + + switch(portals.zbuffer) + { + case 1: + g_QglTable.m_pfn_qglEnable(GL_DEPTH_TEST); + g_QglTable.m_pfn_qglDepthMask(GL_FALSE); + break; + case 2: + g_QglTable.m_pfn_qglDisable(GL_DEPTH_TEST); + break; + default: + g_QglTable.m_pfn_qglEnable(GL_DEPTH_TEST); + g_QglTable.m_pfn_qglDepthMask(GL_TRUE); + } + + g_QglTable.m_pfn_qglLineWidth(portals.width_3d * 0.5f); + + unsigned int n, p; + + if(portals.polygons) + { + if(portals.zbuffer != 0) + { + float d; + + for(n = 0; n < portals.portal_count; n++) + { + d = (float)cam[0] - portals.portal[n].center.p[0]; + portals.portal[n].dist = d * d; + + d = (float)cam[1] - portals.portal[n].center.p[1]; + portals.portal[n].dist += d * d; + + d = (float)cam[2] - portals.portal[n].center.p[2]; + portals.portal[n].dist += d * d; + + portals.portal_sort[n] = n; + } + + qsort(portals.portal_sort, portals.portal_count, 4, compare); + + for(n = 0; n < portals.portal_count; n++) + { + if(portals.polygons == 2 && !portals.portal[portals.portal_sort[n]].hint) + continue; + + if(portals.clip) + { + if(min_check[0] < portals.portal[portals.portal_sort[n]].min[0]) + continue; + else if(min_check[1] < portals.portal[portals.portal_sort[n]].min[1]) + continue; + else if(min_check[2] < portals.portal[portals.portal_sort[n]].min[2]) + continue; + else if(max_check[0] > portals.portal[portals.portal_sort[n]].max[0]) + continue; + else if(max_check[1] > portals.portal[portals.portal_sort[n]].max[1]) + continue; + else if(max_check[2] > portals.portal[portals.portal_sort[n]].max[2]) + continue; + } + + g_QglTable.m_pfn_qglColor4f(portals.portal[portals.portal_sort[n]].fp_color_random[0], portals.portal[portals.portal_sort[n]].fp_color_random[1], + portals.portal[portals.portal_sort[n]].fp_color_random[2], trans); + + g_QglTable.m_pfn_qglBegin(GL_POLYGON); + + for(p = 0; p < portals.portal[portals.portal_sort[n]].point_count; p++) + g_QglTable.m_pfn_qglVertex3fv(portals.portal[portals.portal_sort[n]].point[p].p); + + g_QglTable.m_pfn_qglEnd(); + } + } + else + { + for(n = 0; n < portals.portal_count; n++) + { + if(portals.polygons == 2 && !portals.portal[n].hint) + continue; + + if(portals.clip) + { + if(min_check[0] < portals.portal[n].min[0]) + continue; + else if(min_check[1] < portals.portal[n].min[1]) + continue; + else if(min_check[2] < portals.portal[n].min[2]) + continue; + else if(max_check[0] > portals.portal[n].max[0]) + continue; + else if(max_check[1] > portals.portal[n].max[1]) + continue; + else if(max_check[2] > portals.portal[n].max[2]) + continue; + } + + g_QglTable.m_pfn_qglColor4f(portals.portal[n].fp_color_random[0], portals.portal[n].fp_color_random[1], + portals.portal[n].fp_color_random[2], trans); + + g_QglTable.m_pfn_qglBegin(GL_POLYGON); + + for(p = 0; p < portals.portal[n].point_count; p++) + g_QglTable.m_pfn_qglVertex3fv(portals.portal[n].point[p].p); + + g_QglTable.m_pfn_qglEnd(); + } + } + } + + if(portals.lines) + { + g_QglTable.m_pfn_qglColor4fv(portals.fp_color_3d); + + for(n = 0; n < portals.portal_count; n++) + { + if(portals.lines == 2 && !portals.portal[n].hint) + continue; + + if(portals.clip) + { + if(min_check[0] < portals.portal[n].min[0]) + continue; + else if(min_check[1] < portals.portal[n].min[1]) + continue; + else if(min_check[2] < portals.portal[n].min[2]) + continue; + else if(max_check[0] > portals.portal[n].max[0]) + continue; + else if(max_check[1] > portals.portal[n].max[1]) + continue; + else if(max_check[2] > portals.portal[n].max[2]) + continue; + } + + g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP); + + for(p = 0; p < portals.portal[n].point_count; p++) + g_QglTable.m_pfn_qglVertex3fv(portals.portal[n].inner_point[p].p); + + g_QglTable.m_pfn_qglEnd(); + } + } + + g_QglTable.m_pfn_qglPopAttrib(); +} + diff --git a/contrib/prtview/prtview.cpp b/contrib/prtview/prtview.cpp index 842b9d85..43960970 100644 --- a/contrib/prtview/prtview.cpp +++ b/contrib/prtview/prtview.cpp @@ -1,548 +1,548 @@ -/* -PrtView plugin for GtkRadiant -Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com - -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 -*/ - -// PrtView.cpp : Defines the initialization routines for the DLL. -// - -#include "stdafx.h" -#include -#include - -#define Q3R_CMD_SPLITTER "-" -#define Q3R_CMD_ABOUT "About Portal Viewer" -#define Q3R_CMD_LOAD "Load .prt file" -#define Q3R_CMD_RELEASE "Unload .prt file" -#define Q3R_CMD_SHOW_3D "Toggle portals (3D)" -#define Q3R_CMD_SHOW_2D "Toggle portals (2D)" -#define Q3R_CMD_OPTIONS "Configure Portal Viewer" - -static char INIfn[NAME_MAX]; - -///////////////////////////////////////////////////////////////////////////// -// CPrtViewApp construction - -#define RENDER_2D "Render2D" -#define WIDTH_2D "Width2D" -#define AA_2D "AntiAlias2D" -#define COLOR_2D "Color2D" - -#define RENDER_3D "Render3D" -#define WIDTH_3D "Width3D" -#define AA_3D "AntiAlias3D" -#define COLOR_3D "Color3D" -#define COLOR_FOG "ColorFog" -#define FOG "Fog" -#define ZBUFFER "ZBuffer" -#define POLYGON "Polygons" -#define LINE "Lines" -#define TRANS_3D "Transparency" -#define CLIP_RANGE "ClipRange" -#define CLIP "Clip" - -void InitInstance () -{ -#ifdef _WIN32 - char fn[_MAX_PATH]; - char fn_drive[_MAX_DRIVE]; - char fn_dir[_MAX_DIR]; - char fn_name[_MAX_FNAME]; - char fn_ext[_MAX_EXT]; - - GetModuleFileName(GetModuleHandle("PrtView.dll"), fn, _MAX_PATH); - - _splitpath(fn, fn_drive, fn_dir, fn_name, fn_ext); - - strcpy(INIfn, fn_drive); - strcat(INIfn, fn_dir); - strcat(INIfn, fn_name); - strcat(INIfn, ".ini"); -#else // if def __linux__ - strcpy (INIfn, g_get_home_dir ()); - strcat (INIfn, "/.radiant/"); - strcat (INIfn, RADIANT_VERSION); - strcat (INIfn, "/prtview.ini"); -#endif - - portals.show_2d = INIGetInt(RENDER_2D, FALSE) ? true : false; - portals.aa_2d = INIGetInt(AA_2D, FALSE) ? true : false; - portals.width_2d = (float)INIGetInt(WIDTH_2D, 10); - portals.color_2d = (COLORREF)INIGetInt(COLOR_2D, RGB(0, 0, 255)) & 0xFFFFFF; - - if (portals.width_2d > 40.0f) - portals.width_2d = 40.0f; - else if (portals.width_2d < 2.0f) - portals.width_2d = 2.0f; - - portals.show_3d = INIGetInt(RENDER_3D, TRUE) ? true : false; - - portals.zbuffer = INIGetInt(ZBUFFER, 1); - portals.fog = INIGetInt(FOG, FALSE) ? true : false; - portals.polygons = INIGetInt(POLYGON, TRUE); - portals.lines = INIGetInt(LINE, TRUE); - portals.aa_3d = INIGetInt(AA_3D, FALSE) ? true : false; - portals.width_3d = (float)INIGetInt(WIDTH_3D, 4); - portals.color_3d = (COLORREF)INIGetInt(COLOR_3D, RGB(255, 255, 0)) & 0xFFFFFF; - portals.color_fog = (COLORREF)INIGetInt(COLOR_FOG, RGB(127, 127, 127)) & 0xFFFFFF; - portals.trans_3d = (float)INIGetInt(TRANS_3D, 50); - portals.clip = INIGetInt(CLIP, FALSE) ? true : false; - portals.clip_range = (float)INIGetInt(CLIP_RANGE, 16); - - if (portals.clip_range < 1) - portals.clip_range = 1; - else if (portals.clip_range > 128) - portals.clip_range = 128; - - if (portals.zbuffer < 0) - portals.zbuffer = 0; - else if (portals.zbuffer > 2) - portals.zbuffer = 0; - - if (portals.width_3d > 40.0f) - portals.width_3d = 40.0f; - else if (portals.width_3d < 2.0f) - portals.width_3d = 2.0f; - - if (portals.trans_3d > 100.0f) - portals.trans_3d = 100.0f; - else if (portals.trans_3d < 0.0f) - portals.trans_3d = 0.0f; - - SaveConfig(); - - portals.FixColors(); -} - -void SaveConfig () -{ - INISetInt(RENDER_2D, portals.show_2d, "Draw in 2D windows"); - INISetInt(WIDTH_2D, (int)portals.width_2d, "Width of lines in 2D windows (in units of 1/2)"); - INISetInt(COLOR_2D, (int)portals.color_2d, "Color of lines in 2D windows"); - INISetInt(AA_2D, portals.aa_2d, "Draw lines in 2D window anti-aliased"); - - INISetInt(ZBUFFER, portals.zbuffer, "ZBuffer level in 3D window"); - INISetInt(FOG, portals.fog, "Use depth cueing in 3D window"); - INISetInt(POLYGON, portals.polygons, "Render using polygons polygons in 3D window"); - INISetInt(LINE, portals.polygons, "Render using lines in 3D window"); - INISetInt(RENDER_3D, portals.show_3d, "Draw in 3D windows"); - INISetInt(WIDTH_3D, (int)portals.width_3d, "Width of lines in 3D window (in units of 1/2)"); - INISetInt(COLOR_3D, (int)portals.color_3d, "Color of lines/polygons in 3D window"); - INISetInt(COLOR_FOG, (int)portals.color_fog, "Color of distant lines/polygons in 3D window"); - INISetInt(AA_3D, portals.aa_3d, "Draw lines in 3D window anti-aliased"); - INISetInt(TRANS_3D, (int)portals.trans_3d, "Transparency in 3d view (0 = solid, 100 = invisible)"); - INISetInt(CLIP, portals.clip, "Cubic clipper active for portal viewer"); - INISetInt(CLIP_RANGE, (int)portals.clip_range, "Portal viewer cubic clip distance (in units of 64)"); -} - -// Radiant function table -// use to access what Radiant provides -_QERFuncTable_1 g_FuncTable; -_QERQglTable g_QglTable; - -#define CONFIG_SECTION "Configuration" - -#if defined(__linux__) || defined(__APPLE__) - -static bool read_var (const char *filename, const char *section, const char *key, char *value) -{ - char line[1024], *ptr; - FILE *rc; - - rc = fopen (filename, "rt"); - - if (rc == NULL) - return false; - - while (fgets (line, 1024, rc) != 0) - { - // First we find the section - if (line[0] != '[') - continue; - - ptr = strchr (line, ']'); - *ptr = '\0'; - - if (strcmp (&line[1], section) == 0) - { - while (fgets (line, 1024, rc) != 0) - { - ptr = strchr (line, '='); - - if (ptr == NULL) - { - // reached the end of the section - fclose (rc); - return false; - } - *ptr = '\0'; - - if (strcmp (line, key) == 0) - { - strcpy (value, ptr+1); - fclose (rc); - - while (value[strlen (value)-1] == 10 || - value[strlen (value)-1] == 13 || - value[strlen (value)-1] == 32) - value[strlen (value)-1] = 0; - return true; - } - } - } - } - - fclose (rc); - return false; -} - -static bool save_var (const char *filename, const char *section, const char *key, const char *value) -{ - char line[1024], *ptr; - FILE *old_rc = NULL, *rc; - bool found; - - rc = fopen (filename, "rb"); - - if (rc != NULL) - { - guint32 len; - void *buf; - - char *tmpname = g_strdup_printf ("%s.tmp", filename); - old_rc = fopen (tmpname, "w+b"); - g_free (tmpname); - - fseek (rc, 0, SEEK_END); - len = ftell (rc); - rewind (rc); - buf = g_malloc (len); - fread (buf, len, 1, rc); - fwrite (buf, len, 1, old_rc); - g_free (buf); - fclose (rc); - rewind (old_rc); - } - - rc = fopen (filename, "wb"); - - if (rc == NULL) - return false; - - // First we need to find the section - found = false; - if (old_rc != NULL) - while (fgets (line, 1024, old_rc) != NULL) - { - fputs (line, rc); - - if (line[0] == '[') - { - ptr = strchr (line, ']'); - *ptr = '\0'; - - if (strcmp (&line[1], section) == 0) - { - found = true; - break; - } - } - } - - if (!found) - { - fputs ("\n", rc); - fprintf (rc, "[%s]\n", section); - } - - fprintf (rc, "%s=%s\n", key, value); - - if (old_rc != NULL) - { - while (fgets (line, 1024, old_rc) != NULL) - { - ptr = strchr (line, '='); - - if (ptr != NULL) - { - *ptr = '\0'; - - if (strcmp (line, key) == 0) - break; - - *ptr = '='; - fputs (line, rc); - } - else - { - fputs (line, rc); - break; - } - } - - while (fgets (line, 1024, old_rc) != NULL) - fputs (line, rc); - - fclose (old_rc); - - char *tmpname = g_strdup_printf ("%s.tmp", filename); - remove (tmpname); - g_free (tmpname); - } - - fclose (rc); - - return true; -} - -#endif - -int INIGetInt(char *key, int def) -{ -#if defined(__linux__) || defined(__APPLE__) - char value[1024]; - - if (read_var (INIfn, CONFIG_SECTION, key, value)) - return atoi (value); - else - return def; -#else - return GetPrivateProfileInt(CONFIG_SECTION, key, def, INIfn); -#endif -} - -void INISetInt(char *key, int val, char *comment /* = NULL */) -{ - char s[1000]; - - if(comment) - sprintf(s, "%d ; %s", val, comment); - else - sprintf(s, "%d", val); -#if defined(__linux__) || defined(__APPLE__) - save_var (INIfn, CONFIG_SECTION, key, s); -#else - WritePrivateProfileString(CONFIG_SECTION, key, s, INIfn); -#endif -} - - -// plugin name -static const char *PLUGIN_NAME = "Portal Viewer"; -// commands in the menu -static const char *PLUGIN_COMMANDS = - Q3R_CMD_ABOUT ";" - Q3R_CMD_SPLITTER ";" - Q3R_CMD_OPTIONS ";" - Q3R_CMD_SPLITTER ";" - Q3R_CMD_SHOW_2D ";" - Q3R_CMD_SHOW_3D ";" - Q3R_CMD_SPLITTER ";" - Q3R_CMD_RELEASE ";" - Q3R_CMD_LOAD; - -extern "C" LPVOID WINAPI QERPlug_GetFuncTable() -{ - return &g_FuncTable; -} - - -//extern "C" LPCSTR WINAPI QERPlug_Init (HMODULE hApp, GtkWidget* hwndMain) -extern "C" const char* QERPlug_Init (void *hApp, void* pMainWidget) -{ - // Setup defaults & load config - InitInstance(); - - return "Portal Viewer for Q3Radiant"; -} - -extern "C" const char* QERPlug_GetName() -{ - return (char*)PLUGIN_NAME; -} - -extern "C" const char* QERPlug_GetCommandList() -{ - return (char*)PLUGIN_COMMANDS; -} - -/* -void Sys_Printf (char *text, ...) -{ - va_list argptr; - char buf[32768]; - - va_start (argptr,text); - vsprintf (buf, text, argptr); - va_end (argptr); - - g_FuncTable.m_pfnSysMsg (buf); -} -*/ - -bool interfaces_started = false; - -static void CheckInterfaces() -{ - if (interfaces_started) - return; - - render.Register(); - - interfaces_started = true; -} - -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,Q3R_CMD_ABOUT)) - { - DoAboutDlg (); - } - else if (!strcmp(p,Q3R_CMD_LOAD)) - { - CheckInterfaces(); - - if (interfaces_started) - { - if (DoLoadPortalFileDialog () == IDOK) - { - portals.Load(); - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL); - } - else - { - Sys_Printf(MSG_PREFIX "Portal file load aborted.\n", portals.fn); - } - } - } - else if (!strcmp(p,Q3R_CMD_RELEASE)) - { - portals.Purge(); - - if (interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL); - - Sys_Printf(MSG_PREFIX "Portals unloaded.\n"); - } - else if (!strcmp(p,Q3R_CMD_SHOW_2D)) - { - portals.show_2d = !portals.show_2d; - - if(interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL); - SaveConfig(); - - if(portals.show_2d) - Sys_Printf(MSG_PREFIX "Portals will be rendered in 2D view.\n"); - else - Sys_Printf(MSG_PREFIX "Portals will NOT be rendered in 2D view.\n"); - } - else if (!strcmp(p,Q3R_CMD_SHOW_3D)) - { - portals.show_3d = !portals.show_3d; - SaveConfig(); - - if (interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL); - - if (portals.show_3d) - Sys_Printf(MSG_PREFIX "Portals will be rendered in 3D view.\n"); - else - Sys_Printf(MSG_PREFIX "Portals will NOT be rendered in 3D view.\n"); - } - else if (!strcmp(p,Q3R_CMD_OPTIONS)) - { - DoConfigDialog (); - SaveConfig(); - - if (interfaces_started) - g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL); - } -} - - - -// ============================================================================= -// SYNAPSE - -class CSynapseClientPrtView : public CSynapseClient -{ -public: - // CSynapseClient API - bool RequestAPI(APIDescriptor_t *pAPI); - const char* GetInfo(); - - CSynapseClientPrtView() { } - virtual ~CSynapseClientPrtView() { } -}; - - -CSynapseServer* g_pSynapseServer = NULL; -CSynapseClientPrtView 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(PLUGIN_MAJOR, PRTVIEW_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); - - return &g_SynapseClient; -} - -bool CSynapseClientPrtView::RequestAPI(APIDescriptor_t *pAPI) -{ - if( !strcmp(pAPI->major_name, PLUGIN_MAJOR) ) - { - if( !strcmp(pAPI->minor_name, PRTVIEW_MINOR) ) - { - _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; - } - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -#include "version.h" - -const char* CSynapseClientPrtView::GetInfo() -{ - return "PrtView module built " __DATE__ " " RADIANT_VERSION; -} +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +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 +*/ + +// PrtView.cpp : Defines the initialization routines for the DLL. +// + +#include "stdafx.h" +#include +#include + +#define Q3R_CMD_SPLITTER "-" +#define Q3R_CMD_ABOUT "About Portal Viewer" +#define Q3R_CMD_LOAD "Load .prt file" +#define Q3R_CMD_RELEASE "Unload .prt file" +#define Q3R_CMD_SHOW_3D "Toggle portals (3D)" +#define Q3R_CMD_SHOW_2D "Toggle portals (2D)" +#define Q3R_CMD_OPTIONS "Configure Portal Viewer" + +static char INIfn[NAME_MAX]; + +///////////////////////////////////////////////////////////////////////////// +// CPrtViewApp construction + +#define RENDER_2D "Render2D" +#define WIDTH_2D "Width2D" +#define AA_2D "AntiAlias2D" +#define COLOR_2D "Color2D" + +#define RENDER_3D "Render3D" +#define WIDTH_3D "Width3D" +#define AA_3D "AntiAlias3D" +#define COLOR_3D "Color3D" +#define COLOR_FOG "ColorFog" +#define FOG "Fog" +#define ZBUFFER "ZBuffer" +#define POLYGON "Polygons" +#define LINE "Lines" +#define TRANS_3D "Transparency" +#define CLIP_RANGE "ClipRange" +#define CLIP "Clip" + +void InitInstance () +{ +#ifdef _WIN32 + char fn[_MAX_PATH]; + char fn_drive[_MAX_DRIVE]; + char fn_dir[_MAX_DIR]; + char fn_name[_MAX_FNAME]; + char fn_ext[_MAX_EXT]; + + GetModuleFileName(GetModuleHandle("PrtView.dll"), fn, _MAX_PATH); + + _splitpath(fn, fn_drive, fn_dir, fn_name, fn_ext); + + strcpy(INIfn, fn_drive); + strcat(INIfn, fn_dir); + strcat(INIfn, fn_name); + strcat(INIfn, ".ini"); +#else // if def __linux__ + strcpy (INIfn, g_get_home_dir ()); + strcat (INIfn, "/.radiant/"); + strcat (INIfn, RADIANT_VERSION); + strcat (INIfn, "/prtview.ini"); +#endif + + portals.show_2d = INIGetInt(RENDER_2D, FALSE) ? true : false; + portals.aa_2d = INIGetInt(AA_2D, FALSE) ? true : false; + portals.width_2d = (float)INIGetInt(WIDTH_2D, 10); + portals.color_2d = (COLORREF)INIGetInt(COLOR_2D, RGB(0, 0, 255)) & 0xFFFFFF; + + if (portals.width_2d > 40.0f) + portals.width_2d = 40.0f; + else if (portals.width_2d < 2.0f) + portals.width_2d = 2.0f; + + portals.show_3d = INIGetInt(RENDER_3D, TRUE) ? true : false; + + portals.zbuffer = INIGetInt(ZBUFFER, 1); + portals.fog = INIGetInt(FOG, FALSE) ? true : false; + portals.polygons = INIGetInt(POLYGON, TRUE); + portals.lines = INIGetInt(LINE, TRUE); + portals.aa_3d = INIGetInt(AA_3D, FALSE) ? true : false; + portals.width_3d = (float)INIGetInt(WIDTH_3D, 4); + portals.color_3d = (COLORREF)INIGetInt(COLOR_3D, RGB(255, 255, 0)) & 0xFFFFFF; + portals.color_fog = (COLORREF)INIGetInt(COLOR_FOG, RGB(127, 127, 127)) & 0xFFFFFF; + portals.trans_3d = (float)INIGetInt(TRANS_3D, 50); + portals.clip = INIGetInt(CLIP, FALSE) ? true : false; + portals.clip_range = (float)INIGetInt(CLIP_RANGE, 16); + + if (portals.clip_range < 1) + portals.clip_range = 1; + else if (portals.clip_range > 128) + portals.clip_range = 128; + + if (portals.zbuffer < 0) + portals.zbuffer = 0; + else if (portals.zbuffer > 2) + portals.zbuffer = 0; + + if (portals.width_3d > 40.0f) + portals.width_3d = 40.0f; + else if (portals.width_3d < 2.0f) + portals.width_3d = 2.0f; + + if (portals.trans_3d > 100.0f) + portals.trans_3d = 100.0f; + else if (portals.trans_3d < 0.0f) + portals.trans_3d = 0.0f; + + SaveConfig(); + + portals.FixColors(); +} + +void SaveConfig () +{ + INISetInt(RENDER_2D, portals.show_2d, "Draw in 2D windows"); + INISetInt(WIDTH_2D, (int)portals.width_2d, "Width of lines in 2D windows (in units of 1/2)"); + INISetInt(COLOR_2D, (int)portals.color_2d, "Color of lines in 2D windows"); + INISetInt(AA_2D, portals.aa_2d, "Draw lines in 2D window anti-aliased"); + + INISetInt(ZBUFFER, portals.zbuffer, "ZBuffer level in 3D window"); + INISetInt(FOG, portals.fog, "Use depth cueing in 3D window"); + INISetInt(POLYGON, portals.polygons, "Render using polygons polygons in 3D window"); + INISetInt(LINE, portals.polygons, "Render using lines in 3D window"); + INISetInt(RENDER_3D, portals.show_3d, "Draw in 3D windows"); + INISetInt(WIDTH_3D, (int)portals.width_3d, "Width of lines in 3D window (in units of 1/2)"); + INISetInt(COLOR_3D, (int)portals.color_3d, "Color of lines/polygons in 3D window"); + INISetInt(COLOR_FOG, (int)portals.color_fog, "Color of distant lines/polygons in 3D window"); + INISetInt(AA_3D, portals.aa_3d, "Draw lines in 3D window anti-aliased"); + INISetInt(TRANS_3D, (int)portals.trans_3d, "Transparency in 3d view (0 = solid, 100 = invisible)"); + INISetInt(CLIP, portals.clip, "Cubic clipper active for portal viewer"); + INISetInt(CLIP_RANGE, (int)portals.clip_range, "Portal viewer cubic clip distance (in units of 64)"); +} + +// Radiant function table +// use to access what Radiant provides +_QERFuncTable_1 g_FuncTable; +_QERQglTable g_QglTable; + +#define CONFIG_SECTION "Configuration" + +#if defined(__linux__) || defined(__APPLE__) + +static bool read_var (const char *filename, const char *section, const char *key, char *value) +{ + char line[1024], *ptr; + FILE *rc; + + rc = fopen (filename, "rt"); + + if (rc == NULL) + return false; + + while (fgets (line, 1024, rc) != 0) + { + // First we find the section + if (line[0] != '[') + continue; + + ptr = strchr (line, ']'); + *ptr = '\0'; + + if (strcmp (&line[1], section) == 0) + { + while (fgets (line, 1024, rc) != 0) + { + ptr = strchr (line, '='); + + if (ptr == NULL) + { + // reached the end of the section + fclose (rc); + return false; + } + *ptr = '\0'; + + if (strcmp (line, key) == 0) + { + strcpy (value, ptr+1); + fclose (rc); + + while (value[strlen (value)-1] == 10 || + value[strlen (value)-1] == 13 || + value[strlen (value)-1] == 32) + value[strlen (value)-1] = 0; + return true; + } + } + } + } + + fclose (rc); + return false; +} + +static bool save_var (const char *filename, const char *section, const char *key, const char *value) +{ + char line[1024], *ptr; + FILE *old_rc = NULL, *rc; + bool found; + + rc = fopen (filename, "rb"); + + if (rc != NULL) + { + guint32 len; + void *buf; + + char *tmpname = g_strdup_printf ("%s.tmp", filename); + old_rc = fopen (tmpname, "w+b"); + g_free (tmpname); + + fseek (rc, 0, SEEK_END); + len = ftell (rc); + rewind (rc); + buf = g_malloc (len); + fread (buf, len, 1, rc); + fwrite (buf, len, 1, old_rc); + g_free (buf); + fclose (rc); + rewind (old_rc); + } + + rc = fopen (filename, "wb"); + + if (rc == NULL) + return false; + + // First we need to find the section + found = false; + if (old_rc != NULL) + while (fgets (line, 1024, old_rc) != NULL) + { + fputs (line, rc); + + if (line[0] == '[') + { + ptr = strchr (line, ']'); + *ptr = '\0'; + + if (strcmp (&line[1], section) == 0) + { + found = true; + break; + } + } + } + + if (!found) + { + fputs ("\n", rc); + fprintf (rc, "[%s]\n", section); + } + + fprintf (rc, "%s=%s\n", key, value); + + if (old_rc != NULL) + { + while (fgets (line, 1024, old_rc) != NULL) + { + ptr = strchr (line, '='); + + if (ptr != NULL) + { + *ptr = '\0'; + + if (strcmp (line, key) == 0) + break; + + *ptr = '='; + fputs (line, rc); + } + else + { + fputs (line, rc); + break; + } + } + + while (fgets (line, 1024, old_rc) != NULL) + fputs (line, rc); + + fclose (old_rc); + + char *tmpname = g_strdup_printf ("%s.tmp", filename); + remove (tmpname); + g_free (tmpname); + } + + fclose (rc); + + return true; +} + +#endif + +int INIGetInt(char *key, int def) +{ +#if defined(__linux__) || defined(__APPLE__) + char value[1024]; + + if (read_var (INIfn, CONFIG_SECTION, key, value)) + return atoi (value); + else + return def; +#else + return GetPrivateProfileInt(CONFIG_SECTION, key, def, INIfn); +#endif +} + +void INISetInt(char *key, int val, char *comment /* = NULL */) +{ + char s[1000]; + + if(comment) + sprintf(s, "%d ; %s", val, comment); + else + sprintf(s, "%d", val); +#if defined(__linux__) || defined(__APPLE__) + save_var (INIfn, CONFIG_SECTION, key, s); +#else + WritePrivateProfileString(CONFIG_SECTION, key, s, INIfn); +#endif +} + + +// plugin name +static const char *PLUGIN_NAME = "Portal Viewer"; +// commands in the menu +static const char *PLUGIN_COMMANDS = + Q3R_CMD_ABOUT ";" + Q3R_CMD_SPLITTER ";" + Q3R_CMD_OPTIONS ";" + Q3R_CMD_SPLITTER ";" + Q3R_CMD_SHOW_2D ";" + Q3R_CMD_SHOW_3D ";" + Q3R_CMD_SPLITTER ";" + Q3R_CMD_RELEASE ";" + Q3R_CMD_LOAD; + +extern "C" LPVOID WINAPI QERPlug_GetFuncTable() +{ + return &g_FuncTable; +} + + +//extern "C" LPCSTR WINAPI QERPlug_Init (HMODULE hApp, GtkWidget* hwndMain) +extern "C" const char* QERPlug_Init (void *hApp, void* pMainWidget) +{ + // Setup defaults & load config + InitInstance(); + + return "Portal Viewer for Q3Radiant"; +} + +extern "C" const char* QERPlug_GetName() +{ + return (char*)PLUGIN_NAME; +} + +extern "C" const char* QERPlug_GetCommandList() +{ + return (char*)PLUGIN_COMMANDS; +} + +/* +void Sys_Printf (char *text, ...) +{ + va_list argptr; + char buf[32768]; + + va_start (argptr,text); + vsprintf (buf, text, argptr); + va_end (argptr); + + g_FuncTable.m_pfnSysMsg (buf); +} +*/ + +bool interfaces_started = false; + +static void CheckInterfaces() +{ + if (interfaces_started) + return; + + render.Register(); + + interfaces_started = true; +} + +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,Q3R_CMD_ABOUT)) + { + DoAboutDlg (); + } + else if (!strcmp(p,Q3R_CMD_LOAD)) + { + CheckInterfaces(); + + if (interfaces_started) + { + if (DoLoadPortalFileDialog () == IDOK) + { + portals.Load(); + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL); + } + else + { + Sys_Printf(MSG_PREFIX "Portal file load aborted.\n", portals.fn); + } + } + } + else if (!strcmp(p,Q3R_CMD_RELEASE)) + { + portals.Purge(); + + if (interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL); + + Sys_Printf(MSG_PREFIX "Portals unloaded.\n"); + } + else if (!strcmp(p,Q3R_CMD_SHOW_2D)) + { + portals.show_2d = !portals.show_2d; + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL); + SaveConfig(); + + if(portals.show_2d) + Sys_Printf(MSG_PREFIX "Portals will be rendered in 2D view.\n"); + else + Sys_Printf(MSG_PREFIX "Portals will NOT be rendered in 2D view.\n"); + } + else if (!strcmp(p,Q3R_CMD_SHOW_3D)) + { + portals.show_3d = !portals.show_3d; + SaveConfig(); + + if (interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL); + + if (portals.show_3d) + Sys_Printf(MSG_PREFIX "Portals will be rendered in 3D view.\n"); + else + Sys_Printf(MSG_PREFIX "Portals will NOT be rendered in 3D view.\n"); + } + else if (!strcmp(p,Q3R_CMD_OPTIONS)) + { + DoConfigDialog (); + SaveConfig(); + + if (interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL); + } +} + + + +// ============================================================================= +// SYNAPSE + +class CSynapseClientPrtView : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + + CSynapseClientPrtView() { } + virtual ~CSynapseClientPrtView() { } +}; + + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientPrtView 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(PLUGIN_MAJOR, PRTVIEW_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); + + return &g_SynapseClient; +} + +bool CSynapseClientPrtView::RequestAPI(APIDescriptor_t *pAPI) +{ + if( !strcmp(pAPI->major_name, PLUGIN_MAJOR) ) + { + if( !strcmp(pAPI->minor_name, PRTVIEW_MINOR) ) + { + _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; + } + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientPrtView::GetInfo() +{ + return "PrtView module built " __DATE__ " " RADIANT_VERSION; +} diff --git a/contrib/prtview/stdafx.cpp b/contrib/prtview/stdafx.cpp index 6bee6d29..06ae853b 100644 --- a/contrib/prtview/stdafx.cpp +++ b/contrib/prtview/stdafx.cpp @@ -1,25 +1,25 @@ -/* -PrtView plugin for GtkRadiant -Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com - -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 -*/ - -// stdafx.cpp : source file that includes just the standard includes -// PrtView.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "stdafx.h" - +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +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 +*/ + +// stdafx.cpp : source file that includes just the standard includes +// PrtView.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + diff --git a/docs/developer/XMLPush/StdAfx.cpp b/docs/developer/XMLPush/StdAfx.cpp index e8b9d80f..6304ff3d 100644 --- a/docs/developer/XMLPush/StdAfx.cpp +++ b/docs/developer/XMLPush/StdAfx.cpp @@ -1,8 +1,8 @@ -// stdafx.cpp : source file that includes just the standard includes -// XMLPush.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "stdafx.h" - -// TODO: reference any additional headers you need in STDAFX.H -// and not in this file +// stdafx.cpp : source file that includes just the standard includes +// XMLPush.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/docs/developer/XMLPush/XMLPush.cpp b/docs/developer/XMLPush/XMLPush.cpp index 9edc3c63..c3a9ec0e 100644 --- a/docs/developer/XMLPush/XMLPush.cpp +++ b/docs/developer/XMLPush/XMLPush.cpp @@ -1,30 +1,30 @@ -// XMLPush.cpp : Defines the entry point for the console application. -// - -#include "stdafx.h" - -int main(int argc, char* argv[]) -{ - FILE *f; - xmlDocPtr doc; - - f = fopen("XMLDump.xml", "r"); - if (f != NULL) { - int res, size = 1024; - char chars[1024]; - xmlParserCtxtPtr ctxt; - - res = fread(chars, 1, 4, f); - if (res > 0) { - ctxt = xmlCreatePushParserCtxt(NULL, NULL, - chars, res, "foooo (filename)?"); - while ((res = fread(chars, 1, size, f)) > 0) { - xmlParseChunk(ctxt, chars, res, 0); - } - xmlParseChunk(ctxt, chars, 0, 1); - doc = ctxt->myDoc; - xmlFreeParserCtxt(ctxt); - } - } - return 0; -} +// XMLPush.cpp : Defines the entry point for the console application. +// + +#include "stdafx.h" + +int main(int argc, char* argv[]) +{ + FILE *f; + xmlDocPtr doc; + + f = fopen("XMLDump.xml", "r"); + if (f != NULL) { + int res, size = 1024; + char chars[1024]; + xmlParserCtxtPtr ctxt; + + res = fread(chars, 1, 4, f); + if (res > 0) { + ctxt = xmlCreatePushParserCtxt(NULL, NULL, + chars, res, "foooo (filename)?"); + while ((res = fread(chars, 1, size, f)) > 0) { + xmlParseChunk(ctxt, chars, res, 0); + } + xmlParseChunk(ctxt, chars, 0, 1); + doc = ctxt->myDoc; + xmlFreeParserCtxt(ctxt); + } + } + return 0; +} diff --git a/libs/cmdlib/cmdlib.cpp b/libs/cmdlib/cmdlib.cpp index 6aeee9f6..8e904fa7 100644 --- a/libs/cmdlib/cmdlib.cpp +++ b/libs/cmdlib/cmdlib.cpp @@ -1,496 +1,496 @@ -/* -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 -*/ - -// -// start of shared cmdlib stuff -// - -#include "cmdlib.h" - -#ifdef _WIN32 - #include -#endif -#if defined (__linux__) || defined (__APPLE__) - #include -#endif - -// FIXME TTimo this should be cleaned up .. -// NOTE: we don't use this crap .. with the total mess of mixing win32/unix paths we need to recognize both '/' and '\\' -#define PATHSEPERATOR '/' - -#if defined (__linux__) || defined (__APPLE__) -bool Q_Exec(const char *cmd, char *cmdline, const char *execdir, bool bCreateConsole) -{ - char fullcmd[2048]; - char *pCmd; -#ifdef _DEBUG - printf("Q_Exec damnit\n"); -#endif - switch (fork()) - { - case -1: - return true; - break; - case 0: - // always concat the command on linux - if (cmd) - { - strcpy(fullcmd, cmd); - } - else - fullcmd[0] = '\0'; - if (cmdline) - { - strcat(fullcmd, " "); - strcat(fullcmd, cmdline); - } - pCmd = fullcmd; - while (*pCmd == ' ') - pCmd++; -#ifdef _DEBUG - printf("Running system...\n"); - printf("Command: %s\n", pCmd); -#endif - system( pCmd ); -#ifdef _DEBUG - printf ("system() returned\n"); -#endif - _exit (0); - break; - } - return true; -} -#endif - -#ifdef _WIN32 -// NOTE TTimo windows is VERY nitpicky about the syntax in CreateProcess -bool Q_Exec(const char *cmd, char *cmdline, const char *execdir, bool bCreateConsole) -{ - PROCESS_INFORMATION ProcessInformation; - STARTUPINFO startupinfo = {0}; - DWORD dwCreationFlags; - GetStartupInfo (&startupinfo); - if (bCreateConsole) - dwCreationFlags = CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS; - else - dwCreationFlags = DETACHED_PROCESS | NORMAL_PRIORITY_CLASS; - const char *pCmd; - char *pCmdline; - pCmd = cmd; - if (pCmd) - { - while (*pCmd == ' ') - pCmd++; - } - pCmdline = cmdline; - if (pCmdline) - { - while (*pCmdline == ' ') - pCmdline++; - } - if (CreateProcess( - pCmd, - pCmdline, - NULL, - NULL, - FALSE, - dwCreationFlags, - NULL, - execdir, - &startupinfo, - &ProcessInformation - )) - return true; - return false; -} -#endif - -#define MEM_BLOCKSIZE 4096 -void* qblockmalloc(size_t nSize) -{ - void *b; - // round up to threshold - int nAllocSize = nSize % MEM_BLOCKSIZE; - if ( nAllocSize > 0) - { - nSize += MEM_BLOCKSIZE - nAllocSize; - } - b = malloc(nSize + 1); - memset (b, 0, nSize); - return b; -} - -//++timo NOTE: can be replaced by g_malloc0(nSize+1) when moving to glib memory handling -void* qmalloc (size_t nSize) -{ - void *b; - b = malloc(nSize + 1); - memset (b, 0, nSize); - return b; -} - -/* -================ -Q_filelength -================ -*/ -int Q_filelength (FILE *f) -{ - int pos; - int end; - - pos = ftell (f); - fseek (f, 0, SEEK_END); - end = ftell (f); - fseek (f, pos, SEEK_SET); - - return end; -} - -void DefaultExtension (char *path, char *extension) -{ - char *src; -// -// if path doesn't have a .EXT, append extension -// (extension should include the .) -// - src = path + strlen(path) - 1; - - while (*src != PATHSEPERATOR && src != path) - { - if (*src == '.') - return; // it has an extension - src--; - } - - strcat (path, extension); -} - -void DefaultPath (char *path, char *basepath) -{ - char temp[128]; - - if (path[0] == PATHSEPERATOR) - return; // absolute path location - strcpy (temp,path); - strcpy (path,basepath); - strcat (path,temp); -} - - -void StripFilename (char *path) -{ - int length; - - length = strlen(path)-1; - while (length > 0 && path[length] != PATHSEPERATOR) - length--; - path[length] = 0; -} - -void StripExtension (char *path) -{ - int length; - - length = strlen(path)-1; - while (length > 0 && path[length] != '.') - { - length--; - if (path[length] == '/') - return; // no extension - } - if (length) - path[length] = 0; -} - - -/* -==================== -Extract file parts -==================== -*/ -void ExtractFilePath (const char *path, char *dest) -{ - const char *src; - - src = path + strlen(path) - 1; - -// -// back up until a \ or the start -// - while (src != path && *(src-1) != '/' && *(src-1) != '\\') - src--; - - memcpy (dest, path, src-path); - dest[src-path] = 0; -} - -void ExtractFileName (const char *path, char *dest) -{ - const char *src; - - src = path + strlen(path) - 1; - -// -// back up until a \ or the start -// - while (src != path && *(src-1) != '/' - && *(src-1) != '\\' ) - src--; - - while (*src) - { - *dest++ = *src++; - } - *dest = 0; -} - -inline const char* path_get_filename_start(const char* path) -{ - { - const char* last_forward_slash = strrchr(path, '/'); - if(last_forward_slash != NULL) - return last_forward_slash + 1; - } - - { - const char* last_backward_slash = strrchr(path, '\\'); - if(last_backward_slash != NULL) - return last_backward_slash + 1; - } - - return path; -} - -inline unsigned int filename_get_base_length(const char* filename) -{ - const char* last_period = strrchr(filename, '.'); - return (last_period != NULL) ? last_period - filename : strlen(filename); -} - -void ExtractFileBase (const char *path, char *dest) -{ - const char* filename = path_get_filename_start(path); - unsigned int length = filename_get_base_length(filename); - strncpy(dest, filename, length); - dest[length] = '\0'; -} - -void ExtractFileExtension (const char *path, char *dest) -{ - const char *src; - - src = path + strlen(path) - 1; - -// -// back up until a . or the start -// - while (src != path && *(src-1) != '.') - src--; - if (src == path) - { - *dest = 0; // no extension - return; - } - - strcpy (dest,src); -} - - -void ConvertDOSToUnixName( char *dst, const char *src ) -{ - while ( *src ) - { - if ( *src == '\\' ) - *dst = '/'; - else - *dst = *src; - dst++; src++; - } - *dst = 0; -} - - -char* StrDup(char* pStr) -{ - if (pStr) - { - return strcpy(new char[strlen(pStr)+1], pStr); - } - return NULL; -} - -char* StrDup(const char* pStr) -{ - if (pStr) - { - return strcpy(new char[strlen(pStr)+1], pStr); - } - return NULL; -} - -void CreateDirectoryPath (const char *path) { - char base[PATH_MAX]; - char *src; - char back; - - ExtractFilePath(path, base); - - src = base+1; - while (1) { - while (*src != '\0' && *src != '/' && *src != '\\') { - src++; - } - if (*src == '\0') { - break; - } - back = *src; *src = '\0'; - Q_mkdir(base, 0755); - *src = back; src++; - } -} - -/* -============================================================================ - - BYTE ORDER FUNCTIONS - -============================================================================ -*/ - -#ifdef _SGI_SOURCE - #define __BIG_ENDIAN__ -#endif - -#ifdef __BIG_ENDIAN__ - -short LittleShort (short l) -{ - byte b1,b2; - - b1 = l&255; - b2 = (l>>8)&255; - - return(b1<<8) + b2; -} - -short BigShort (short l) -{ - return l; -} - - -int LittleLong (int l) -{ - byte b1,b2,b3,b4; - - b1 = l&255; - b2 = (l>>8)&255; - b3 = (l>>16)&255; - b4 = (l>>24)&255; - - return((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; -} - -int BigLong (int l) -{ - return l; -} - - -float LittleFloat (float l) -{ - union - { - byte b[4]; float f; - } in, out; - - in.f = l; - out.b[0] = in.b[3]; - out.b[1] = in.b[2]; - out.b[2] = in.b[1]; - out.b[3] = in.b[0]; - - return out.f; -} - -float BigFloat (float l) -{ - return l; -} - -#else - -short BigShort (short l) -{ - byte b1,b2; - - b1 = l&255; - b2 = (l>>8)&255; - - return(b1<<8) + b2; -} - -short LittleShort (short l) -{ - return l; -} - - -int BigLong (int l) -{ - byte b1,b2,b3,b4; - - b1 = l&255; - b2 = (l>>8)&255; - b3 = (l>>16)&255; - b4 = (l>>24)&255; - - return((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; -} - -int LittleLong (int l) -{ - return l; -} - -float BigFloat (float l) -{ - union - { - byte b[4]; float f; - } in, out; - - in.f = l; - out.b[0] = in.b[3]; - out.b[1] = in.b[2]; - out.b[2] = in.b[1]; - out.b[3] = in.b[0]; - - return out.f; -} - -float LittleFloat (float l) -{ - return l; -} - -#endif +/* +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 +*/ + +// +// start of shared cmdlib stuff +// + +#include "cmdlib.h" + +#ifdef _WIN32 + #include +#endif +#if defined (__linux__) || defined (__APPLE__) + #include +#endif + +// FIXME TTimo this should be cleaned up .. +// NOTE: we don't use this crap .. with the total mess of mixing win32/unix paths we need to recognize both '/' and '\\' +#define PATHSEPERATOR '/' + +#if defined (__linux__) || defined (__APPLE__) +bool Q_Exec(const char *cmd, char *cmdline, const char *execdir, bool bCreateConsole) +{ + char fullcmd[2048]; + char *pCmd; +#ifdef _DEBUG + printf("Q_Exec damnit\n"); +#endif + switch (fork()) + { + case -1: + return true; + break; + case 0: + // always concat the command on linux + if (cmd) + { + strcpy(fullcmd, cmd); + } + else + fullcmd[0] = '\0'; + if (cmdline) + { + strcat(fullcmd, " "); + strcat(fullcmd, cmdline); + } + pCmd = fullcmd; + while (*pCmd == ' ') + pCmd++; +#ifdef _DEBUG + printf("Running system...\n"); + printf("Command: %s\n", pCmd); +#endif + system( pCmd ); +#ifdef _DEBUG + printf ("system() returned\n"); +#endif + _exit (0); + break; + } + return true; +} +#endif + +#ifdef _WIN32 +// NOTE TTimo windows is VERY nitpicky about the syntax in CreateProcess +bool Q_Exec(const char *cmd, char *cmdline, const char *execdir, bool bCreateConsole) +{ + PROCESS_INFORMATION ProcessInformation; + STARTUPINFO startupinfo = {0}; + DWORD dwCreationFlags; + GetStartupInfo (&startupinfo); + if (bCreateConsole) + dwCreationFlags = CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS; + else + dwCreationFlags = DETACHED_PROCESS | NORMAL_PRIORITY_CLASS; + const char *pCmd; + char *pCmdline; + pCmd = cmd; + if (pCmd) + { + while (*pCmd == ' ') + pCmd++; + } + pCmdline = cmdline; + if (pCmdline) + { + while (*pCmdline == ' ') + pCmdline++; + } + if (CreateProcess( + pCmd, + pCmdline, + NULL, + NULL, + FALSE, + dwCreationFlags, + NULL, + execdir, + &startupinfo, + &ProcessInformation + )) + return true; + return false; +} +#endif + +#define MEM_BLOCKSIZE 4096 +void* qblockmalloc(size_t nSize) +{ + void *b; + // round up to threshold + int nAllocSize = nSize % MEM_BLOCKSIZE; + if ( nAllocSize > 0) + { + nSize += MEM_BLOCKSIZE - nAllocSize; + } + b = malloc(nSize + 1); + memset (b, 0, nSize); + return b; +} + +//++timo NOTE: can be replaced by g_malloc0(nSize+1) when moving to glib memory handling +void* qmalloc (size_t nSize) +{ + void *b; + b = malloc(nSize + 1); + memset (b, 0, nSize); + return b; +} + +/* +================ +Q_filelength +================ +*/ +int Q_filelength (FILE *f) +{ + int pos; + int end; + + pos = ftell (f); + fseek (f, 0, SEEK_END); + end = ftell (f); + fseek (f, pos, SEEK_SET); + + return end; +} + +void DefaultExtension (char *path, char *extension) +{ + char *src; +// +// if path doesn't have a .EXT, append extension +// (extension should include the .) +// + src = path + strlen(path) - 1; + + while (*src != PATHSEPERATOR && src != path) + { + if (*src == '.') + return; // it has an extension + src--; + } + + strcat (path, extension); +} + +void DefaultPath (char *path, char *basepath) +{ + char temp[128]; + + if (path[0] == PATHSEPERATOR) + return; // absolute path location + strcpy (temp,path); + strcpy (path,basepath); + strcat (path,temp); +} + + +void StripFilename (char *path) +{ + int length; + + length = strlen(path)-1; + while (length > 0 && path[length] != PATHSEPERATOR) + length--; + path[length] = 0; +} + +void StripExtension (char *path) +{ + int length; + + length = strlen(path)-1; + while (length > 0 && path[length] != '.') + { + length--; + if (path[length] == '/') + return; // no extension + } + if (length) + path[length] = 0; +} + + +/* +==================== +Extract file parts +==================== +*/ +void ExtractFilePath (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' && *(src-1) != '\\') + src--; + + memcpy (dest, path, src-path); + dest[src-path] = 0; +} + +void ExtractFileName (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' + && *(src-1) != '\\' ) + src--; + + while (*src) + { + *dest++ = *src++; + } + *dest = 0; +} + +inline const char* path_get_filename_start(const char* path) +{ + { + const char* last_forward_slash = strrchr(path, '/'); + if(last_forward_slash != NULL) + return last_forward_slash + 1; + } + + { + const char* last_backward_slash = strrchr(path, '\\'); + if(last_backward_slash != NULL) + return last_backward_slash + 1; + } + + return path; +} + +inline unsigned int filename_get_base_length(const char* filename) +{ + const char* last_period = strrchr(filename, '.'); + return (last_period != NULL) ? last_period - filename : strlen(filename); +} + +void ExtractFileBase (const char *path, char *dest) +{ + const char* filename = path_get_filename_start(path); + unsigned int length = filename_get_base_length(filename); + strncpy(dest, filename, length); + dest[length] = '\0'; +} + +void ExtractFileExtension (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a . or the start +// + while (src != path && *(src-1) != '.') + src--; + if (src == path) + { + *dest = 0; // no extension + return; + } + + strcpy (dest,src); +} + + +void ConvertDOSToUnixName( char *dst, const char *src ) +{ + while ( *src ) + { + if ( *src == '\\' ) + *dst = '/'; + else + *dst = *src; + dst++; src++; + } + *dst = 0; +} + + +char* StrDup(char* pStr) +{ + if (pStr) + { + return strcpy(new char[strlen(pStr)+1], pStr); + } + return NULL; +} + +char* StrDup(const char* pStr) +{ + if (pStr) + { + return strcpy(new char[strlen(pStr)+1], pStr); + } + return NULL; +} + +void CreateDirectoryPath (const char *path) { + char base[PATH_MAX]; + char *src; + char back; + + ExtractFilePath(path, base); + + src = base+1; + while (1) { + while (*src != '\0' && *src != '/' && *src != '\\') { + src++; + } + if (*src == '\0') { + break; + } + back = *src; *src = '\0'; + Q_mkdir(base, 0755); + *src = back; src++; + } +} + +/* +============================================================================ + + BYTE ORDER FUNCTIONS + +============================================================================ +*/ + +#ifdef _SGI_SOURCE + #define __BIG_ENDIAN__ +#endif + +#ifdef __BIG_ENDIAN__ + +short LittleShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return(b1<<8) + b2; +} + +short BigShort (short l) +{ + return l; +} + + +int LittleLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int BigLong (int l) +{ + return l; +} + + +float LittleFloat (float l) +{ + union + { + byte b[4]; float f; + } in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float BigFloat (float l) +{ + return l; +} + +#else + +short BigShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return(b1<<8) + b2; +} + +short LittleShort (short l) +{ + return l; +} + + +int BigLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int LittleLong (int l) +{ + return l; +} + +float BigFloat (float l) +{ + union + { + byte b[4]; float f; + } in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float LittleFloat (float l) +{ + return l; +} + +#endif diff --git a/libs/pak/pakstuff.cpp b/libs/pak/pakstuff.cpp index f3ae725e..b6028cc7 100644 --- a/libs/pak/pakstuff.cpp +++ b/libs/pak/pakstuff.cpp @@ -1,979 +1,979 @@ -/* -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 -*/ - -#include -#include -#include -#include -#if defined (__linux__) || defined (__APPLE__) -#include -#endif -#ifdef _WIN32 -#include -#endif -#include "pakstuff.h" -#include "unzip.h" -#include "str.h" - -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - -int m_nPAKIndex; -FILE* pakfile[16]; -struct PACKDirectory pakdir; -PACKDirPtr pakdirptr = &pakdir; -UInt16 dirsize; -bool pakopen = false; -int f_type; -DIRECTORY *paktextures = NULL; -UInt32 PakColormapOffset; -UInt32 PakColormapSize; -DIRECTORY *dirhead = NULL; -bool g_bPK3 = false; -char g_strBasePaths[16][1024]; -int g_numBasePaths = 0; - -struct PK3FileInfo -{ - unzFile m_zFile; - char *m_pName; - unz_s m_zInfo; - long m_lSize; - ~PK3FileInfo() - { - delete []m_pName; - } - bool operator ==(const PK3FileInfo& rhs) const { return strcmp(m_pName, rhs.m_pName) == 0; } -}; - -#define __PATHSEPERATOR '/' - -//#define LOG_PAKFAIL - -#ifdef LOG_PAKFAIL - -#if defined (__linux__) || defined (__APPLE__) -#include -#include -#endif -#include - -class LogFile -{ -public: - FILE *m_pFile; - LogFile(const char* pName) - { -#if defined (__linux__) || defined (__APPLE__) - // leo: use ~/.q3a/radiant/paklog instead of /tmp/paklog.txt - char *home = NULL; - - home = getenv("HOME"); - if ( home == NULL ) - { - uid_t id = getuid(); - struct passwd *pwd; - - setpwent(); - while( (pwd = getpwent()) != NULL ) - if( pwd->pw_uid == id ) - { - home = pwd->pw_dir; - break; - } - endpwent(); - } - - if (home != NULL) - { - char path[PATH_MAX]; - strcpy (path, home); - if (path[strlen(path)-1] != '/') - strcat (path, "/"); - strcat (path, ".q3a/radiant/paklog"); - m_pFile = fopen(path, "w"); - } - else -#endif - m_pFile = fopen(pName, "w"); - } - ~LogFile() - { - if (m_pFile) - { - fclose(m_pFile); - } - } - void Log(const char *pFormat, ...) - { - if (m_pFile == NULL) - return; - - va_list arg_ptr; - va_start(arg_ptr, pFormat); - fprintf(m_pFile, pFormat, arg_ptr); - va_end(arg_ptr); - } -}; - -LogFile g_LogFile("/tmp/paklog.txt"); -#endif - -template class StrPtr : public Str -{ -protected: - T* m_pPtr; - StrPtr() - { - m_pPtr = NULL; - } - - StrPtr(const char *pStr, T *p) : Str(pStr) - { - m_pPtr = p; - } - - T* Ptr() - { - return m_pPtr; - } - - T& Ref() - { - return *m_pPtr; - } - - -}; -// PtrList -// a list of ptrs -// -template class PtrList -{ -protected: - T *m_pPtr; - PtrList *m_pNext; - -public: - - PtrList() - { - m_pNext = NULL; - m_pPtr = NULL; - } - - PtrList(T *ip) - { - m_pNext = NULL; - m_pPtr = ip; - } - - virtual ~PtrList() - { - delete m_pPtr; - } - - PtrList* Next() - { - return m_pNext; - } - - void Add(T *ip) - { - PtrList *pl = this; - while (pl && pl->m_pNext) - { - pl = pl->Next(); - } - pl->m_pNext = new PtrList(ip); - } - - void Remove() - { - PtrList *p = m_pNext; - if (p) - { - while (p->m_pNext != this && p->m_pNext != NULL) - { - p = p->m_pNext; - } - if (p->m_pNext == this) - { - p->m_pNext = m_pNext; - } - } - } - - virtual PtrList* Find(T *ip) - { - PtrList *p = m_pNext; - while (p) - { - if (*p->m_pPtr == *ip) - { - return p; - } - p = p->m_pNext; - } - return NULL; - } - - // remove vp from the list - void Remove(T *ip) - { - PtrList *p = Find(ip); - if (p) - { - p->Remove(); - } - } - - T* Ptr() - { - return m_pPtr; - } - - T& Ref() - { - return *m_pPtr; - } - - void RemoveAll() - { - PtrList *p = m_pNext; - while (p) - { - PtrList *p2 = p; - p = p->m_pNext; - delete p2; - } - } -}; - - -typedef PtrList ZFileList; -typedef PtrList StrList; -typedef PtrList PK3List; - - -StrList g_PK3TexturePaths; -PK3List g_PK3Files; -ZFileList g_zFiles; -#define WORK_LEN 1024 -#define TEXTURE_PATH "textures" -#define PATH_SEPERATORS "/\\:\0" - -/* -char* __StrDup(char* pStr) -{ - if (pStr == NULL) - pStr = ""; - - return strcpy(new char[strlen(pStr)+1], pStr); -} - -char* __StrDup(const char* pStr) -{ - if (pStr == NULL) - pStr = ""; - - return strcpy(new char[strlen(pStr)+1], pStr); -} -*/ - -#define MEM_BLOCKSIZE 4096 -void* __qblockmalloc(size_t nSize) -{ - void *b; - // round up to threshold - int nAllocSize = nSize % MEM_BLOCKSIZE; - if ( nAllocSize > 0) - { - nSize += MEM_BLOCKSIZE - nAllocSize; - } - b = malloc(nSize + 1); - memset (b, 0, nSize); - return b; -} - -void* __qmalloc (size_t nSize) -{ - void *b; - b = malloc(nSize + 1); - memset (b, 0, nSize); - return b; -} - - -/* -==================== -Extract file parts -==================== -*/ -void __ExtractFilePath (const char *path, char *dest) -{ - const char *src; - - src = path + strlen(path) - 1; - -// -// back up until a \ or the start -// - while (src != path && *(src-1) != __PATHSEPERATOR) - src--; - - memcpy (dest, path, src-path); - dest[src-path] = 0; -} - -void __ExtractFileName (const char *path, char *dest) -{ - const char *src; - - src = path + strlen(path) - 1; - -// -// back up until a \ or the start -// - while (src != path && *(src-1) != '/' - && *(src-1) != '\\' ) - src--; - - while (*src) - { - *dest++ = *src++; - } - *dest = 0; -} - -void __ExtractFileBase (const char *path, char *dest) -{ - const char *src; - - src = path + strlen(path) - 1; - -// -// back up until a \ or the start -// - while (src != path && *(src-1) != '/' - && *(src-1) != '\\' ) - src--; - - while (*src && *src != '.') - { - *dest++ = *src++; - } - *dest = 0; -} - -void __ExtractFileExtension (const char *path, char *dest) -{ - const char *src; - - src = path + strlen(path) - 1; - -// -// back up until a . or the start -// - while (src != path && *(src-1) != '.') - src--; - if (src == path) - { - *dest = 0; // no extension - return; - } - - strcpy (dest,src); -} - - -void __ConvertDOSToUnixName( char *dst, const char *src ) -{ - while ( *src ) - { - if ( *src == '\\' ) - *dst = '/'; - else - *dst = *src; - dst++; src++; - } - *dst = 0; -} - - - - - -static void AddSlash(Str& str) -{ - int nLen = str.GetLength(); - if (nLen > 0) - { - if (str[nLen-1] != '\\' && str[nLen-1] != '/') - str += '\\'; - } -} - -static void FindReplace(Str& strContents, const char* pTag, const char* pValue) -{ - if (strcmp(pTag, pValue) == 0) - return; - for (int nPos = strContents.Find(pTag); nPos >= 0; nPos = strContents.Find(pTag)) - { - int nRightLen = strContents.GetLength() - strlen(pTag) - nPos; - Str strLeft(strContents.Left(nPos)); - Str strRight(strContents.Right(nRightLen)); - strLeft += pValue; - strLeft += strRight; - strContents = strLeft; - } -} - - - - - -void ClearFileList(FILELIST **list) -{ - FILELIST *temp; - - while(*list) - { - temp = *list; - *list = (*list)->next; - free(temp); - } -} - -void ClearDirList(DIRLIST **list) -{ - DIRLIST *temp; - - while(*list) - { - temp = *list; - *list = (*list)->next; - free(temp); - } -} - -DIRECTORY *FindPakDir(DIRECTORY *dir, char *name) -{ - DIRECTORY *currentPtr; - - for(currentPtr = dir; currentPtr; currentPtr = currentPtr->next) - { - if(!stricmp(name, currentPtr->name)) - { - return currentPtr; - } - } - return NULL; -} - - -// LoadPK3FileList -// --------------- -// -// This gets passed a file mask which we want to remove as -// we are only interested in the directory name and any given -// extension. Only handles explicit filenames or *.something -// -bool LoadPK3FileList(FILELIST **filelist, const char *pattern) -{ - char cSearch[WORK_LEN]; - __ConvertDOSToUnixName( cSearch, pattern ); - char cPath[WORK_LEN]; - char cExt[WORK_LEN]; - char cFile[WORK_LEN]; - char cWork[WORK_LEN]; - __ExtractFilePath(pattern, cPath); - __ExtractFileName(pattern, cFile); - __ExtractFileExtension(pattern, cExt); - const char *pCompare = (strnicmp(cFile, "*.", 2) == 0) ? cExt : cFile; - - PK3List *p = g_PK3Files.Next(); - while (p != NULL) - { - // qualify the path - PK3FileInfo *pKey = p->Ptr(); - if (strstr(pKey->m_pName, cPath) && strstr(pKey->m_pName, pCompare)) - { - __ExtractFileName(pKey->m_pName, cWork); - AddToFileListAlphabetized(filelist, cWork, 0, 0, false); - } - p = p->Next(); - } - return (*filelist) != NULL; -} - -bool GetPackFileList(FILELIST **filelist, char *pattern) -{ - char *str1, *str2; - int i; - DIRECTORY *dummy = paktextures; - FILELIST *temp; - - if (!pakopen) - return false; - - if (g_bPK3) - { - return LoadPK3FileList(filelist, pattern); - } - - str1 = pattern; - - for(i = 0; pattern[i] != '\0'; i++) - { - if(pattern[i] == '\\') - pattern[i] = '/'; - } - - while(strchr(str1, '/')) - { - str2 = strchr(str1, '/'); - *str2++ = '\0'; - dummy = FindPakDir(dummy, str1); - if(!dummy) - return false; - str1 = str2; - } - for(temp = dummy->files; temp; temp=temp->next) - { - AddToFileListAlphabetized(filelist, temp->filename, temp->offset, 0, false); - } - return true; -} - -bool GetPackTextureDirs(DIRLIST **dirlist) -{ - UInt16 i; - char buf[57]; - - if (!pakopen) - return 1; - - if (g_bPK3) - { - StrList *pl = g_PK3TexturePaths.Next(); - while (pl != NULL) - { - AddToDirListAlphabetized(dirlist, pl->Ref(), 0); - pl = pl->Next(); - } - return true; - } - - for (i = 0; i < dirsize; i++) - { - if(!strnicmp(pakdirptr[i].name, "textures", 8)) - { - strncpy(buf, &(pakdirptr[i].name[9]), 46); - if(strchr(buf, '\\')) - *strchr(buf, '\\') = '\0'; - else if(strchr(buf, '/')) - *strchr(buf, '/') = '\0'; - else - buf[56] = '\0'; - - if(strchr(buf, '.')) - continue; - - AddToDirListAlphabetized(dirlist, buf, 0); - } - } - return true; -} - -bool AddToDirListAlphabetized(DIRLIST **list, char *dirname, int from) -{ - DIRLIST *currentPtr, *previousPtr, *newPtr; - - strlwr(dirname); - for(currentPtr = *list; currentPtr; currentPtr = currentPtr->next) - { - if(!stricmp(dirname, currentPtr->dirname)) - { - return false; - } - } - previousPtr = NULL; - currentPtr = *list; - - if((newPtr = (DIRLIST *)__qmalloc(sizeof(DIRLIST))) == NULL) - return false; - - strcpy(newPtr->dirname, dirname); - newPtr->from = from; - - while(currentPtr != NULL && stricmp(dirname, currentPtr->dirname) > 0) - { - previousPtr = currentPtr; - currentPtr = currentPtr->next; - } //End while - if(previousPtr == NULL) - { - newPtr->next = *list; - *list = newPtr; - } //End if - else - { - previousPtr->next = newPtr; - newPtr->next = currentPtr; - } //End else - return true; -} - -bool AddToFileListAlphabetized(FILELIST **list, char *filename, UInt32 offset, UInt32 size, bool dirs) -{ - FILELIST *currentPtr, *previousPtr, *newPtr; - - for(currentPtr = *list; currentPtr; currentPtr = currentPtr->next) - { - if(!stricmp(filename, currentPtr->filename)) - { - return false; - } - } - previousPtr = NULL; - currentPtr = *list; - - if((newPtr = (FILELIST *)__qmalloc(sizeof(FILELIST))) == NULL) - return false; - - strcpy(newPtr->filename, filename); - newPtr->offset = offset; - newPtr->size = size; - - while(currentPtr != NULL && stricmp(filename, currentPtr->filename) > 0) - { - previousPtr = currentPtr; - currentPtr = currentPtr->next; - } //End while - if(previousPtr == NULL) - { - newPtr->next = *list; - *list = newPtr; - } //End if - else - { - previousPtr->next = newPtr; - newPtr->next = currentPtr; - } //End else - return true; -} - -int PakLoadAnyFile(const char *filename, void **bufferptr) -{ - char cWork[WORK_LEN]; - if (g_bPK3) - { - // leo: hack to be able to use pak files from multiple directories - for (int i = 0; i < g_numBasePaths; i++) - { - PK3FileInfo *pInfo; - Str strKey; - // need to lookup the file without the base/texture path on it - Str strBase(g_strBasePaths[i]); - AddSlash(strBase); - __ConvertDOSToUnixName(cWork, strBase); - Str strFile(filename); - __ConvertDOSToUnixName(strFile, strFile); - strFile.MakeLower(); - strlwr(cWork); - FindReplace(strFile, cWork, ""); - - PK3FileInfo infoFind; - infoFind.m_pName = __StrDup(strFile.GetBuffer()); - PK3List *pList = g_PK3Files.Find(&infoFind); - if (pList) - { - pInfo = pList->Ptr(); - memcpy(pInfo->m_zFile, &pInfo->m_zInfo, sizeof(unz_s)); - if (unzOpenCurrentFile(pInfo->m_zFile) == UNZ_OK) - { - void *buffer = __qblockmalloc(pInfo->m_lSize+1); - int n = unzReadCurrentFile(pInfo->m_zFile , buffer, pInfo->m_lSize); - *bufferptr = buffer; - unzCloseCurrentFile(pInfo->m_zFile); - return n; - } - } - } - -#ifdef LOG_PAKFAIL - sprintf(cWork, "PAK failed on %s\n", filename); - g_LogFile.Log(cWork); -#endif - return -1; - } - - for (int i = 0; i < dirsize; i++) - { - if(!stricmp(filename, pakdirptr[i].name)) - { - if (fseek(pakfile[m_nPAKIndex], pakdirptr[i].offset, SEEK_SET) >= 0) - { - void *buffer = __qmalloc (pakdirptr[i].size+1); - ((char *)buffer)[pakdirptr[i].size] = 0; - if (fread(buffer, 1, pakdirptr[i].size, pakfile[m_nPAKIndex]) == pakdirptr[i].size) - { - *bufferptr = buffer; - return pakdirptr[i].size; - } - } - } - } -#ifdef LOG_PAKFAIL - sprintf(cWork, "PAK failed on %s\n", filename); - g_LogFile.Log(cWork); -#endif - return -1; -} - - - -DIRECTORY *AddPakDir(DIRECTORY **dir, char *name) -{ - DIRECTORY *currentPtr, *previousPtr, *newPtr; - - for(currentPtr = *dir; currentPtr; currentPtr = currentPtr->next) - { - if(!stricmp(name, currentPtr->name)) - { - return currentPtr; - } - } - previousPtr = NULL; - currentPtr = *dir; - - if((newPtr = (DIRECTORY *)__qmalloc(sizeof(DIRECTORY))) == NULL) - return NULL; - - strcpy(newPtr->name, name); - newPtr->files = NULL; - - while(currentPtr != NULL && stricmp(name, currentPtr->name) > 0) - { - previousPtr = currentPtr; - currentPtr = currentPtr->next; - } - if(previousPtr == NULL) - { - newPtr->next = *dir; - *dir = newPtr; - } - else - { - previousPtr->next = newPtr; - newPtr->next = currentPtr; - } - return newPtr; -} - - -// OpenPK3 -// ------- -// Opens a PK3 ( or zip ) file and creates a list of filenames -// and zip info structures -// -bool OpenPK3(const char *filename) -{ - char cFilename[WORK_LEN]; - char cName[WORK_LEN]; - char cWork[WORK_LEN]; - unz_file_info zInfo; - unzFile *zFile = new unzFile(unzOpen(filename)); - g_zFiles.Add(zFile); - if (zFile != NULL) - { - int nStatus = unzGoToFirstFile(*zFile); - while (nStatus == UNZ_OK) - { - cFilename[0] = '\0'; - unzGetCurrentFileInfo(*zFile, &zInfo, cFilename, WORK_LEN, NULL, 0, NULL, 0); - strlwr(cFilename); - __ConvertDOSToUnixName( cWork, cFilename); - if (strstr(cWork, ".") != NULL) - { - PK3FileInfo *pInfo = new PK3FileInfo(); - pInfo->m_pName = __StrDup(cWork); - memcpy(&pInfo->m_zInfo, (unz_s*)*zFile, sizeof(unz_s)); - pInfo->m_lSize = zInfo.uncompressed_size; - pInfo->m_zFile = *zFile; - g_PK3Files.Add(pInfo); - } - char *p = strstr(cFilename, TEXTURE_PATH); - if (p != NULL) - { - // FIXME: path differences per os ? - // catch solo directory entry - if (strlen(p) > strlen(TEXTURE_PATH) + 1) - { - // skip textures + path seperator - p += strlen(TEXTURE_PATH) + 1; - int nEnd = strcspn(p, PATH_SEPERATORS); - strncpy(cName, p, nEnd); - cName[nEnd] = '\0'; - - bool bFound = false; - StrList *pl = g_PK3TexturePaths.Next(); - while (pl != NULL) - { - if (strcmpi(pl->Ref(), cName) == 0) - { - // already have this, continue - bFound = true; - break; - } - pl = pl->Next(); - } - if (!bFound) - { - g_PK3TexturePaths.Add(new Str(cName)); - } - } - } - nStatus = unzGoToNextFile(*zFile); - } - } - return (zFile != NULL); -} - -void closePK3(unzFile zf) -{ - unzClose(zf); -} - -void OpenPakFile(const char *filename) -{ - if(!pakopen) - paktextures = NULL; - - pakopen = g_bPK3 = OpenPK3(filename); -} - -void ClearPaKDir(DIRECTORY **dir) -{ - DIRECTORY *d1 = *dir, *d2; - - while(d1) - { - ClearFileList(&(d1->files)); - d2 = d1; - d1 = d1->next; - free(d2); - } -} - -void CleanUpPakDirs() -{ - ClearPaKDir(&paktextures); - paktextures = NULL; - dirhead = NULL; - g_PK3TexturePaths.RemoveAll(); - g_PK3Files.RemoveAll(); -} - -void ClosePakFile(void) -{ - if(pakopen) - { - if (g_bPK3) - { - ZFileList *p = g_zFiles.Next(); - while (p != NULL) - { - unzFile uz = p->Ref(); - closePK3(uz); - p = p->Next(); - } - } - else - { - fclose(pakfile[m_nPAKIndex]); - } - } - pakopen = false; - CleanUpPakDirs(); -} - - -void WINAPI InitPakFile(const char * pBasePath, const char *pName) -{ - if (g_numBasePaths == 0) - { - m_nPAKIndex = 0; - pakopen = false; - paktextures = NULL; - } - strcpy(g_strBasePaths[g_numBasePaths], pBasePath); - g_numBasePaths++; - - if (pName == NULL) - { - //++timo FIXME: use some kind of compatibility lib here! -#if defined (__linux__) || defined (__APPLE__) - char cWork[WORK_LEN]; - struct dirent *dirlist; - DIR *dir; - - dir = opendir (pBasePath); - if (dir != NULL) - { - while ((dirlist = readdir (dir)) != NULL) - { - if (strstr (dirlist->d_name, ".pk3") == NULL) - continue; - sprintf(cWork, "%s/%s", pBasePath, dirlist->d_name); - OpenPakFile(cWork); - } - closedir (dir); - } -#endif -#ifdef _WIN32 - char cWork[WORK_LEN]; - Str strPath(pBasePath); - AddSlash(strPath); - strPath += "*.pk3"; - bool bGo = true; - struct _finddata_t fileinfo; - int handle = _findfirst (strPath, &fileinfo); - if (handle != -1) - { - do - { - sprintf(cWork, "%s/%s", pBasePath, fileinfo.name); - OpenPakFile(cWork); - } while (_findnext( handle, &fileinfo ) != -1); - _findclose (handle); - } -#endif - } - else - { - OpenPakFile(pName); - } -} - +/* +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 +*/ + +#include +#include +#include +#include +#if defined (__linux__) || defined (__APPLE__) +#include +#endif +#ifdef _WIN32 +#include +#endif +#include "pakstuff.h" +#include "unzip.h" +#include "str.h" + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +int m_nPAKIndex; +FILE* pakfile[16]; +struct PACKDirectory pakdir; +PACKDirPtr pakdirptr = &pakdir; +UInt16 dirsize; +bool pakopen = false; +int f_type; +DIRECTORY *paktextures = NULL; +UInt32 PakColormapOffset; +UInt32 PakColormapSize; +DIRECTORY *dirhead = NULL; +bool g_bPK3 = false; +char g_strBasePaths[16][1024]; +int g_numBasePaths = 0; + +struct PK3FileInfo +{ + unzFile m_zFile; + char *m_pName; + unz_s m_zInfo; + long m_lSize; + ~PK3FileInfo() + { + delete []m_pName; + } + bool operator ==(const PK3FileInfo& rhs) const { return strcmp(m_pName, rhs.m_pName) == 0; } +}; + +#define __PATHSEPERATOR '/' + +//#define LOG_PAKFAIL + +#ifdef LOG_PAKFAIL + +#if defined (__linux__) || defined (__APPLE__) +#include +#include +#endif +#include + +class LogFile +{ +public: + FILE *m_pFile; + LogFile(const char* pName) + { +#if defined (__linux__) || defined (__APPLE__) + // leo: use ~/.q3a/radiant/paklog instead of /tmp/paklog.txt + char *home = NULL; + + home = getenv("HOME"); + if ( home == NULL ) + { + uid_t id = getuid(); + struct passwd *pwd; + + setpwent(); + while( (pwd = getpwent()) != NULL ) + if( pwd->pw_uid == id ) + { + home = pwd->pw_dir; + break; + } + endpwent(); + } + + if (home != NULL) + { + char path[PATH_MAX]; + strcpy (path, home); + if (path[strlen(path)-1] != '/') + strcat (path, "/"); + strcat (path, ".q3a/radiant/paklog"); + m_pFile = fopen(path, "w"); + } + else +#endif + m_pFile = fopen(pName, "w"); + } + ~LogFile() + { + if (m_pFile) + { + fclose(m_pFile); + } + } + void Log(const char *pFormat, ...) + { + if (m_pFile == NULL) + return; + + va_list arg_ptr; + va_start(arg_ptr, pFormat); + fprintf(m_pFile, pFormat, arg_ptr); + va_end(arg_ptr); + } +}; + +LogFile g_LogFile("/tmp/paklog.txt"); +#endif + +template class StrPtr : public Str +{ +protected: + T* m_pPtr; + StrPtr() + { + m_pPtr = NULL; + } + + StrPtr(const char *pStr, T *p) : Str(pStr) + { + m_pPtr = p; + } + + T* Ptr() + { + return m_pPtr; + } + + T& Ref() + { + return *m_pPtr; + } + + +}; +// PtrList +// a list of ptrs +// +template class PtrList +{ +protected: + T *m_pPtr; + PtrList *m_pNext; + +public: + + PtrList() + { + m_pNext = NULL; + m_pPtr = NULL; + } + + PtrList(T *ip) + { + m_pNext = NULL; + m_pPtr = ip; + } + + virtual ~PtrList() + { + delete m_pPtr; + } + + PtrList* Next() + { + return m_pNext; + } + + void Add(T *ip) + { + PtrList *pl = this; + while (pl && pl->m_pNext) + { + pl = pl->Next(); + } + pl->m_pNext = new PtrList(ip); + } + + void Remove() + { + PtrList *p = m_pNext; + if (p) + { + while (p->m_pNext != this && p->m_pNext != NULL) + { + p = p->m_pNext; + } + if (p->m_pNext == this) + { + p->m_pNext = m_pNext; + } + } + } + + virtual PtrList* Find(T *ip) + { + PtrList *p = m_pNext; + while (p) + { + if (*p->m_pPtr == *ip) + { + return p; + } + p = p->m_pNext; + } + return NULL; + } + + // remove vp from the list + void Remove(T *ip) + { + PtrList *p = Find(ip); + if (p) + { + p->Remove(); + } + } + + T* Ptr() + { + return m_pPtr; + } + + T& Ref() + { + return *m_pPtr; + } + + void RemoveAll() + { + PtrList *p = m_pNext; + while (p) + { + PtrList *p2 = p; + p = p->m_pNext; + delete p2; + } + } +}; + + +typedef PtrList ZFileList; +typedef PtrList StrList; +typedef PtrList PK3List; + + +StrList g_PK3TexturePaths; +PK3List g_PK3Files; +ZFileList g_zFiles; +#define WORK_LEN 1024 +#define TEXTURE_PATH "textures" +#define PATH_SEPERATORS "/\\:\0" + +/* +char* __StrDup(char* pStr) +{ + if (pStr == NULL) + pStr = ""; + + return strcpy(new char[strlen(pStr)+1], pStr); +} + +char* __StrDup(const char* pStr) +{ + if (pStr == NULL) + pStr = ""; + + return strcpy(new char[strlen(pStr)+1], pStr); +} +*/ + +#define MEM_BLOCKSIZE 4096 +void* __qblockmalloc(size_t nSize) +{ + void *b; + // round up to threshold + int nAllocSize = nSize % MEM_BLOCKSIZE; + if ( nAllocSize > 0) + { + nSize += MEM_BLOCKSIZE - nAllocSize; + } + b = malloc(nSize + 1); + memset (b, 0, nSize); + return b; +} + +void* __qmalloc (size_t nSize) +{ + void *b; + b = malloc(nSize + 1); + memset (b, 0, nSize); + return b; +} + + +/* +==================== +Extract file parts +==================== +*/ +void __ExtractFilePath (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != __PATHSEPERATOR) + src--; + + memcpy (dest, path, src-path); + dest[src-path] = 0; +} + +void __ExtractFileName (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' + && *(src-1) != '\\' ) + src--; + + while (*src) + { + *dest++ = *src++; + } + *dest = 0; +} + +void __ExtractFileBase (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' + && *(src-1) != '\\' ) + src--; + + while (*src && *src != '.') + { + *dest++ = *src++; + } + *dest = 0; +} + +void __ExtractFileExtension (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a . or the start +// + while (src != path && *(src-1) != '.') + src--; + if (src == path) + { + *dest = 0; // no extension + return; + } + + strcpy (dest,src); +} + + +void __ConvertDOSToUnixName( char *dst, const char *src ) +{ + while ( *src ) + { + if ( *src == '\\' ) + *dst = '/'; + else + *dst = *src; + dst++; src++; + } + *dst = 0; +} + + + + + +static void AddSlash(Str& str) +{ + int nLen = str.GetLength(); + if (nLen > 0) + { + if (str[nLen-1] != '\\' && str[nLen-1] != '/') + str += '\\'; + } +} + +static void FindReplace(Str& strContents, const char* pTag, const char* pValue) +{ + if (strcmp(pTag, pValue) == 0) + return; + for (int nPos = strContents.Find(pTag); nPos >= 0; nPos = strContents.Find(pTag)) + { + int nRightLen = strContents.GetLength() - strlen(pTag) - nPos; + Str strLeft(strContents.Left(nPos)); + Str strRight(strContents.Right(nRightLen)); + strLeft += pValue; + strLeft += strRight; + strContents = strLeft; + } +} + + + + + +void ClearFileList(FILELIST **list) +{ + FILELIST *temp; + + while(*list) + { + temp = *list; + *list = (*list)->next; + free(temp); + } +} + +void ClearDirList(DIRLIST **list) +{ + DIRLIST *temp; + + while(*list) + { + temp = *list; + *list = (*list)->next; + free(temp); + } +} + +DIRECTORY *FindPakDir(DIRECTORY *dir, char *name) +{ + DIRECTORY *currentPtr; + + for(currentPtr = dir; currentPtr; currentPtr = currentPtr->next) + { + if(!stricmp(name, currentPtr->name)) + { + return currentPtr; + } + } + return NULL; +} + + +// LoadPK3FileList +// --------------- +// +// This gets passed a file mask which we want to remove as +// we are only interested in the directory name and any given +// extension. Only handles explicit filenames or *.something +// +bool LoadPK3FileList(FILELIST **filelist, const char *pattern) +{ + char cSearch[WORK_LEN]; + __ConvertDOSToUnixName( cSearch, pattern ); + char cPath[WORK_LEN]; + char cExt[WORK_LEN]; + char cFile[WORK_LEN]; + char cWork[WORK_LEN]; + __ExtractFilePath(pattern, cPath); + __ExtractFileName(pattern, cFile); + __ExtractFileExtension(pattern, cExt); + const char *pCompare = (strnicmp(cFile, "*.", 2) == 0) ? cExt : cFile; + + PK3List *p = g_PK3Files.Next(); + while (p != NULL) + { + // qualify the path + PK3FileInfo *pKey = p->Ptr(); + if (strstr(pKey->m_pName, cPath) && strstr(pKey->m_pName, pCompare)) + { + __ExtractFileName(pKey->m_pName, cWork); + AddToFileListAlphabetized(filelist, cWork, 0, 0, false); + } + p = p->Next(); + } + return (*filelist) != NULL; +} + +bool GetPackFileList(FILELIST **filelist, char *pattern) +{ + char *str1, *str2; + int i; + DIRECTORY *dummy = paktextures; + FILELIST *temp; + + if (!pakopen) + return false; + + if (g_bPK3) + { + return LoadPK3FileList(filelist, pattern); + } + + str1 = pattern; + + for(i = 0; pattern[i] != '\0'; i++) + { + if(pattern[i] == '\\') + pattern[i] = '/'; + } + + while(strchr(str1, '/')) + { + str2 = strchr(str1, '/'); + *str2++ = '\0'; + dummy = FindPakDir(dummy, str1); + if(!dummy) + return false; + str1 = str2; + } + for(temp = dummy->files; temp; temp=temp->next) + { + AddToFileListAlphabetized(filelist, temp->filename, temp->offset, 0, false); + } + return true; +} + +bool GetPackTextureDirs(DIRLIST **dirlist) +{ + UInt16 i; + char buf[57]; + + if (!pakopen) + return 1; + + if (g_bPK3) + { + StrList *pl = g_PK3TexturePaths.Next(); + while (pl != NULL) + { + AddToDirListAlphabetized(dirlist, pl->Ref(), 0); + pl = pl->Next(); + } + return true; + } + + for (i = 0; i < dirsize; i++) + { + if(!strnicmp(pakdirptr[i].name, "textures", 8)) + { + strncpy(buf, &(pakdirptr[i].name[9]), 46); + if(strchr(buf, '\\')) + *strchr(buf, '\\') = '\0'; + else if(strchr(buf, '/')) + *strchr(buf, '/') = '\0'; + else + buf[56] = '\0'; + + if(strchr(buf, '.')) + continue; + + AddToDirListAlphabetized(dirlist, buf, 0); + } + } + return true; +} + +bool AddToDirListAlphabetized(DIRLIST **list, char *dirname, int from) +{ + DIRLIST *currentPtr, *previousPtr, *newPtr; + + strlwr(dirname); + for(currentPtr = *list; currentPtr; currentPtr = currentPtr->next) + { + if(!stricmp(dirname, currentPtr->dirname)) + { + return false; + } + } + previousPtr = NULL; + currentPtr = *list; + + if((newPtr = (DIRLIST *)__qmalloc(sizeof(DIRLIST))) == NULL) + return false; + + strcpy(newPtr->dirname, dirname); + newPtr->from = from; + + while(currentPtr != NULL && stricmp(dirname, currentPtr->dirname) > 0) + { + previousPtr = currentPtr; + currentPtr = currentPtr->next; + } //End while + if(previousPtr == NULL) + { + newPtr->next = *list; + *list = newPtr; + } //End if + else + { + previousPtr->next = newPtr; + newPtr->next = currentPtr; + } //End else + return true; +} + +bool AddToFileListAlphabetized(FILELIST **list, char *filename, UInt32 offset, UInt32 size, bool dirs) +{ + FILELIST *currentPtr, *previousPtr, *newPtr; + + for(currentPtr = *list; currentPtr; currentPtr = currentPtr->next) + { + if(!stricmp(filename, currentPtr->filename)) + { + return false; + } + } + previousPtr = NULL; + currentPtr = *list; + + if((newPtr = (FILELIST *)__qmalloc(sizeof(FILELIST))) == NULL) + return false; + + strcpy(newPtr->filename, filename); + newPtr->offset = offset; + newPtr->size = size; + + while(currentPtr != NULL && stricmp(filename, currentPtr->filename) > 0) + { + previousPtr = currentPtr; + currentPtr = currentPtr->next; + } //End while + if(previousPtr == NULL) + { + newPtr->next = *list; + *list = newPtr; + } //End if + else + { + previousPtr->next = newPtr; + newPtr->next = currentPtr; + } //End else + return true; +} + +int PakLoadAnyFile(const char *filename, void **bufferptr) +{ + char cWork[WORK_LEN]; + if (g_bPK3) + { + // leo: hack to be able to use pak files from multiple directories + for (int i = 0; i < g_numBasePaths; i++) + { + PK3FileInfo *pInfo; + Str strKey; + // need to lookup the file without the base/texture path on it + Str strBase(g_strBasePaths[i]); + AddSlash(strBase); + __ConvertDOSToUnixName(cWork, strBase); + Str strFile(filename); + __ConvertDOSToUnixName(strFile, strFile); + strFile.MakeLower(); + strlwr(cWork); + FindReplace(strFile, cWork, ""); + + PK3FileInfo infoFind; + infoFind.m_pName = __StrDup(strFile.GetBuffer()); + PK3List *pList = g_PK3Files.Find(&infoFind); + if (pList) + { + pInfo = pList->Ptr(); + memcpy(pInfo->m_zFile, &pInfo->m_zInfo, sizeof(unz_s)); + if (unzOpenCurrentFile(pInfo->m_zFile) == UNZ_OK) + { + void *buffer = __qblockmalloc(pInfo->m_lSize+1); + int n = unzReadCurrentFile(pInfo->m_zFile , buffer, pInfo->m_lSize); + *bufferptr = buffer; + unzCloseCurrentFile(pInfo->m_zFile); + return n; + } + } + } + +#ifdef LOG_PAKFAIL + sprintf(cWork, "PAK failed on %s\n", filename); + g_LogFile.Log(cWork); +#endif + return -1; + } + + for (int i = 0; i < dirsize; i++) + { + if(!stricmp(filename, pakdirptr[i].name)) + { + if (fseek(pakfile[m_nPAKIndex], pakdirptr[i].offset, SEEK_SET) >= 0) + { + void *buffer = __qmalloc (pakdirptr[i].size+1); + ((char *)buffer)[pakdirptr[i].size] = 0; + if (fread(buffer, 1, pakdirptr[i].size, pakfile[m_nPAKIndex]) == pakdirptr[i].size) + { + *bufferptr = buffer; + return pakdirptr[i].size; + } + } + } + } +#ifdef LOG_PAKFAIL + sprintf(cWork, "PAK failed on %s\n", filename); + g_LogFile.Log(cWork); +#endif + return -1; +} + + + +DIRECTORY *AddPakDir(DIRECTORY **dir, char *name) +{ + DIRECTORY *currentPtr, *previousPtr, *newPtr; + + for(currentPtr = *dir; currentPtr; currentPtr = currentPtr->next) + { + if(!stricmp(name, currentPtr->name)) + { + return currentPtr; + } + } + previousPtr = NULL; + currentPtr = *dir; + + if((newPtr = (DIRECTORY *)__qmalloc(sizeof(DIRECTORY))) == NULL) + return NULL; + + strcpy(newPtr->name, name); + newPtr->files = NULL; + + while(currentPtr != NULL && stricmp(name, currentPtr->name) > 0) + { + previousPtr = currentPtr; + currentPtr = currentPtr->next; + } + if(previousPtr == NULL) + { + newPtr->next = *dir; + *dir = newPtr; + } + else + { + previousPtr->next = newPtr; + newPtr->next = currentPtr; + } + return newPtr; +} + + +// OpenPK3 +// ------- +// Opens a PK3 ( or zip ) file and creates a list of filenames +// and zip info structures +// +bool OpenPK3(const char *filename) +{ + char cFilename[WORK_LEN]; + char cName[WORK_LEN]; + char cWork[WORK_LEN]; + unz_file_info zInfo; + unzFile *zFile = new unzFile(unzOpen(filename)); + g_zFiles.Add(zFile); + if (zFile != NULL) + { + int nStatus = unzGoToFirstFile(*zFile); + while (nStatus == UNZ_OK) + { + cFilename[0] = '\0'; + unzGetCurrentFileInfo(*zFile, &zInfo, cFilename, WORK_LEN, NULL, 0, NULL, 0); + strlwr(cFilename); + __ConvertDOSToUnixName( cWork, cFilename); + if (strstr(cWork, ".") != NULL) + { + PK3FileInfo *pInfo = new PK3FileInfo(); + pInfo->m_pName = __StrDup(cWork); + memcpy(&pInfo->m_zInfo, (unz_s*)*zFile, sizeof(unz_s)); + pInfo->m_lSize = zInfo.uncompressed_size; + pInfo->m_zFile = *zFile; + g_PK3Files.Add(pInfo); + } + char *p = strstr(cFilename, TEXTURE_PATH); + if (p != NULL) + { + // FIXME: path differences per os ? + // catch solo directory entry + if (strlen(p) > strlen(TEXTURE_PATH) + 1) + { + // skip textures + path seperator + p += strlen(TEXTURE_PATH) + 1; + int nEnd = strcspn(p, PATH_SEPERATORS); + strncpy(cName, p, nEnd); + cName[nEnd] = '\0'; + + bool bFound = false; + StrList *pl = g_PK3TexturePaths.Next(); + while (pl != NULL) + { + if (strcmpi(pl->Ref(), cName) == 0) + { + // already have this, continue + bFound = true; + break; + } + pl = pl->Next(); + } + if (!bFound) + { + g_PK3TexturePaths.Add(new Str(cName)); + } + } + } + nStatus = unzGoToNextFile(*zFile); + } + } + return (zFile != NULL); +} + +void closePK3(unzFile zf) +{ + unzClose(zf); +} + +void OpenPakFile(const char *filename) +{ + if(!pakopen) + paktextures = NULL; + + pakopen = g_bPK3 = OpenPK3(filename); +} + +void ClearPaKDir(DIRECTORY **dir) +{ + DIRECTORY *d1 = *dir, *d2; + + while(d1) + { + ClearFileList(&(d1->files)); + d2 = d1; + d1 = d1->next; + free(d2); + } +} + +void CleanUpPakDirs() +{ + ClearPaKDir(&paktextures); + paktextures = NULL; + dirhead = NULL; + g_PK3TexturePaths.RemoveAll(); + g_PK3Files.RemoveAll(); +} + +void ClosePakFile(void) +{ + if(pakopen) + { + if (g_bPK3) + { + ZFileList *p = g_zFiles.Next(); + while (p != NULL) + { + unzFile uz = p->Ref(); + closePK3(uz); + p = p->Next(); + } + } + else + { + fclose(pakfile[m_nPAKIndex]); + } + } + pakopen = false; + CleanUpPakDirs(); +} + + +void WINAPI InitPakFile(const char * pBasePath, const char *pName) +{ + if (g_numBasePaths == 0) + { + m_nPAKIndex = 0; + pakopen = false; + paktextures = NULL; + } + strcpy(g_strBasePaths[g_numBasePaths], pBasePath); + g_numBasePaths++; + + if (pName == NULL) + { + //++timo FIXME: use some kind of compatibility lib here! +#if defined (__linux__) || defined (__APPLE__) + char cWork[WORK_LEN]; + struct dirent *dirlist; + DIR *dir; + + dir = opendir (pBasePath); + if (dir != NULL) + { + while ((dirlist = readdir (dir)) != NULL) + { + if (strstr (dirlist->d_name, ".pk3") == NULL) + continue; + sprintf(cWork, "%s/%s", pBasePath, dirlist->d_name); + OpenPakFile(cWork); + } + closedir (dir); + } +#endif +#ifdef _WIN32 + char cWork[WORK_LEN]; + Str strPath(pBasePath); + AddSlash(strPath); + strPath += "*.pk3"; + bool bGo = true; + struct _finddata_t fileinfo; + int handle = _findfirst (strPath, &fileinfo); + if (handle != -1) + { + do + { + sprintf(cWork, "%s/%s", pBasePath, fileinfo.name); + OpenPakFile(cWork); + } while (_findnext( handle, &fileinfo ) != -1); + _findclose (handle); + } +#endif + } + else + { + OpenPakFile(pName); + } +} + diff --git a/libs/pak/unzip.cpp b/libs/pak/unzip.cpp index 304dc6d3..5cf24528 100644 --- a/libs/pak/unzip.cpp +++ b/libs/pak/unzip.cpp @@ -1,4534 +1,4534 @@ -/***************************************************************************** - * name: unzip.c - * - * desc: IO on .zip files using portions of zlib - * - * - *****************************************************************************/ - -#include -#include -#include -#include "unzip.h" - -typedef unsigned char byte; - -/* unzip.h -- IO for uncompress .zip files using zlib - Version 0.15 beta, Mar 19th, 1998, - - Copyright (C) 1998 Gilles Vollant - - This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g - WinZip, InfoZip tools and compatible. - Encryption and multi volume ZipFile (span) are not supported. - Old compressions used by old PKZip 1.x are not supported - - THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE - CAN CHANGE IN FUTURE VERSION !! - I WAIT FEEDBACK at mail info@winimage.com - Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution - - Condition of use and distribution are the same than zlib : - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - -*/ -/* for more info about .ZIP format, see - ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip - PkWare has also a specification at : - ftp://ftp.pkware.com/probdesc.zip */ - -/* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.1.3, July 9th, 1998 - - Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - - - The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt - (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). -*/ - -/* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-1998 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifndef _ZCONF_H -#define _ZCONF_H - -/* Maximum value for memLevel in deflateInit2 */ -#ifndef MAX_MEM_LEVEL -# ifdef MAXSEG_64K -# define MAX_MEM_LEVEL 8 -# else -# define MAX_MEM_LEVEL 9 -# endif -#endif - -/* Maximum value for windowBits in deflateInit2 and inflateInit2. - * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files - * created by gzip. (Files created by minigzip can still be extracted by - * gzip.) - */ -#ifndef MAX_WBITS -# define MAX_WBITS 15 /* 32K LZ77 window */ -#endif - -/* The memory requirements for deflate are (in bytes): - (1 << (windowBits+2)) + (1 << (memLevel+9)) - that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) - plus a few kilobytes for small objects. For example, if you want to reduce - the default memory requirements from 256K to 128K, compile with - make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" - Of course this will generally degrade compression (there's no free lunch). - - The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes - for small objects. -*/ - - /* Type declarations */ - -#ifndef OF /* function prototypes */ -#define OF(args) args -#endif - -typedef unsigned char Byte; /* 8 bits */ -typedef unsigned int uInt; /* 16 bits or more */ -typedef unsigned long uLong; /* 32 bits or more */ -typedef Byte *voidp; - -#ifndef SEEK_SET -# define SEEK_SET 0 /* Seek from beginning of file. */ -# define SEEK_CUR 1 /* Seek from current position. */ -# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ -#endif - -#endif /* _ZCONF_H */ - -#define ZLIB_VERSION "1.1.3" - -/* - The 'zlib' compression library provides in-memory compression and - decompression functions, including integrity checks of the uncompressed - data. This version of the library supports only one compression method - (deflation) but other algorithms will be added later and will have the same - stream interface. - - Compression can be done in a single step if the buffers are large - enough (for example if an input file is mmap'ed), or can be done by - repeated calls of the compression function. In the latter case, the - application must provide more input and/or consume the output - (providing more output space) before each call. - - The library also supports reading and writing files in gzip (.gz) format - with an interface similar to that of stdio. - - The library does not install any signal handler. The decoder checks - the consistency of the compressed data, so the library should never - crash even in case of corrupted input. -*/ - -/* - The application must update next_in and avail_in when avail_in has - dropped to zero. It must update next_out and avail_out when avail_out - has dropped to zero. The application must initialize zalloc, zfree and - opaque before calling the init function. All other fields are set by the - compression library and must not be updated by the application. - - The opaque value provided by the application will be passed as the first - parameter for calls of zalloc and zfree. This can be useful for custom - memory management. The compression library attaches no meaning to the - opaque value. - - zalloc must return Z_NULL if there is not enough memory for the object. - If zlib is used in a multi-threaded application, zalloc and zfree must be - thread safe. - - On 16-bit systems, the functions zalloc and zfree must be able to allocate - exactly 65536 bytes, but will not be required to allocate more than this - if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, - pointers returned by zalloc for objects of exactly 65536 bytes *must* - have their offset normalized to zero. The default allocation function - provided by this library ensures this (see zutil.c). To reduce memory - requirements and avoid any allocation of 64K objects, at the expense of - compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). - - The fields total_in and total_out can be used for statistics or - progress reports. After compression, total_in holds the total size of - the uncompressed data and may be saved for use in the decompressor - (particularly if the decompressor wants to decompress everything in - a single step). -*/ - - /* constants */ - -#define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ -#define Z_SYNC_FLUSH 2 -#define Z_FULL_FLUSH 3 -#define Z_FINISH 4 -/* Allowed flush values; see deflate() below for details */ - -#define Z_OK 0 -#define Z_STREAM_END 1 -#define Z_NEED_DICT 2 -#define Z_ERRNO (-1) -#define Z_STREAM_ERROR (-2) -#define Z_DATA_ERROR (-3) -#define Z_MEM_ERROR (-4) -#define Z_BUF_ERROR (-5) -#define Z_VERSION_ERROR (-6) -/* Return codes for the compression/decompression functions. Negative - * values are errors, positive values are used for special but normal events. - */ - -#define Z_NO_COMPRESSION 0 -#define Z_BEST_SPEED 1 -#define Z_BEST_COMPRESSION 9 -#define Z_DEFAULT_COMPRESSION (-1) -/* compression levels */ - -#define Z_FILTERED 1 -#define Z_HUFFMAN_ONLY 2 -#define Z_DEFAULT_STRATEGY 0 -/* compression strategy; see deflateInit2() below for details */ - -#define Z_BINARY 0 -#define Z_ASCII 1 -#define Z_UNKNOWN 2 -/* Possible values of the data_type field */ - -#define Z_DEFLATED 8 -/* The deflate compression method (the only one supported in this version) */ - -#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ - -#define zlib_version zlibVersion() -/* for compatibility with versions < 1.0.2 */ - - /* basic functions */ - -const char * zlibVersion OF((void)); -/* The application can compare zlibVersion and ZLIB_VERSION for consistency. - If the first character differs, the library code actually used is - not compatible with the zlib.h header file used by the application. - This check is automatically made by deflateInit and inflateInit. - */ - -/* -int deflateInit OF((z_streamp strm, int level)); - - Initializes the internal stream state for compression. The fields - zalloc, zfree and opaque must be initialized before by the caller. - If zalloc and zfree are set to Z_NULL, deflateInit updates them to - use default allocation functions. - - The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: - 1 gives best speed, 9 gives best compression, 0 gives no compression at - all (the input data is simply copied a block at a time). - Z_DEFAULT_COMPRESSION requests a default compromise between speed and - compression (currently equivalent to level 6). - - deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if level is not a valid compression level, - Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible - with the version assumed by the caller (ZLIB_VERSION). - msg is set to null if there is no error message. deflateInit does not - perform any compression: this will be done by deflate(). -*/ - - -int deflate OF((z_streamp strm, int flush)); -/* - deflate compresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce some - output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. deflate performs one or both of the - following actions: - - - Compress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in and avail_in are updated and - processing will resume at this point for the next call of deflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. This action is forced if the parameter flush is non zero. - Forcing flush frequently degrades the compression ratio, so this parameter - should be set only when necessary (in interactive applications). - Some output may be provided even if flush is not set. - - Before the call of deflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating avail_in or avail_out accordingly; avail_out - should never be zero before the call. The application can consume the - compressed output when it wants, for example when the output buffer is full - (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK - and with zero avail_out, it must be called again after making room in the - output buffer because there might be more output pending. - - If the parameter flush is set to Z_SYNC_FLUSH, all pending output is - flushed to the output buffer and the output is aligned on a byte boundary, so - that the decompressor can get all input data available so far. (In particular - avail_in is zero after the call if enough output space has been provided - before the call.) Flushing may degrade compression for some compression - algorithms and so it should be used only when necessary. - - If flush is set to Z_FULL_FLUSH, all output is flushed as with - Z_SYNC_FLUSH, and the compression state is reset so that decompression can - restart from this point if previous compressed data has been damaged or if - random access is desired. Using Z_FULL_FLUSH too often can seriously degrade - the compression. - - If deflate returns with avail_out == 0, this function must be called again - with the same value of the flush parameter and more output space (updated - avail_out), until the flush is complete (deflate returns with non-zero - avail_out). - - If the parameter flush is set to Z_FINISH, pending input is processed, - pending output is flushed and deflate returns with Z_STREAM_END if there - was enough output space; if deflate returns with Z_OK, this function must be - called again with Z_FINISH and more output space (updated avail_out) but no - more input data, until it returns with Z_STREAM_END or an error. After - deflate has returned Z_STREAM_END, the only possible operations on the - stream are deflateReset or deflateEnd. - - Z_FINISH can be used immediately after deflateInit if all the compression - is to be done in a single step. In this case, avail_out must be at least - 0.1% larger than avail_in plus 12 bytes. If deflate does not return - Z_STREAM_END, then it must be called again as described above. - - deflate() sets strm->adler to the adler32 checksum of all input read - so (that is, total_in bytes). - - deflate() may update data_type if it can make a good guess about - the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered - binary. This field is only for information purposes and does not affect - the compression algorithm in any manner. - - deflate() returns Z_OK if some progress has been made (more input - processed or more output produced), Z_STREAM_END if all input has been - consumed and all output has been produced (only when flush is set to - Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example - if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible - (for example avail_in or avail_out was zero). -*/ - - -int deflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the - stream state was inconsistent, Z_DATA_ERROR if the stream was freed - prematurely (some input or output was discarded). In the error case, - msg may be set but then points to a static string (which must not be - deallocated). -*/ - - -/* -int inflateInit OF((z_streamp strm)); - - Initializes the internal stream state for decompression. The fields - next_in, avail_in, zalloc, zfree and opaque must be initialized before by - the caller. If next_in is not Z_NULL and avail_in is large enough (the exact - value depends on the compression method), inflateInit determines the - compression method from the zlib header and allocates all data structures - accordingly; otherwise the allocation will be deferred to the first call of - inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to - use default allocation functions. - - inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_VERSION_ERROR if the zlib library version is incompatible with the - version assumed by the caller. msg is set to null if there is no error - message. inflateInit does not perform any decompression apart from reading - the zlib header if present: this will be done by inflate(). (So next_in and - avail_in may be modified, but next_out and avail_out are unchanged.) -*/ - - -int inflate OF((z_streamp strm, int flush)); -/* - inflate decompresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may some - introduce some output latency (reading input without producing any output) - except when forced to flush. - - The detailed semantics are as follows. inflate performs one or both of the - following actions: - - - Decompress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in is updated and processing - will resume at this point for the next call of inflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. inflate() provides as much output as possible, until there - is no more input data or no more space in the output buffer (see below - about the flush parameter). - - Before the call of inflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating the next_* and avail_* values accordingly. - The application can consume the uncompressed output when it wants, for - example when the output buffer is full (avail_out == 0), or after each - call of inflate(). If inflate returns Z_OK and with zero avail_out, it - must be called again after making room in the output buffer because there - might be more output pending. - - If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much - output as possible to the output buffer. The flushing behavior of inflate is - not specified for values of the flush parameter other than Z_SYNC_FLUSH - and Z_FINISH, but the current implementation actually flushes as much output - as possible anyway. - - inflate() should normally be called until it returns Z_STREAM_END or an - error. However if all decompression is to be performed in a single step - (a single call of inflate), the parameter flush should be set to - Z_FINISH. In this case all pending input is processed and all pending - output is flushed; avail_out must be large enough to hold all the - uncompressed data. (The size of the uncompressed data may have been saved - by the compressor for this purpose.) The next operation on this stream must - be inflateEnd to deallocate the decompression state. The use of Z_FINISH - is never required, but can be used to inform inflate that a faster routine - may be used for the single inflate() call. - - If a preset dictionary is needed at this point (see inflateSetDictionary - below), inflate sets strm-adler to the adler32 checksum of the - dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise - it sets strm->adler to the adler32 checksum of all output produced - so (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or - an error code as described below. At the end of the stream, inflate() - checks that its computed adler32 checksum is equal to that saved by the - compressor and returns Z_STREAM_END only if the checksum is correct. - - inflate() returns Z_OK if some progress has been made (more input processed - or more output produced), Z_STREAM_END if the end of the compressed data has - been reached and all uncompressed output has been produced, Z_NEED_DICT if a - preset dictionary is needed at this point, Z_DATA_ERROR if the input data was - corrupted (input stream not conforming to the zlib format or incorrect - adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent - (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if no progress is possible or if there was not - enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR - case, the application may then call inflateSync to look for a good - compression block. -*/ - - -int inflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state - was inconsistent. In the error case, msg may be set but then points to a - static string (which must not be deallocated). -*/ - - /* Advanced functions */ - -/* - The following functions are needed only in some special applications. -*/ - -/* -int deflateInit2 OF((z_streamp strm, - int level, - int method, - int windowBits, - int memLevel, - int strategy)); - - This is another version of deflateInit with more compression options. The - fields next_in, zalloc, zfree and opaque must be initialized before by - the caller. - - The method parameter is the compression method. It must be Z_DEFLATED in - this version of the library. - - The windowBits parameter is the base two logarithm of the window size - (the size of the history buffer). It should be in the range 8..15 for this - version of the library. Larger values of this parameter result in better - compression at the expense of memory usage. The default value is 15 if - deflateInit is used instead. - - The memLevel parameter specifies how much memory should be allocated - for the internal compression state. memLevel=1 uses minimum memory but - is slow and reduces compression ratio; memLevel=9 uses maximum memory - for optimal speed. The default value is 8. See zconf.h for total memory - usage as a function of windowBits and memLevel. - - The strategy parameter is used to tune the compression algorithm. Use the - value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a - filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no - string match). Filtered data consists mostly of small values with a - somewhat random distribution. In this case, the compression algorithm is - tuned to compress them better. The effect of Z_FILTERED is to force more - Huffman coding and less string matching; it is somewhat intermediate - between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects - the compression ratio but not the correctness of the compressed output even - if it is not set appropriately. - - deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid - method). msg is set to null if there is no error message. deflateInit2 does - not perform any compression: this will be done by deflate(). -*/ - -int deflateSetDictionary OF((z_streamp strm, - const Byte *dictionary, - uInt dictLength)); -/* - Initializes the compression dictionary from the given byte sequence - without producing any compressed output. This function must be called - immediately after deflateInit, deflateInit2 or deflateReset, before any - call of deflate. The compressor and decompressor must use exactly the same - dictionary (see inflateSetDictionary). - - The dictionary should consist of strings (byte sequences) that are likely - to be encountered later in the data to be compressed, with the most commonly - used strings preferably put towards the end of the dictionary. Using a - dictionary is most useful when the data to be compressed is short and can be - predicted with good accuracy; the data can then be compressed better than - with the default empty dictionary. - - Depending on the size of the compression data structures selected by - deflateInit or deflateInit2, a part of the dictionary may in effect be - discarded, for example if the dictionary is larger than the window size in - deflate or deflate2. Thus the strings most likely to be useful should be - put at the end of the dictionary, not at the front. - - Upon return of this function, strm->adler is set to the Adler32 value - of the dictionary; the decompressor may later use this value to determine - which dictionary has been used by the compressor. (The Adler32 value - applies to the whole dictionary even if only a subset of the dictionary is - actually used by the compressor.) - - deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is - inconsistent (for example if deflate has already been called for this stream - or if the compression method is bsort). deflateSetDictionary does not - perform any compression: this will be done by deflate(). -*/ - -int deflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when several compression strategies will be - tried, for example when there are several ways of pre-processing the input - data with a filter. The streams that will be discarded should then be freed - by calling deflateEnd. Note that deflateCopy duplicates the internal - compression state which can be quite large, so this strategy is slow and - can consume lots of memory. - - deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. -*/ - -int deflateReset OF((z_streamp strm)); -/* - This function is equivalent to deflateEnd followed by deflateInit, - but does not free and reallocate all the internal compression state. - The stream will keep the same compression level and any other attributes - that may have been set by deflateInit2. - - deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -int deflateParams OF((z_streamp strm, - int level, - int strategy)); -/* - Dynamically update the compression level and compression strategy. The - interpretation of level and strategy is as in deflateInit2. This can be - used to switch between compression and straight copy of the input data, or - to switch to a different kind of input data requiring a different - strategy. If the compression level is changed, the input available so far - is compressed with the old level (and may be flushed); the new level will - take effect only at the next call of deflate(). - - Before the call of deflateParams, the stream state must be set as for - a call of deflate(), since the currently available input may have to - be compressed and flushed. In particular, strm->avail_out must be non-zero. - - deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source - stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR - if strm->avail_out was zero. -*/ - -/* -int inflateInit2 OF((z_streamp strm, - int windowBits)); - - This is another version of inflateInit with an extra parameter. The - fields next_in, avail_in, zalloc, zfree and opaque must be initialized - before by the caller. - - The windowBits parameter is the base two logarithm of the maximum window - size (the size of the history buffer). It should be in the range 8..15 for - this version of the library. The default value is 15 if inflateInit is used - instead. If a compressed stream with a larger window size is given as - input, inflate() will return with the error code Z_DATA_ERROR instead of - trying to allocate a larger window. - - inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative - memLevel). msg is set to null if there is no error message. inflateInit2 - does not perform any decompression apart from reading the zlib header if - present: this will be done by inflate(). (So next_in and avail_in may be - modified, but next_out and avail_out are unchanged.) -*/ - -int inflateSetDictionary OF((z_streamp strm, - const Byte *dictionary, - uInt dictLength)); -/* - Initializes the decompression dictionary from the given uncompressed byte - sequence. This function must be called immediately after a call of inflate - if this call returned Z_NEED_DICT. The dictionary chosen by the compressor - can be determined from the Adler32 value returned by this call of - inflate. The compressor and decompressor must use exactly the same - dictionary (see deflateSetDictionary). - - inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is - inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the - expected one (incorrect Adler32 value). inflateSetDictionary does not - perform any decompression: this will be done by subsequent calls of - inflate(). -*/ - -int inflateSync OF((z_streamp strm)); -/* - Skips invalid compressed data until a full flush point (see above the - description of deflate with Z_FULL_FLUSH) can be found, or until all - available input is skipped. No output is provided. - - inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR - if no more input was provided, Z_DATA_ERROR if no flush point has been found, - or Z_STREAM_ERROR if the stream structure was inconsistent. In the success - case, the application may save the current current value of total_in which - indicates where valid compressed data was found. In the error case, the - application may repeatedly call inflateSync, providing more input each time, - until success or end of the input data. -*/ - -int inflateReset OF((z_streamp strm)); -/* - This function is equivalent to inflateEnd followed by inflateInit, - but does not free and reallocate all the internal decompression state. - The stream will keep attributes that may have been set by inflateInit2. - - inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - - - /* utility functions */ - -/* - The following utility functions are implemented on top of the - basic stream-oriented functions. To simplify the interface, some - default options are assumed (compression level and memory usage, - standard memory allocation functions). The source code of these - utility functions can easily be modified if you need special options. -*/ - -int compress OF((Byte *dest, uLong *destLen, - const Byte *source, uLong sourceLen)); -/* - Compresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be at least 0.1% larger than - sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the - compressed buffer. - This function can be used to compress a whole file at once if the - input file is mmap'ed. - compress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer. -*/ - -int compress2 OF((Byte *dest, uLong *destLen, - const Byte *source, uLong sourceLen, - int level)); -/* - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least 0.1% larger than sourceLen plus - 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ - -int uncompress OF((Byte *dest, uLong *destLen, - const Byte *source, uLong sourceLen)); -/* - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be large enough to hold the - entire uncompressed data. (The size of the uncompressed data must have - been saved previously by the compressor and transmitted to the decompressor - by some mechanism outside the scope of this compression library.) - Upon exit, destLen is the actual size of the compressed buffer. - This function can be used to decompress a whole file at once if the - input file is mmap'ed. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted. -*/ - - -typedef voidp gzFile; - -gzFile gzopen OF((const char *path, const char *mode)); -/* - Opens a gzip (.gz) file for reading or writing. The mode parameter - is as in fopen ("rb" or "wb") but can also include a compression level - ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for - Huffman only compression as in "wb1h". (See the description - of deflateInit2 for more information about the strategy parameter.) - - gzopen can be used to read a file which is not in gzip format; in this - case gzread will directly read from the file without decompression. - - gzopen returns NULL if the file could not be opened or if there was - insufficient memory to allocate the (de)compression state; errno - can be checked to distinguish the two cases (if errno is zero, the - zlib error is Z_MEM_ERROR). */ - -gzFile gzdopen OF((int fd, const char *mode)); -/* - gzdopen() associates a gzFile with the file descriptor fd. File - descriptors are obtained from calls like open, dup, creat, pipe or - fileno (in the file has been previously opened with fopen). - The mode parameter is as in gzopen. - The next call of gzclose on the returned gzFile will also close the - file descriptor fd, just like fclose(fdopen(fd), mode) closes the file - descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). - gzdopen returns NULL if there was insufficient memory to allocate - the (de)compression state. -*/ - -int gzsetparams OF((gzFile file, int level, int strategy)); -/* - Dynamically update the compression level or strategy. See the description - of deflateInit2 for the meaning of these parameters. - gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not - opened for writing. -*/ - -int gzread OF((gzFile file, voidp buf, unsigned len)); -/* - Reads the given number of uncompressed bytes from the compressed file. - If the input file was not in gzip format, gzread copies the given number - of bytes into the buffer. - gzread returns the number of uncompressed bytes actually read (0 for - end of file, -1 for error). */ - -int gzwrite OF((gzFile file, - const voidp buf, unsigned len)); -/* - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of uncompressed bytes actually written - (0 in case of error). -*/ - -int gzprintf OF((gzFile file, const char *format, ...)); -/* - Converts, formats, and writes the args to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written (0 in case of error). -*/ - -int gzputs OF((gzFile file, const char *s)); -/* - Writes the given null-terminated string to the compressed file, excluding - the terminating null character. - gzputs returns the number of characters written, or -1 in case of error. -*/ - -char * gzgets OF((gzFile file, char *buf, int len)); -/* - Reads bytes from the compressed file until len-1 characters are read, or - a newline character is read and transferred to buf, or an end-of-file - condition is encountered. The string is then terminated with a null - character. - gzgets returns buf, or Z_NULL in case of error. -*/ - -int gzputc OF((gzFile file, int c)); -/* - Writes c, converted to an unsigned char, into the compressed file. - gzputc returns the value that was written, or -1 in case of error. -*/ - -int gzgetc OF((gzFile file)); -/* - Reads one byte from the compressed file. gzgetc returns this byte - or -1 in case of end of file or error. -*/ - -int gzflush OF((gzFile file, int flush)); -/* - Flushes all pending output into the compressed file. The parameter - flush is as in the deflate() function. The return value is the zlib - error number (see function gzerror below). gzflush returns Z_OK if - the flush parameter is Z_FINISH and all output could be flushed. - gzflush should be called only when strictly necessary because it can - degrade compression. -*/ - -long gzseek OF((gzFile file, - long offset, int whence)); -/* - Sets the starting position for the next gzread or gzwrite on the - given compressed file. The offset represents a number of bytes in the - uncompressed data stream. The whence parameter is defined as in lseek(2); - the value SEEK_END is not supported. - If the file is opened for reading, this function is emulated but can be - extremely slow. If the file is opened for writing, only forward seeks are - supported; gzseek then compresses a sequence of zeroes up to the new - starting position. - - gzseek returns the resulting offset location as measured in bytes from - the beginning of the uncompressed stream, or -1 in case of error, in - particular if the file is opened for writing and the new starting position - would be before the current position. -*/ - -int gzrewind OF((gzFile file)); -/* - Rewinds the given file. This function is supported only for reading. - - gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) -*/ - -long gztell OF((gzFile file)); -/* - Returns the starting position for the next gzread or gzwrite on the - given compressed file. This position represents a number of bytes in the - uncompressed data stream. - - gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) -*/ - -int gzeof OF((gzFile file)); -/* - Returns 1 when EOF has previously been detected reading the given - input stream, otherwise zero. -*/ - -int gzclose OF((gzFile file)); -/* - Flushes all pending output if necessary, closes the compressed file - and deallocates all the (de)compression state. The return value is the zlib - error number (see function gzerror below). -*/ - -const char * gzerror OF((gzFile file, int *errnum)); -/* - Returns the error message for the last error which occurred on the - given compressed file. errnum is set to zlib error number. If an - error occurred in the file system and not in the compression library, - errnum is set to Z_ERRNO and the application may consult errno - to get the exact error code. -*/ - - /* checksum functions */ - -/* - These functions are not related to compression but are exported - anyway because they might be useful in applications using the - compression library. -*/ - -uLong adler32 OF((uLong adler, const Byte *buf, uInt len)); - -/* - Update a running Adler-32 checksum with the bytes buf[0..len-1] and - return the updated checksum. If buf is NULL, this function returns - the required initial value for the checksum. - An Adler-32 checksum is almost as reliable as a CRC32 but can be computed - much faster. Usage example: - - uLong adler = adler32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - adler = adler32(adler, buffer, length); - } - if (adler != original_adler) error(); -*/ - -uLong crc32 OF((uLong crc, const Byte *buf, uInt len)); -/* - Update a running crc with the bytes buf[0..len-1] and return the updated - crc. If buf is NULL, this function returns the required initial value - for the crc. Pre- and post-conditioning (one's complement) is performed - within this function so it shouldn't be done by the application. - Usage example: - - uLong crc = crc32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - crc = crc32(crc, buffer, length); - } - if (crc != original_crc) error(); -*/ - -// private stuff to not include cmdlib.h -/* -============================================================================ - - BYTE ORDER FUNCTIONS - -============================================================================ -*/ - -#ifdef _SGI_SOURCE -#define __BIG_ENDIAN__ -#endif - -#ifdef __BIG_ENDIAN__ - -short __LittleShort (short l) -{ - byte b1,b2; - - b1 = l&255; - b2 = (l>>8)&255; - - return (b1<<8) + b2; -} - -short __BigShort (short l) -{ - return l; -} - - -int __LittleLong (int l) -{ - byte b1,b2,b3,b4; - - b1 = l&255; - b2 = (l>>8)&255; - b3 = (l>>16)&255; - b4 = (l>>24)&255; - - return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; -} - -int __BigLong (int l) -{ - return l; -} - - -float __LittleFloat (float l) -{ - union {byte b[4]; float f;} in, out; - - in.f = l; - out.b[0] = in.b[3]; - out.b[1] = in.b[2]; - out.b[2] = in.b[1]; - out.b[3] = in.b[0]; - - return out.f; -} - -float __BigFloat (float l) -{ - return l; -} - - -#else - - -short __BigShort (short l) -{ - byte b1,b2; - - b1 = l&255; - b2 = (l>>8)&255; - - return (b1<<8) + b2; -} - -short __LittleShort (short l) -{ - return l; -} - - -int __BigLong (int l) -{ - byte b1,b2,b3,b4; - - b1 = l&255; - b2 = (l>>8)&255; - b3 = (l>>16)&255; - b4 = (l>>24)&255; - - return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; -} - -int __LittleLong (int l) -{ - return l; -} - -float __BigFloat (float l) -{ - union {byte b[4]; float f;} in, out; - - in.f = l; - out.b[0] = in.b[3]; - out.b[1] = in.b[2]; - out.b[2] = in.b[1]; - out.b[3] = in.b[0]; - - return out.f; -} - -float __LittleFloat (float l) -{ - return l; -} - - - -#endif - - - - - /* various hacks, don't look :) */ - -/* deflateInit and inflateInit are macros to allow checking the zlib version - * and the compiler's view of z_stream: - */ -int deflateInit_ OF((z_streamp strm, int level, - const char *version, int stream_size)); -int inflateInit_ OF((z_streamp strm, - const char *version, int stream_size)); -int deflateInit2_ OF((z_streamp strm, int level, int method, - int windowBits, int memLevel, - int strategy, const char *version, - int stream_size)); -int inflateInit2_ OF((z_streamp strm, int windowBits, - const char *version, int stream_size)); -#define deflateInit(strm, level) \ - deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit(strm) \ - inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) -#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ - deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ - (strategy), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit2(strm, windowBits) \ - inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) - - -const char * zError OF((int err)); -int inflateSyncPoint OF((z_streamp z)); -const uLong * get_crc_table OF((void)); - -typedef unsigned char uch; -typedef unsigned short ush; -typedef unsigned long ulg; - -extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ -/* (size given to avoid silly warnings with Visual C++) */ - -#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] - -#define ERR_RETURN(strm,err) \ - return (strm->msg = (char*)ERR_MSG(err), (err)) -/* To be used only when the state is known to be valid */ - - /* common constants */ - -#ifndef DEF_WBITS -# define DEF_WBITS MAX_WBITS -#endif -/* default windowBits for decompression. MAX_WBITS is for compression only */ - -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif -/* default memLevel */ - -#define STORED_BLOCK 0 -#define STATIC_TREES 1 -#define DYN_TREES 2 -/* The three kinds of block type */ - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -/* The minimum and maximum match lengths */ - -#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ - - /* target dependencies */ - - /* Common defaults */ - -#ifndef OS_CODE -# define OS_CODE 0x03 /* assume Unix */ -#endif - -#ifndef F_OPEN -# define F_OPEN(name, mode) fopen((name), (mode)) -#endif - - /* functions */ - -#ifdef HAVE_STRERROR - extern char *strerror OF((int)); -# define zstrerror(errnum) strerror(errnum) -#else -# define zstrerror(errnum) "" -#endif - -#define zmemcpy memcpy -#define zmemcmp memcmp -#define zmemzero(dest, len) memset(dest, 0, len) - -/* Diagnostic functions */ -#ifdef _ZIP_DEBUG_ - int z_verbose = 0; -# define Assert(cond,msg) assert(cond); - //{if(!(cond)) Sys_Error(msg);} -# define Trace(x) {if (z_verbose>=0) Sys_Error x ;} -# define Tracev(x) {if (z_verbose>0) Sys_Error x ;} -# define Tracevv(x) {if (z_verbose>1) Sys_Error x ;} -# define Tracec(c,x) {if (z_verbose>0 && (c)) Sys_Error x ;} -# define Tracecv(c,x) {if (z_verbose>1 && (c)) Sys_Error x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif - - -typedef uLong (*check_func) OF((uLong check, const Byte *buf, uInt len)); -voidp zcalloc OF((voidp opaque, unsigned items, unsigned size)); -void zcfree OF((voidp opaque, voidp ptr)); - -#define ZALLOC(strm, items, size) \ - (*((strm)->zalloc))((strm)->opaque, (items), (size)) -#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidp)(addr)) -#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} - - -#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \ - !defined(CASESENSITIVITYDEFAULT_NO) -#define CASESENSITIVITYDEFAULT_NO -#endif - - -#ifndef UNZ_BUFSIZE -#define UNZ_BUFSIZE (65536) -#endif - -#ifndef UNZ_MAXFILENAMEINZIP -#define UNZ_MAXFILENAMEINZIP (256) -#endif - -#ifndef ALLOC -# define ALLOC(size) (malloc(size)) -#endif -#ifndef TRYFREE -# define TRYFREE(p) {if (p) free(p);} -#endif - -#define SIZECENTRALDIRITEM (0x2e) -#define SIZEZIPLOCALHEADER (0x1e) - - - -/* =========================================================================== - Read a byte from a gz_stream; update next_in and avail_in. Return EOF - for end of file. - IN assertion: the stream s has been sucessfully opened for reading. -*/ - -/* -static int unzlocal_getByte(FILE *fin,int *pi) -{ - unsigned char c; - int err = fread(&c, 1, 1, fin); - if (err==1) - { - *pi = (int)c; - return UNZ_OK; - } - else - { - if (ferror(fin)) - return UNZ_ERRNO; - else - return UNZ_EOF; - } -} -*/ - -/* =========================================================================== - Reads a long in LSB order from the given gz_stream. Sets -*/ -static int unzlocal_getShort (FILE* fin, uLong *pX) -{ - short v; - - fread( &v, sizeof(v), 1, fin ); - - *pX = __LittleShort( v); - return UNZ_OK; - -/* - uLong x ; - int i; - int err; - - err = unzlocal_getByte(fin,&i); - x = (uLong)i; - - if (err==UNZ_OK) - err = unzlocal_getByte(fin,&i); - x += ((uLong)i)<<8; - - if (err==UNZ_OK) - *pX = x; - else - *pX = 0; - return err; -*/ -} - -static int unzlocal_getLong (FILE *fin, uLong *pX) -{ - int v; - - fread( &v, sizeof(v), 1, fin ); - - *pX = __LittleLong( v); - return UNZ_OK; - -/* - uLong x ; - int i; - int err; - - err = unzlocal_getByte(fin,&i); - x = (uLong)i; - - if (err==UNZ_OK) - err = unzlocal_getByte(fin,&i); - x += ((uLong)i)<<8; - - if (err==UNZ_OK) - err = unzlocal_getByte(fin,&i); - x += ((uLong)i)<<16; - - if (err==UNZ_OK) - err = unzlocal_getByte(fin,&i); - x += ((uLong)i)<<24; - - if (err==UNZ_OK) - *pX = x; - else - *pX = 0; - return err; -*/ -} - - -/* My own strcmpi / strcasecmp */ -static int strcmpcasenosensitive_internal (const char* fileName1,const char* fileName2) -{ - for (;;) - { - char c1=*(fileName1++); - char c2=*(fileName2++); - if ((c1>='a') && (c1<='z')) - c1 -= 0x20; - if ((c2>='a') && (c2<='z')) - c2 -= 0x20; - if (c1=='\0') - return ((c2=='\0') ? 0 : -1); - if (c2=='\0') - return 1; - if (c1c2) - return 1; - } -} - - -#ifdef CASESENSITIVITYDEFAULT_NO -#define CASESENSITIVITYDEFAULTVALUE 2 -#else -#define CASESENSITIVITYDEFAULTVALUE 1 -#endif - -#ifndef STRCMPCASENOSENTIVEFUNCTION -#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal -#endif - -/* - Compare two filename (fileName1,fileName2). - If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) - If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi - or strcasecmp) - If iCaseSenisivity = 0, case sensitivity is defaut of your operating system - (like 1 on Unix, 2 on Windows) - -*/ -extern int unzStringFileNameCompare (const char* fileName1,const char* fileName2,int iCaseSensitivity) -{ - if (iCaseSensitivity==0) - iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; - - if (iCaseSensitivity==1) - return strcmp(fileName1,fileName2); - - return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); -} - -#define BUFREADCOMMENT (0x400) - -/* - Locate the Central directory of a zipfile (at the end, just before - the global comment) -*/ -static uLong unzlocal_SearchCentralDir(FILE *fin) -{ - unsigned char* buf; - uLong uSizeFile; - uLong uBackRead; - uLong uMaxBack=0xffff; /* maximum size of global comment */ - uLong uPosFound=0; - - if (fseek(fin,0,SEEK_END) != 0) - return 0; - - - uSizeFile = ftell( fin ); - - if (uMaxBack>uSizeFile) - uMaxBack = uSizeFile; - - buf = (unsigned char*)malloc(BUFREADCOMMENT+4); - if (buf==NULL) - return 0; - - uBackRead = 4; - while (uBackReaduMaxBack) - uBackRead = uMaxBack; - else - uBackRead+=BUFREADCOMMENT; - uReadPos = uSizeFile-uBackRead ; - - uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? - (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); - if (fseek(fin,uReadPos,SEEK_SET)!=0) - break; - - if (fread(buf,(uInt)uReadSize,1,fin)!=1) - break; - - for (i=(int)uReadSize-3; (i--)>0;) - if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && - ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) - { - uPosFound = uReadPos+i; - break; - } - - if (uPosFound!=0) - break; - } - free(buf); - return uPosFound; -} - -extern unzFile unzReOpen (const char* path, unzFile file) -{ - unz_s *s; - FILE * fin; - - fin=fopen(path,"rb"); - if (fin==NULL) - return NULL; - - s=(unz_s*)malloc(sizeof(unz_s)); - memcpy(s, (unz_s*)file, sizeof(unz_s)); - - s->file = fin; - return (unzFile)s; -} - -/* - Open a Zip file. path contain the full pathname (by example, - on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer - "zlib/zlib109.zip". - If the zipfile cannot be opened (file don't exist or in not valid), the - return value is NULL. - Else, the return value is a unzFile Handle, usable with other function - of this unzip package. -*/ -extern unzFile unzOpen (const char* path) -{ - unz_s us; - unz_s *s; - uLong central_pos,uL; - FILE * fin ; - - uLong number_disk; /* number of the current dist, used for - spaning ZIP, unsupported, always 0*/ - uLong number_disk_with_CD; /* number the the disk with central dir, used - for spaning ZIP, unsupported, always 0*/ - uLong number_entry_CD; /* total number of entries in - the central dir - (same than number_entry on nospan) */ - - int err=UNZ_OK; - - fin=fopen(path,"rb"); - if (fin==NULL) - return NULL; - - central_pos = unzlocal_SearchCentralDir(fin); - if (central_pos==0) - err=UNZ_ERRNO; - - if (fseek(fin,central_pos,SEEK_SET)!=0) - err=UNZ_ERRNO; - - /* the signature, already checked */ - if (unzlocal_getLong(fin,&uL)!=UNZ_OK) - err=UNZ_ERRNO; - - /* number of this disk */ - if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK) - err=UNZ_ERRNO; - - /* number of the disk with the start of the central directory */ - if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) - err=UNZ_ERRNO; - - /* total number of entries in the central dir on this disk */ - if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) - err=UNZ_ERRNO; - - /* total number of entries in the central dir */ - if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) - err=UNZ_ERRNO; - - if ((number_entry_CD!=us.gi.number_entry) || - (number_disk_with_CD!=0) || - (number_disk!=0)) - err=UNZ_BADZIPFILE; - - /* size of the central directory */ - if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) - err=UNZ_ERRNO; - - /* offset of start of central directory with respect to the - starting disk number */ - if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) - err=UNZ_ERRNO; - - /* zipfile comment length */ - if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) - err=UNZ_ERRNO; - - if ((central_pospfile_in_zip_read!=NULL) - unzCloseCurrentFile(file); - - fclose(s->file); - free(s); - return UNZ_OK; -} - - -/* - Write info about the ZipFile in the *pglobal_info structure. - No preparation of the structure is needed - return UNZ_OK if there is no problem. */ -extern int unzGetGlobalInfo (unzFile file,unz_global_info *pglobal_info) -{ - unz_s* s; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - *pglobal_info=s->gi; - return UNZ_OK; -} - - -/* - Translate date/time from Dos format to tm_unz (readable more easilty) -*/ -static void unzlocal_DosDateToTmuDate (uLong ulDosDate, tm_unz* ptm) -{ - uLong uDate; - uDate = (uLong)(ulDosDate>>16); - ptm->tm_mday = (uInt)(uDate&0x1f) ; - ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; - ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; - - ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); - ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; - ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; -} - -/* - Get Info about the current file in the zipfile, with internal only info -*/ -static int unzlocal_GetCurrentFileInfoInternal (unzFile file, - unz_file_info *pfile_info, - unz_file_info_internal - *pfile_info_internal, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize) -{ - unz_s* s; - unz_file_info file_info; - unz_file_info_internal file_info_internal; - int err=UNZ_OK; - uLong uMagic; - long lSeek=0; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0) - err=UNZ_ERRNO; - - - /* we check the magic */ - if (err==UNZ_OK) - if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) - err=UNZ_ERRNO; - else if (uMagic!=0x02014b50) - err=UNZ_BADZIPFILE; - - if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK) - err=UNZ_ERRNO; - - unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); - - if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) - err=UNZ_ERRNO; - - lSeek+=file_info.size_filename; - if ((err==UNZ_OK) && (szFileName!=NULL)) - { - uLong uSizeRead ; - if (file_info.size_filename0) && (fileNameBufferSize>0)) - if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1) - err=UNZ_ERRNO; - lSeek -= uSizeRead; - } - - - if ((err==UNZ_OK) && (extraField!=NULL)) - { - uLong uSizeRead ; - if (file_info.size_file_extrafile,lSeek,SEEK_CUR)==0) - lSeek=0; - else - err=UNZ_ERRNO; - if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) - if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1) - err=UNZ_ERRNO; - lSeek += file_info.size_file_extra - uSizeRead; - } - else - lSeek+=file_info.size_file_extra; - - - if ((err==UNZ_OK) && (szComment!=NULL)) - { - uLong uSizeRead ; - if (file_info.size_file_commentfile,lSeek,SEEK_CUR)==0) - lSeek=0; - else - err=UNZ_ERRNO; - if ((file_info.size_file_comment>0) && (commentBufferSize>0)) - if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1) - err=UNZ_ERRNO; - lSeek+=file_info.size_file_comment - uSizeRead; - } - else - lSeek+=file_info.size_file_comment; - - if ((err==UNZ_OK) && (pfile_info!=NULL)) - *pfile_info=file_info; - - if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) - *pfile_info_internal=file_info_internal; - - return err; -} - - - -/* - Write info about the ZipFile in the *pglobal_info structure. - No preparation of the structure is needed - return UNZ_OK if there is no problem. -*/ -extern int unzGetCurrentFileInfo ( unzFile file, unz_file_info *pfile_info, - char *szFileName, uLong fileNameBufferSize, - void *extraField, uLong extraFieldBufferSize, - char *szComment, uLong commentBufferSize) -{ - return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, - szFileName,fileNameBufferSize, - extraField,extraFieldBufferSize, - szComment,commentBufferSize); -} - -/* - Set the current file of the zipfile to the first file. - return UNZ_OK if there is no problem -*/ -extern int unzGoToFirstFile (unzFile file) -{ - int err=UNZ_OK; - unz_s* s; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - s->pos_in_central_dir=s->offset_central_dir; - s->num_file=0; - err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, - &s->cur_file_info_internal, - NULL,0,NULL,0,NULL,0); - s->current_file_ok = (err == UNZ_OK); - return err; -} - - -/* - Set the current file of the zipfile to the next file. - return UNZ_OK if there is no problem - return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. -*/ -extern int unzGoToNextFile (unzFile file) -{ - unz_s* s; - int err; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (!s->current_file_ok) - return UNZ_END_OF_LIST_OF_FILE; - if (s->num_file+1==s->gi.number_entry) - return UNZ_END_OF_LIST_OF_FILE; - - s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + - s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; - s->num_file++; - err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, - &s->cur_file_info_internal, - NULL,0,NULL,0,NULL,0); - s->current_file_ok = (err == UNZ_OK); - return err; -} - - -/* - Try locate the file szFileName in the zipfile. - For the iCaseSensitivity signification, see unzipStringFileNameCompare - - return value : - UNZ_OK if the file is found. It becomes the current file. - UNZ_END_OF_LIST_OF_FILE if the file is not found -*/ -extern int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) -{ - unz_s* s; - int err; - - - uLong num_fileSaved; - uLong pos_in_central_dirSaved; - - - if (file==NULL) - return UNZ_PARAMERROR; - - if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) - return UNZ_PARAMERROR; - - s=(unz_s*)file; - if (!s->current_file_ok) - return UNZ_END_OF_LIST_OF_FILE; - - num_fileSaved = s->num_file; - pos_in_central_dirSaved = s->pos_in_central_dir; - - err = unzGoToFirstFile(file); - - while (err == UNZ_OK) - { - char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; - unzGetCurrentFileInfo(file,NULL, - szCurrentFileName,sizeof(szCurrentFileName)-1, - NULL,0,NULL,0); - if (unzStringFileNameCompare(szCurrentFileName, - szFileName,iCaseSensitivity)==0) - return UNZ_OK; - err = unzGoToNextFile(file); - } - - s->num_file = num_fileSaved ; - s->pos_in_central_dir = pos_in_central_dirSaved ; - return err; -} - - -/* - Read the static header of the current zipfile - Check the coherency of the static header and info in the end of central - directory about this file - store in *piSizeVar the size of extra info in static header - (filename and size of extra field data) -*/ -static int unzlocal_CheckCurrentFileCoherencyHeader (unz_s* s, uInt* piSizeVar, - uLong *poffset_local_extrafield, - uInt *psize_local_extrafield) -{ - uLong uMagic,uData,uFlags; - uLong size_filename; - uLong size_extra_field; - int err=UNZ_OK; - - *piSizeVar = 0; - *poffset_local_extrafield = 0; - *psize_local_extrafield = 0; - - if (fseek(s->file,s->cur_file_info_internal.offset_curfile + - s->byte_before_the_zipfile,SEEK_SET)!=0) - return UNZ_ERRNO; - - - if (err==UNZ_OK) - if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) - err=UNZ_ERRNO; - else if (uMagic!=0x04034b50) - err=UNZ_BADZIPFILE; - - if (unzlocal_getShort(s->file,&uData) != UNZ_OK) - err=UNZ_ERRNO; -/* - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) - err=UNZ_BADZIPFILE; -*/ - if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&uData) != UNZ_OK) - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) - err=UNZ_BADZIPFILE; - - if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && - (s->cur_file_info.compression_method!=Z_DEFLATED)) - err=UNZ_BADZIPFILE; - - if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */ - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */ - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && - ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */ - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && - ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */ - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && - ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - - if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK) - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) - err=UNZ_BADZIPFILE; - - *piSizeVar += (uInt)size_filename; - - if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK) - err=UNZ_ERRNO; - *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + - SIZEZIPLOCALHEADER + size_filename; - *psize_local_extrafield = (uInt)size_extra_field; - - *piSizeVar += (uInt)size_extra_field; - - return err; -} - -/* - Open for reading data the current file in the zipfile. - If there is no error and the file is opened, the return value is UNZ_OK. -*/ -extern int unzOpenCurrentFile (unzFile file) -{ - int err=UNZ_OK; - int Store; - uInt iSizeVar; - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - uLong offset_local_extrafield; /* offset of the static extra field */ - uInt size_local_extrafield; /* size of the static extra field */ - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (!s->current_file_ok) - return UNZ_PARAMERROR; - - if (s->pfile_in_zip_read != NULL) - unzCloseCurrentFile(file); - - if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, - &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) - return UNZ_BADZIPFILE; - - pfile_in_zip_read_info = (file_in_zip_read_info_s*) - malloc(sizeof(file_in_zip_read_info_s)); - if (pfile_in_zip_read_info==NULL) - return UNZ_INTERNALERROR; - - pfile_in_zip_read_info->read_buffer=(char*)malloc(UNZ_BUFSIZE); - pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; - pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; - pfile_in_zip_read_info->pos_local_extrafield=0; - - if (pfile_in_zip_read_info->read_buffer==NULL) - { - free(pfile_in_zip_read_info); - return UNZ_INTERNALERROR; - } - - pfile_in_zip_read_info->stream_initialised=0; - - if ((s->cur_file_info.compression_method!=0) && - (s->cur_file_info.compression_method!=Z_DEFLATED)) - err=UNZ_BADZIPFILE; - Store = s->cur_file_info.compression_method==0; - - pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; - pfile_in_zip_read_info->crc32=0; - pfile_in_zip_read_info->compression_method = - s->cur_file_info.compression_method; - pfile_in_zip_read_info->file=s->file; - pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; - - pfile_in_zip_read_info->stream.total_out = 0; - - if (!Store) - { - pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; - pfile_in_zip_read_info->stream.zfree = (free_func)0; - pfile_in_zip_read_info->stream.opaque = (voidp)0; - - err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); - if (err == Z_OK) - pfile_in_zip_read_info->stream_initialised=1; - /* windowBits is passed < 0 to tell that there is no zlib header. - * Note that in this case inflate *requires* an extra "dummy" byte - * after the compressed stream in order to complete decompression and - * return Z_STREAM_END. - * In unzip, i don't wait absolutely Z_STREAM_END because I known the - * size of both compressed and uncompressed data - */ - } - pfile_in_zip_read_info->rest_read_compressed = - s->cur_file_info.compressed_size ; - pfile_in_zip_read_info->rest_read_uncompressed = - s->cur_file_info.uncompressed_size ; - - - pfile_in_zip_read_info->pos_in_zipfile = - s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + - iSizeVar; - - pfile_in_zip_read_info->stream.avail_in = (uInt)0; - - - s->pfile_in_zip_read = pfile_in_zip_read_info; - return UNZ_OK; -} - - -/* - Read bytes from the current file. - buf contain buffer where data must be copied - len the size of buf. - - return the number of byte copied if somes bytes are copied - return 0 if the end of file was reached - return <0 with error code if there is an error - (UNZ_ERRNO for IO error, or zLib error for uncompress error) -*/ -extern int unzReadCurrentFile (unzFile file, void *buf, unsigned len) -{ - int err=UNZ_OK; - uInt iRead = 0; - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - - if ((pfile_in_zip_read_info->read_buffer == NULL)) - return UNZ_END_OF_LIST_OF_FILE; - if (len==0) - return 0; - - pfile_in_zip_read_info->stream.next_out = (Byte*)buf; - - pfile_in_zip_read_info->stream.avail_out = (uInt)len; - - if (len>pfile_in_zip_read_info->rest_read_uncompressed) - pfile_in_zip_read_info->stream.avail_out = - (uInt)pfile_in_zip_read_info->rest_read_uncompressed; - - while (pfile_in_zip_read_info->stream.avail_out>0) - { - if ((pfile_in_zip_read_info->stream.avail_in==0) && - (pfile_in_zip_read_info->rest_read_compressed>0)) - { - uInt uReadThis = UNZ_BUFSIZE; - if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; - if (uReadThis == 0) - return UNZ_EOF; - if (s->cur_file_info.compressed_size == pfile_in_zip_read_info->rest_read_compressed) - if (fseek(pfile_in_zip_read_info->file, - pfile_in_zip_read_info->pos_in_zipfile + - pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0) - return UNZ_ERRNO; - if (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1, - pfile_in_zip_read_info->file)!=1) - return UNZ_ERRNO; - pfile_in_zip_read_info->pos_in_zipfile += uReadThis; - - pfile_in_zip_read_info->rest_read_compressed-=uReadThis; - - pfile_in_zip_read_info->stream.next_in = - (Byte*)pfile_in_zip_read_info->read_buffer; - pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; - } - - if (pfile_in_zip_read_info->compression_method==0) - { - uInt uDoCopy,i ; - if (pfile_in_zip_read_info->stream.avail_out < - pfile_in_zip_read_info->stream.avail_in) - uDoCopy = pfile_in_zip_read_info->stream.avail_out ; - else - uDoCopy = pfile_in_zip_read_info->stream.avail_in ; - - for (i=0;istream.next_out+i) = - *(pfile_in_zip_read_info->stream.next_in+i); - - pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, - pfile_in_zip_read_info->stream.next_out, - uDoCopy); - pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; - pfile_in_zip_read_info->stream.avail_in -= uDoCopy; - pfile_in_zip_read_info->stream.avail_out -= uDoCopy; - pfile_in_zip_read_info->stream.next_out += uDoCopy; - pfile_in_zip_read_info->stream.next_in += uDoCopy; - pfile_in_zip_read_info->stream.total_out += uDoCopy; - iRead += uDoCopy; - } - else - { - uLong uTotalOutBefore,uTotalOutAfter; - const Byte *bufBefore; - uLong uOutThis; - int flush=Z_SYNC_FLUSH; - - uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; - bufBefore = pfile_in_zip_read_info->stream.next_out; - - /* - if ((pfile_in_zip_read_info->rest_read_uncompressed == - pfile_in_zip_read_info->stream.avail_out) && - (pfile_in_zip_read_info->rest_read_compressed == 0)) - flush = Z_FINISH; - */ - err=inflate(&pfile_in_zip_read_info->stream,flush); - - uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; - uOutThis = uTotalOutAfter-uTotalOutBefore; - - pfile_in_zip_read_info->crc32 = - crc32(pfile_in_zip_read_info->crc32,bufBefore, - (uInt)(uOutThis)); - - pfile_in_zip_read_info->rest_read_uncompressed -= - uOutThis; - - iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); - - if (err==Z_STREAM_END) - return (iRead==0) ? UNZ_EOF : iRead; - if (err!=Z_OK) - break; - } - } - - if (err==Z_OK) - return iRead; - return err; -} - - -/* - Give the current position in uncompressed data -*/ -extern long unztell (unzFile file) -{ - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - return (long)pfile_in_zip_read_info->stream.total_out; -} - - -/* - return 1 if the end of file was reached, 0 elsewhere -*/ -extern int unzeof (unzFile file) -{ - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - if (pfile_in_zip_read_info->rest_read_uncompressed == 0) - return 1; - else - return 0; -} - - - -/* - Read extra field from the current file (opened by unzOpenCurrentFile) - This is the static-header version of the extra field (sometimes, there is - more info in the static-header version than in the central-header) - - if buf==NULL, it return the size of the static extra field that can be read - - if buf!=NULL, len is the size of the buffer, the extra header is copied in - buf. - the return value is the number of bytes copied in buf, or (if <0) - the error code -*/ -extern int unzGetLocalExtrafield (unzFile file,void *buf,unsigned len) -{ - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - uInt read_now; - uLong size_to_read; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - size_to_read = (pfile_in_zip_read_info->size_local_extrafield - - pfile_in_zip_read_info->pos_local_extrafield); - - if (buf==NULL) - return (int)size_to_read; - - if (len>size_to_read) - read_now = (uInt)size_to_read; - else - read_now = (uInt)len ; - - if (read_now==0) - return 0; - - if (fseek(pfile_in_zip_read_info->file, - pfile_in_zip_read_info->offset_local_extrafield + - pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0) - return UNZ_ERRNO; - - if (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1) - return UNZ_ERRNO; - - return (int)read_now; -} - -/* - Close the file in zip opened with unzipOpenCurrentFile - Return UNZ_CRCERROR if all the file was read but the CRC is not good -*/ -extern int unzCloseCurrentFile (unzFile file) -{ - int err=UNZ_OK; - - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - - if (pfile_in_zip_read_info->rest_read_uncompressed == 0) - { - if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) - err=UNZ_CRCERROR; - } - - - free(pfile_in_zip_read_info->read_buffer); - pfile_in_zip_read_info->read_buffer = NULL; - if (pfile_in_zip_read_info->stream_initialised) - inflateEnd(&pfile_in_zip_read_info->stream); - - pfile_in_zip_read_info->stream_initialised = 0; - free(pfile_in_zip_read_info); - - s->pfile_in_zip_read=NULL; - - return err; -} - - -/* - Get the global comment string of the ZipFile, in the szComment buffer. - uSizeBuf is the size of the szComment buffer. - return the number of byte copied or an error code <0 -*/ -extern int unzGetGlobalComment (unzFile file, char *szComment, uLong uSizeBuf) -{ - unz_s* s; - uLong uReadThis ; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - - uReadThis = uSizeBuf; - if (uReadThis>s->gi.size_comment) - uReadThis = s->gi.size_comment; - - if (fseek(s->file,s->central_pos+22,SEEK_SET)!=0) - return UNZ_ERRNO; - - if (uReadThis>0) - { - *szComment='\0'; - if (fread(szComment,(uInt)uReadThis,1,s->file)!=1) - return UNZ_ERRNO; - } - - if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) - *(szComment+s->gi.size_comment)='\0'; - return (int)uReadThis; -} - -/* crc32.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef DYNAMIC_CRC_TABLE - -static int crc_table_empty = 1; -static uLong crc_table[256]; -static void make_crc_table OF((void)); - -/* - Generate a table for a byte-wise 32-bit CRC calculation on the polynomial: - x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. - - Polynomials over GF(2) are represented in binary, one bit per coefficient, - with the lowest powers in the most significant bit. Then adding polynomials - is just exclusive-or, and multiplying a polynomial by x is a right shift by - one. If we call the above polynomial p, and represent a byte as the - polynomial q, also with the lowest power in the most significant bit (so the - byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, - where a mod b means the remainder after dividing a by b. - - This calculation is done using the shift-register method of multiplying and - taking the remainder. The register is initialized to zero, and for each - incoming bit, x^32 is added mod p to the register if the bit is a one (where - x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by - x (which is shifting right by one and adding x^32 mod p if the bit shifted - out is a one). We start with the highest power (least significant bit) of - q and repeat for all eight bits of q. - - The table is simply the CRC of all possible eight bit values. This is all - the information needed to generate CRC's on data a byte at a time for all - combinations of CRC register values and incoming bytes. -*/ -static void make_crc_table() -{ - uLong c; - int n, k; - uLong poly; /* polynomial exclusive-or pattern */ - /* terms of polynomial defining this crc (except x^32): */ - static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; - - /* make exclusive-or pattern from polynomial (0xedb88320L) */ - poly = 0L; - for (n = 0; n < sizeof(p)/sizeof(Byte); n++) - poly |= 1L << (31 - p[n]); - - for (n = 0; n < 256; n++) - { - c = (uLong)n; - for (k = 0; k < 8; k++) - c = c & 1 ? poly ^ (c >> 1) : c >> 1; - crc_table[n] = c; - } - crc_table_empty = 0; -} -#else -/* ======================================================================== - * Table of CRC-32's of all single-byte values (made by make_crc_table) - */ -static const uLong crc_table[256] = { - 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, - 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, - 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, - 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, - 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, - 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, - 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, - 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, - 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, - 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, - 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, - 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, - 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, - 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, - 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, - 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, - 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, - 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, - 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, - 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, - 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, - 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, - 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, - 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, - 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, - 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, - 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, - 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, - 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, - 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, - 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, - 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, - 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, - 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, - 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, - 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, - 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, - 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, - 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, - 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, - 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, - 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, - 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, - 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, - 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, - 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, - 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, - 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, - 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, - 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, - 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, - 0x2d02ef8dL -}; -#endif - -/* ========================================================================= - * This function can be used by asm versions of crc32() - */ -const uLong * get_crc_table() -{ -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) make_crc_table(); -#endif - return (const uLong *)crc_table; -} - -/* ========================================================================= */ -#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); -#define DO2(buf) DO1(buf); DO1(buf); -#define DO4(buf) DO2(buf); DO2(buf); -#define DO8(buf) DO4(buf); DO4(buf); - -/* ========================================================================= */ -uLong crc32(uLong crc, const Byte *buf, uInt len) -{ - if (buf == Z_NULL) return 0L; -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) - make_crc_table(); -#endif - crc = crc ^ 0xffffffffL; - while (len >= 8) - { - DO8(buf); - len -= 8; - } - if (len) do { - DO1(buf); - } while (--len); - return crc ^ 0xffffffffL; -} - -/* infblock.h -- header to use infblock.c - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -struct inflate_blocks_state; -typedef struct inflate_blocks_state inflate_blocks_statef; - -extern inflate_blocks_statef * inflate_blocks_new OF(( - z_streamp z, - check_func c, /* check function */ - uInt w)); /* window size */ - -extern int inflate_blocks OF(( - inflate_blocks_statef *, - z_streamp , - int)); /* initial return code */ - -extern void inflate_blocks_reset OF(( - inflate_blocks_statef *, - z_streamp , - uLong *)); /* check value on output */ - -extern int inflate_blocks_free OF(( - inflate_blocks_statef *, - z_streamp)); - -extern void inflate_set_dictionary OF(( - inflate_blocks_statef *s, - const Byte *d, /* dictionary */ - uInt n)); /* dictionary length */ - -extern int inflate_blocks_sync_point OF(( - inflate_blocks_statef *s)); - -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits - -/* Table for deflate from PKZIP's appnote.txt. */ -static const uInt border[] = { /* Order of the bit length code lengths */ - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - -/* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* Huffman code lookup table entry--this entry is four bytes for machines - that have 16-bit pointers (e.g. PC's in the small or medium model). */ - -typedef struct inflate_huft_s inflate_huft; - -struct inflate_huft_s { - union { - struct { - Byte Exop; /* number of extra bits or operation */ - Byte Bits; /* number of bits in this code or subcode */ - } what; - uInt pad; /* pad structure to a power of 2 (4 bytes for */ - } word; /* 16-bit, 8 bytes for 32-bit int's) */ - uInt base; /* literal, length base, distance base, - or table offset */ -}; - -/* Maximum size of dynamic tree. The maximum found in a long but non- - exhaustive search was 1004 huft structures (850 for length/literals - and 154 for distances, the latter actually the result of an - exhaustive search). The actual maximum is not known, but the - value below is more than safe. */ -#define MANY 1440 - -extern int inflate_trees_bits OF(( - uInt *, /* 19 code lengths */ - uInt *, /* bits tree desired/actual depth */ - inflate_huft * *, /* bits tree result */ - inflate_huft *, /* space for trees */ - z_streamp)); /* for messages */ - -extern int inflate_trees_dynamic OF(( - uInt, /* number of literal/length codes */ - uInt, /* number of distance codes */ - uInt *, /* that many (total) code lengths */ - uInt *, /* literal desired/actual bit depth */ - uInt *, /* distance desired/actual bit depth */ - inflate_huft * *, /* literal/length tree result */ - inflate_huft * *, /* distance tree result */ - inflate_huft *, /* space for trees */ - z_streamp)); /* for messages */ - -extern int inflate_trees_fixed OF(( - uInt *, /* literal desired/actual bit depth */ - uInt *, /* distance desired/actual bit depth */ - inflate_huft * *, /* literal/length tree result */ - inflate_huft * *, /* distance tree result */ - z_streamp)); /* for memory allocation */ - - -/* infcodes.h -- header to use infcodes.c - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -struct inflate_codes_state; -typedef struct inflate_codes_state inflate_codes_statef; - -extern inflate_codes_statef *inflate_codes_new OF(( - uInt, uInt, - inflate_huft *, inflate_huft *, - z_streamp )); - -extern int inflate_codes OF(( - inflate_blocks_statef *, - z_streamp , - int)); - -extern void inflate_codes_free OF(( - inflate_codes_statef *, - z_streamp )); - -/* infutil.h -- types and macros common to blocks and codes - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -#ifndef _INFUTIL_H -#define _INFUTIL_H - -typedef enum { - TYPE, /* get type bits (3, including end bit) */ - LENS, /* get lengths for stored */ - STORED, /* processing stored block */ - TABLE, /* get table lengths */ - BTREE, /* get bit lengths tree for a dynamic block */ - DTREE, /* get length, distance trees for a dynamic block */ - CODES, /* processing fixed or dynamic block */ - DRY, /* output remaining window bytes */ - DONE, /* finished last block, done */ - BAD} /* got a data error--stuck here */ -inflate_block_mode; - -/* inflate blocks semi-private state */ -struct inflate_blocks_state { - - /* mode */ - inflate_block_mode mode; /* current inflate_block mode */ - - /* mode dependent information */ - union { - uInt left; /* if STORED, bytes left to copy */ - struct { - uInt table; /* table lengths (14 bits) */ - uInt index; /* index into blens (or border) */ - uInt *blens; /* bit lengths of codes */ - uInt bb; /* bit length tree depth */ - inflate_huft *tb; /* bit length decoding tree */ - } trees; /* if DTREE, decoding info for trees */ - struct { - inflate_codes_statef - *codes; - } decode; /* if CODES, current state */ - } sub; /* submode */ - uInt last; /* true if this block is the last block */ - - /* mode independent information */ - uInt bitk; /* bits in bit buffer */ - uLong bitb; /* bit buffer */ - inflate_huft *hufts; /* single malloc for tree space */ - Byte *window; /* sliding window */ - Byte *end; /* one byte after sliding window */ - Byte *read; /* window read pointer */ - Byte *write; /* window write pointer */ - check_func checkfn; /* check function */ - uLong check; /* check on output */ - -}; - - -/* defines for inflate input/output */ -/* update pointers and return */ -#define UPDBITS {s->bitb=b;s->bitk=k;} -#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} -#define UPDOUT {s->write=q;} -#define UPDATE {UPDBITS UPDIN UPDOUT} -#define LEAVE {UPDATE return inflate_flush(s,z,r);} -/* get bytes and bits */ -#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} -#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} -#define NEXTBYTE (n--,*p++) -#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} -/* output bytes */ -#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) -#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} -#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} -#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} -#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} -#define OUTBYTE(a) {*q++=(Byte)(a);m--;} -/* load static pointers */ -#define LOAD {LOADIN LOADOUT} - -/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ -extern uInt inflate_mask[17]; - -/* copy as much as possible from the sliding window to the output area */ -extern int inflate_flush OF(( - inflate_blocks_statef *, - z_streamp , - int)); - -#endif - - -/* - Notes beyond the 1.93a appnote.txt: - - 1. Distance pointers never point before the beginning of the output - stream. - 2. Distance pointers can point back across blocks, up to 32k away. - 3. There is an implied maximum of 7 bits for the bit length table and - 15 bits for the actual data. - 4. If only one code exists, then it is encoded using one bit. (Zero - would be more efficient, but perhaps a little confusing.) If two - codes exist, they are coded using one bit each (0 and 1). - 5. There is no way of sending zero distance codes--a dummy must be - sent if there are none. (History: a pre 2.0 version of PKZIP would - store blocks with no distance codes, but this was discovered to be - too harsh a criterion.) Valid only for 1.93a. 2.04c does allow - zero distance codes, which is sent as one code of zero bits in - length. - 6. There are up to 286 literal/length codes. Code 256 represents the - end-of-block. Note however that the static length tree defines - 288 codes just to fill out the Huffman codes. Codes 286 and 287 - cannot be used though, since there is no length base or extra bits - defined for them. Similarily, there are up to 30 distance codes. - However, static trees define 32 codes (all 5 bits) to fill out the - Huffman codes, but the last two had better not show up in the data. - 7. Unzip can check dynamic Huffman blocks for complete code sets. - The exception is that a single code would not be complete (see #4). - 8. The five bits following the block type is really the number of - literal codes sent minus 257. - 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits - (1+6+6). Therefore, to output three times the length, you output - three codes (1+1+1), whereas to output four times the same length, - you only need two codes (1+3). Hmm. - 10. In the tree reconstruction algorithm, Code = Code + Increment - only if BitLength(i) is not zero. (Pretty obvious.) - 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) - 12. Note: length code 284 can represent 227-258, but length code 285 - really is 258. The last length deserves its own, short code - since it gets used a lot in very redundant files. The length - 258 is special since 258 - 3 (the min match length) is 255. - 13. The literal/length and distance code bit lengths are read as a - single stream of lengths. It is possible (and advantageous) for - a repeat code (16, 17, or 18) to go across the boundary between - the two sets of lengths. - */ - - -void inflate_blocks_reset(inflate_blocks_statef *s, z_streamp z, uLong *c) -{ - if (c != Z_NULL) - *c = s->check; - if (s->mode == BTREE || s->mode == DTREE) - ZFREE(z, s->sub.trees.blens); - if (s->mode == CODES) - inflate_codes_free(s->sub.decode.codes, z); - s->mode = TYPE; - s->bitk = 0; - s->bitb = 0; - s->read = s->write = s->window; - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(0L, (const Byte *)Z_NULL, 0); - Tracev(("inflate: blocks reset\n")); -} - - -inflate_blocks_statef *inflate_blocks_new(z_streamp z, check_func c, uInt w) -{ - inflate_blocks_statef *s; - - if ((s = (inflate_blocks_statef *)ZALLOC - (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) - return s; - if ((s->hufts = - (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) - { - ZFREE(z, s); - return Z_NULL; - } - if ((s->window = (Byte *)ZALLOC(z, 1, w)) == Z_NULL) - { - ZFREE(z, s->hufts); - ZFREE(z, s); - return Z_NULL; - } - s->end = s->window + w; - s->checkfn = c; - s->mode = TYPE; - Tracev(("inflate: blocks allocated\n")); - inflate_blocks_reset(s, z, Z_NULL); - return s; -} - - -int inflate_blocks(inflate_blocks_statef *s, z_streamp z, int r) -{ - uInt t; /* temporary storage */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Byte *p; /* input data pointer */ - uInt n; /* bytes available there */ - Byte *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - - /* copy input/output information to locals (UPDATE macro restores) */ - LOAD - - /* process input based on current state */ - while (1) switch (s->mode) - { - case TYPE: - NEEDBITS(3) - t = (uInt)b & 7; - s->last = t & 1; - switch (t >> 1) - { - case 0: /* stored */ - Tracev(("inflate: stored block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - t = k & 7; /* go to byte boundary */ - DUMPBITS(t) - s->mode = LENS; /* get length of stored block */ - break; - case 1: /* fixed */ - Tracev(("inflate: fixed codes block%s\n", - s->last ? " (last)" : "")); - { - uInt bl, bd; - inflate_huft *tl, *td; - - inflate_trees_fixed(&bl, &bd, &tl, &td, z); - s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); - if (s->sub.decode.codes == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - } - DUMPBITS(3) - s->mode = CODES; - break; - case 2: /* dynamic */ - Tracev(("inflate: dynamic codes block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - s->mode = TABLE; - break; - case 3: /* illegal */ - DUMPBITS(3) - s->mode = BAD; - z->msg = (char*)"invalid block type"; - r = Z_DATA_ERROR; - LEAVE - } - break; - case LENS: - NEEDBITS(32) - if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) - { - s->mode = BAD; - z->msg = (char*)"invalid stored block lengths"; - r = Z_DATA_ERROR; - LEAVE - } - s->sub.left = (uInt)b & 0xffff; - b = k = 0; /* dump bits */ - Tracev(("inflate: stored length %u\n", s->sub.left)); - s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); - break; - case STORED: - if (n == 0) - LEAVE - NEEDOUT - t = s->sub.left; - if (t > n) t = n; - if (t > m) t = m; - zmemcpy(q, p, t); - p += t; n -= t; - q += t; m -= t; - if ((s->sub.left -= t) != 0) - break; - Tracev(("inflate: stored end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - s->mode = s->last ? DRY : TYPE; - break; - case TABLE: - NEEDBITS(14) - s->sub.trees.table = t = (uInt)b & 0x3fff; -#ifndef PKZIP_BUG_WORKAROUND - if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) - { - s->mode = BAD; - z->msg = (char*)"too many length or distance symbols"; - r = Z_DATA_ERROR; - LEAVE - } -#endif - t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); - if ((s->sub.trees.blens = (uInt*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - DUMPBITS(14) - s->sub.trees.index = 0; - Tracev(("inflate: table sizes ok\n")); - s->mode = BTREE; - case BTREE: - while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) - { - NEEDBITS(3) - s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; - DUMPBITS(3) - } - while (s->sub.trees.index < 19) - s->sub.trees.blens[border[s->sub.trees.index++]] = 0; - s->sub.trees.bb = 7; - t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, - &s->sub.trees.tb, s->hufts, z); - if (t != Z_OK) - { - ZFREE(z, s->sub.trees.blens); - r = t; - if (r == Z_DATA_ERROR) - s->mode = BAD; - LEAVE - } - s->sub.trees.index = 0; - Tracev(("inflate: bits tree ok\n")); - s->mode = DTREE; - case DTREE: - while (t = s->sub.trees.table, - s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) - { - inflate_huft *h; - uInt i, j, c; - - t = s->sub.trees.bb; - NEEDBITS(t) - h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); - t = h->bits; - c = h->base; - if (c < 16) - { - DUMPBITS(t) - s->sub.trees.blens[s->sub.trees.index++] = c; - } - else /* c == 16..18 */ - { - i = c == 18 ? 7 : c - 14; - j = c == 18 ? 11 : 3; - NEEDBITS(t + i) - DUMPBITS(t) - j += (uInt)b & inflate_mask[i]; - DUMPBITS(i) - i = s->sub.trees.index; - t = s->sub.trees.table; - if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || - (c == 16 && i < 1)) - { - ZFREE(z, s->sub.trees.blens); - s->mode = BAD; - z->msg = (char*)"invalid bit length repeat"; - r = Z_DATA_ERROR; - LEAVE - } - c = c == 16 ? s->sub.trees.blens[i - 1] : 0; - do { - s->sub.trees.blens[i++] = c; - } while (--j); - s->sub.trees.index = i; - } - } - s->sub.trees.tb = Z_NULL; - { - uInt bl, bd; - inflate_huft *tl, *td; - inflate_codes_statef *c; - - bl = 9; /* must be <= 9 for lookahead assumptions */ - bd = 6; /* must be <= 9 for lookahead assumptions */ - t = s->sub.trees.table; - t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), - s->sub.trees.blens, &bl, &bd, &tl, &td, - s->hufts, z); - ZFREE(z, s->sub.trees.blens); - if (t != Z_OK) - { - if (t == (uInt)Z_DATA_ERROR) - s->mode = BAD; - r = t; - LEAVE - } - Tracev(("inflate: trees ok\n")); - if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - s->sub.decode.codes = c; - } - s->mode = CODES; - case CODES: - UPDATE - if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) - return inflate_flush(s, z, r); - r = Z_OK; - inflate_codes_free(s->sub.decode.codes, z); - LOAD - Tracev(("inflate: codes end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - if (!s->last) - { - s->mode = TYPE; - break; - } - s->mode = DRY; - case DRY: - FLUSH - if (s->read != s->write) - LEAVE - s->mode = DONE; - case DONE: - r = Z_STREAM_END; - LEAVE - case BAD: - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -} - - -int inflate_blocks_free(inflate_blocks_statef *s, z_streamp z) -{ - inflate_blocks_reset(s, z, Z_NULL); - ZFREE(z, s->window); - ZFREE(z, s->hufts); - ZFREE(z, s); - Tracev(("inflate: blocks freed\n")); - return Z_OK; -} - - -void inflate_set_dictionary(inflate_blocks_statef *s, const Byte *d, uInt n) -{ - zmemcpy(s->window, d, n); - s->read = s->write = s->window + n; -} - - -/* Returns true if inflate is currently at the end of a block generated - * by Z_SYNC_FLUSH or Z_FULL_FLUSH. - * IN assertion: s != Z_NULL - */ -int inflate_blocks_sync_point(inflate_blocks_statef *s) -{ - return s->mode == LENS; -} - -/* And'ing with mask[n] masks the lower n bits */ -uInt inflate_mask[17] = { - 0x0000, - 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, - 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff -}; - -/* copy as much as possible from the sliding window to the output area */ -int inflate_flush(inflate_blocks_statef *s, z_streamp z, int r) -{ - uInt n; - Byte *p; - Byte *q; - - /* static copies of source and destination pointers */ - p = z->next_out; - q = s->read; - - /* compute number of bytes to copy as as end of window */ - n = (uInt)((q <= s->write ? s->write : s->end) - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - /* update counters */ - z->avail_out -= n; - z->total_out += n; - - /* update check information */ - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(s->check, q, n); - - /* copy as as end of window */ - zmemcpy(p, q, n); - p += n; - q += n; - - /* see if more to copy at beginning of window */ - if (q == s->end) - { - /* wrap pointers */ - q = s->window; - if (s->write == s->end) - s->write = s->window; - - /* compute bytes to copy */ - n = (uInt)(s->write - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - /* update counters */ - z->avail_out -= n; - z->total_out += n; - - /* update check information */ - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(s->check, q, n); - - /* copy */ - zmemcpy(p, q, n); - p += n; - q += n; - } - - /* update pointers */ - z->next_out = p; - s->read = q; - - /* done */ - return r; -} - -/* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -const char inflate_copyright[] = - " inflate 1.1.3 Copyright 1995-1998 Mark Adler "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits - - -static int huft_build OF(( - uInt *, /* code lengths in bits */ - uInt, /* number of codes */ - uInt, /* number of "simple" codes */ - const uInt *, /* list of base values for non-simple codes */ - const uInt *, /* list of extra bits for non-simple codes */ - inflate_huft **, /* result: starting table */ - uInt *, /* maximum lookup bits (returns actual) */ - inflate_huft *, /* space for trees */ - uInt *, /* hufts used in space */ - uInt * )); /* space for values */ - -/* Tables for deflate from PKZIP's appnote.txt. */ -static const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - /* see note #13 above about 258 */ -static const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ -static const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577}; -static const uInt cpdext[30] = { /* Extra bits for distance codes */ - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13}; - -/* - Huffman code decoding is performed using a multi-level table lookup. - The fastest way to decode is to simply build a lookup table whose - size is determined by the longest code. However, the time it takes - to build this table can also be a factor if the data being decoded - is not very long. The most common codes are necessarily the - shortest codes, so those codes dominate the decoding time, and hence - the speed. The idea is you can have a shorter table that decodes the - shorter, more probable codes, and then point to subsidiary tables for - the longer codes. The time it costs to decode the longer codes is - then traded against the time it takes to make longer tables. - - This results of this trade are in the variables lbits and dbits - below. lbits is the number of bits the first level table for literal/ - length codes can decode in one step, and dbits is the same thing for - the distance codes. Subsequent tables are also less than or equal to - those sizes. These values may be adjusted either when all of the - codes are shorter than that, in which case the longest code length in - bits is used, or when the shortest code is *longer* than the requested - table size, in which case the length of the shortest code in bits is - used. - - There are two different values for the two tables, since they code a - different number of possibilities each. The literal/length table - codes 286 possible values, or in a flat code, a little over eight - bits. The distance table codes 30 possible values, or a little less - than five bits, flat. The optimum values for speed end up being - about one bit more than those, so lbits is 8+1 and dbits is 5+1. - The optimum values may differ though from machine to machine, and - possibly even between compilers. Your mileage may vary. - */ - - -/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ -#define BMAX 15 /* maximum bit length of any code */ - -static int huft_build(uInt *b, uInt n, uInt s, const uInt *d, const uInt *e, inflate_huft ** t, uInt *m, inflate_huft *hp, uInt *hn, uInt *v) -//uInt *b; /* code lengths in bits (all assumed <= BMAX) */ -//uInt n; /* number of codes (assumed <= 288) */ -//uInt s; /* number of simple-valued codes (0..s-1) */ -//const uInt *d; /* list of base values for non-simple codes */ -//const uInt *e; /* list of extra bits for non-simple codes */ -//inflate_huft ** t; /* result: starting table */ -//uInt *m; /* maximum lookup bits, returns actual */ -//inflate_huft *hp; /* space for trees */ -//uInt *hn; /* hufts used in space */ -//uInt *v; /* working area: values in order of bit length */ -/* Given a list of code lengths and a maximum table size, make a set of - tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR - if the given code set is incomplete (the tables are still built in this - case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of - lengths), or Z_MEM_ERROR if not enough memory. */ -{ - - uInt a; /* counter for codes of length k */ - uInt c[BMAX+1]; /* bit length count table */ - uInt f; /* i repeats in table every f entries */ - int g; /* maximum code length */ - int h; /* table level */ - register uInt i; /* counter, current code */ - register uInt j; /* counter */ - register int k; /* number of bits in current code */ - int l; /* bits per table (returned in m) */ - uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */ - register uInt *p; /* pointer into c[], b[], or v[] */ - inflate_huft *q; /* points to current table */ - struct inflate_huft_s r; /* table entry for structure assignment */ - inflate_huft *u[BMAX]; /* table stack */ - register int w; /* bits before this table == (l * h) */ - uInt x[BMAX+1]; /* bit offsets, then code stack */ - uInt *xp; /* pointer into x */ - int y; /* number of dummy codes added */ - uInt z; /* number of entries in current table */ - - - /* Generate counts for each bit length */ - p = c; -#define C0 *p++ = 0; -#define C2 C0 C0 C0 C0 -#define C4 C2 C2 C2 C2 - C4 /* clear c[]--assume BMAX+1 is 16 */ - p = b; i = n; - do { - c[*p++]++; /* assume all entries <= BMAX */ - } while (--i); - if (c[0] == n) /* null input--all zero length codes */ - { - *t = (inflate_huft *)Z_NULL; - *m = 0; - return Z_OK; - } - - - /* Find minimum and maximum length, bound *m by those */ - l = *m; - for (j = 1; j <= BMAX; j++) - if (c[j]) - break; - k = j; /* minimum code length */ - if ((uInt)l < j) - l = j; - for (i = BMAX; i; i--) - if (c[i]) - break; - g = i; /* maximum code length */ - if ((uInt)l > i) - l = i; - *m = l; - - - /* Adjust last length count to fill out codes, if needed */ - for (y = 1 << j; j < i; j++, y <<= 1) - if ((y -= c[j]) < 0) - return Z_DATA_ERROR; - if ((y -= c[i]) < 0) - return Z_DATA_ERROR; - c[i] += y; - - - /* Generate starting offsets into the value table for each length */ - x[1] = j = 0; - p = c + 1; xp = x + 2; - while (--i) { /* note that i == g from above */ - *xp++ = (j += *p++); - } - - - /* Make a table of values in order of bit lengths */ - p = b; i = 0; - do { - if ((j = *p++) != 0) - v[x[j]++] = i; - } while (++i < n); - n = x[g]; /* set n to length of v */ - - - /* Generate the Huffman codes and for each, make the table entries */ - x[0] = i = 0; /* first Huffman code is zero */ - p = v; /* grab values in bit order */ - h = -1; /* no tables yet--level -1 */ - w = -l; /* bits decoded == (l * h) */ - u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ - q = (inflate_huft *)Z_NULL; /* ditto */ - z = 0; /* ditto */ - - /* go through the bit lengths (k already is bits in shortest code) */ - for (; k <= g; k++) - { - a = c[k]; - while (a--) - { - /* here i is the Huffman code of length k bits for value *p */ - /* make tables up to required level */ - while (k > w + l) - { - h++; - w += l; /* previous table always l bits */ - - /* compute minimum size table less than or equal to l bits */ - z = g - w; - z = z > (uInt)l ? l : z; /* table size upper limit */ - if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ - { /* too few codes for k-w bit table */ - f -= a + 1; /* deduct codes from patterns left */ - xp = c + k; - if (j < z) - while (++j < z) /* try smaller tables up to z bits */ - { - if ((f <<= 1) <= *++xp) - break; /* enough codes to use up j bits */ - f -= *xp; /* else deduct codes from patterns */ - } - } - z = 1 << j; /* table entries for j-bit table */ - - /* allocate new table */ - if (*hn + z > MANY) /* (note: doesn't matter for fixed) */ - return Z_MEM_ERROR; /* not enough memory */ - u[h] = q = hp + *hn; - *hn += z; - - /* connect to last table, if there is one */ - if (h) - { - x[h] = i; /* save pattern for backing up */ - r.bits = (Byte)l; /* bits to dump before this table */ - r.exop = (Byte)j; /* bits in this table */ - j = i >> (w - l); - r.base = (uInt)(q - u[h-1] - j); /* offset to this table */ - u[h-1][j] = r; /* connect to last table */ - } - else - *t = q; /* first table is returned result */ - } - - /* set up table entry in r */ - r.bits = (Byte)(k - w); - if (p >= v + n) - r.exop = 128 + 64; /* out of values--invalid code */ - else if (*p < s) - { - r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ - r.base = *p++; /* simple code is just the value */ - } - else - { - r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ - r.base = d[*p++ - s]; - } - - /* fill code-like entries with r */ - f = 1 << (k - w); - for (j = i >> w; j < z; j += f) - q[j] = r; - - /* backwards increment the k-bit code i */ - for (j = 1 << (k - 1); i & j; j >>= 1) - i ^= j; - i ^= j; - - /* backup over finished tables */ - mask = (1 << w) - 1; /* needed on HP, cc -O bug */ - while ((i & mask) != x[h]) - { - h--; /* don't need to update q */ - w -= l; - mask = (1 << w) - 1; - } - } - } - - - /* Return Z_BUF_ERROR if we were given an incomplete table */ - return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; -} - - -int inflate_trees_bits(uInt *c, uInt *bb, inflate_huft * *tb, inflate_huft *hp, z_streamp z) -//uInt *c; /* 19 code lengths */ -//uInt *bb; /* bits tree desired/actual depth */ -//inflate_huft * *tb; /* bits tree result */ -//inflate_huft *hp; /* space for trees */ -//z_streamp z; /* for messages */ -{ - int r; - uInt hn = 0; /* hufts used in space */ - uInt *v; /* work area for huft_build */ - - if ((v = (uInt*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) - return Z_MEM_ERROR; - r = huft_build(c, 19, 19, (uInt*)Z_NULL, (uInt*)Z_NULL, - tb, bb, hp, &hn, v); - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed dynamic bit lengths tree"; - else if (r == Z_BUF_ERROR || *bb == 0) - { - z->msg = (char*)"incomplete dynamic bit lengths tree"; - r = Z_DATA_ERROR; - } - ZFREE(z, v); - return r; -} - - -int inflate_trees_dynamic(uInt nl, uInt nd, uInt *c, uInt *bl, uInt *bd, inflate_huft * *tl, inflate_huft * *td, inflate_huft *hp, z_streamp z) -//uInt nl; /* number of literal/length codes */ -//uInt nd; /* number of distance codes */ -//uInt *c; /* that many (total) code lengths */ -//uInt *bl; /* literal desired/actual bit depth */ -//uInt *bd; /* distance desired/actual bit depth */ -//inflate_huft * *tl; /* literal/length tree result */ -//inflate_huft * *td; /* distance tree result */ -//inflate_huft *hp; /* space for trees */ -//z_streamp z; /* for messages */ -{ - int r; - uInt hn = 0; /* hufts used in space */ - uInt *v; /* work area for huft_build */ - - /* allocate work area */ - if ((v = (uInt*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) - return Z_MEM_ERROR; - - /* build literal/length tree */ - r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); - if (r != Z_OK || *bl == 0) - { - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed literal/length tree"; - else if (r != Z_MEM_ERROR) - { - z->msg = (char*)"incomplete literal/length tree"; - r = Z_DATA_ERROR; - } - ZFREE(z, v); - return r; - } - - /* build distance tree */ - r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); - if (r != Z_OK || (*bd == 0 && nl > 257)) - { - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed distance tree"; - else if (r == Z_BUF_ERROR) { -#ifdef PKZIP_BUG_WORKAROUND - r = Z_OK; - } -#else - z->msg = (char*)"incomplete distance tree"; - r = Z_DATA_ERROR; - } - else if (r != Z_MEM_ERROR) - { - z->msg = (char*)"empty distance tree with lengths"; - r = Z_DATA_ERROR; - } - ZFREE(z, v); - return r; -#endif - } - - /* done */ - ZFREE(z, v); - return Z_OK; -} - -/* inffixed.h -- table for decoding fixed codes - * Generated automatically by the maketree.c program - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -static uInt fixed_bl = 9; -static uInt fixed_bd = 5; -static inflate_huft fixed_tl[] = { - {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, - {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, - {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, - {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, - {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, - {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, - {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, - {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, - {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, - {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, - {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, - {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, - {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, - {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, - {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, - {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, - {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, - {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, - {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, - {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, - {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, - {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, - {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, - {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, - {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, - {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, - {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, - {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, - {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, - {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, - {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, - {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, - {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, - {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, - {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, - {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, - {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, - {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, - {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, - {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, - {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, - {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, - {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, - {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, - {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, - {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, - {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, - {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, - {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, - {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, - {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, - {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, - {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, - {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, - {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, - {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, - {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, - {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, - {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, - {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, - {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, - {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, - {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, - {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, - {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, - {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, - {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, - {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, - {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, - {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, - {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, - {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, - {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, - {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, - {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, - {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, - {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, - {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, - {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, - {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, - {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, - {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, - {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, - {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, - {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, - {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, - {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, - {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, - {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, - {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, - {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, - {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, - {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, - {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, - {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, - {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, - {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, - {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, - {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, - {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, - {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, - {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, - {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, - {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, - {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, - {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, - {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, - {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, - {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, - {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, - {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, - {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, - {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, - {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, - {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, - {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, - {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, - {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, - {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, - {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, - {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, - {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, - {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, - {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, - {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, - {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, - {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, - {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} - }; -static inflate_huft fixed_td[] = { - {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, - {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, - {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, - {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, - {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, - {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, - {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, - {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} - }; - -int inflate_trees_fixed(uInt *bl, uInt *bd, inflate_huft * *tl, inflate_huft * *td, z_streamp z) -//uInt *bl; /* literal desired/actual bit depth */ -//uInt *bd; /* distance desired/actual bit depth */ -//inflate_huft * *tl; /* literal/length tree result */ -//inflate_huft * *td; /* distance tree result */ -//z_streamp z; /* for memory allocation */ -{ - *bl = fixed_bl; - *bd = fixed_bd; - *tl = fixed_tl; - *td = fixed_td; - return Z_OK; -} - -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits - -/* macros for bit input with no checking and for returning unused bytes */ -#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;} - -/* Called with number of bytes left to write in window at least 258 - (the maximum string length) and number of input bytes available - at least ten. The ten bytes are six bytes for the longest length/ - distance pair plus four bytes for overloading the bit buffer. */ - -int inflate_fast(uInt bl, uInt bd, inflate_huft *tl, inflate_huft *td, inflate_blocks_statef *s, z_streamp z) -{ - inflate_huft *t; /* temporary pointer */ - uInt e; /* extra bits or operation */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Byte *p; /* input data pointer */ - uInt n; /* bytes available there */ - Byte *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - uInt ml; /* mask for literal/length tree */ - uInt md; /* mask for distance tree */ - uInt c; /* bytes to copy */ - uInt d; /* distance back to copy from */ - Byte *r; /* copy source pointer */ - - /* load input, output, bit values */ - LOAD - - /* initialize masks */ - ml = inflate_mask[bl]; - md = inflate_mask[bd]; - - /* do until not enough input or output space for fast loop */ - do { /* assume called with m >= 258 && n >= 10 */ - /* get literal/length code */ - GRABBITS(20) /* max bits for literal/length code */ - if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) - { - DUMPBITS(t->bits) - Tracevv((t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - continue; - } - do { - DUMPBITS(t->bits) - if (e & 16) - { - /* get extra bits for length */ - e &= 15; - c = t->base + ((uInt)b & inflate_mask[e]); - DUMPBITS(e) - Tracevv(("inflate: * length %u\n", c)); - - /* decode distance base of block to copy */ - GRABBITS(15); /* max bits for distance code */ - e = (t = td + ((uInt)b & md))->exop; - do { - DUMPBITS(t->bits) - if (e & 16) - { - /* get extra bits to add to distance base */ - e &= 15; - GRABBITS(e) /* get extra bits (up to 13) */ - d = t->base + ((uInt)b & inflate_mask[e]); - DUMPBITS(e) - Tracevv(("inflate: * distance %u\n", d)); - - /* do the copy */ - m -= c; - if ((uInt)(q - s->window) >= d) /* offset before dest */ - { /* just copy */ - r = q - d; - *q++ = *r++; c--; /* minimum count is three, */ - *q++ = *r++; c--; /* so unroll loop a little */ - } - else /* else offset after destination */ - { - e = d - (uInt)(q - s->window); /* bytes from offset to end */ - r = s->end - e; /* pointer to offset */ - if (c > e) /* if source crosses, */ - { - c -= e; /* copy to end of window */ - do { - *q++ = *r++; - } while (--e); - r = s->window; /* copy rest from start of window */ - } - } - do { /* copy all or what's left */ - *q++ = *r++; - } while (--c); - break; - } - else if ((e & 64) == 0) - { - t += t->base; - e = (t += ((uInt)b & inflate_mask[e]))->exop; - } - else - { - z->msg = (char*)"invalid distance code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - } while (1); - break; - } - if ((e & 64) == 0) - { - t += t->base; - if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) - { - DUMPBITS(t->bits) - Tracevv((t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - break; - } - } - else if (e & 32) - { - Tracevv(("inflate: * end of block\n")); - UNGRAB - UPDATE - return Z_STREAM_END; - } - else - { - z->msg = (char*)"invalid literal/length code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - } while (1); - } while (m >= 258 && n >= 10); - - /* not enough input or output--restore pointers and return */ - UNGRAB - UPDATE - return Z_OK; -} - -/* infcodes.c -- process literals and length/distance pairs - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits - -typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ - START, /* x: set up for LEN */ - LEN, /* i: get length/literal/eob next */ - LENEXT, /* i: getting length extra (have base) */ - DIST, /* i: get distance next */ - DISTEXT, /* i: getting distance extra */ - COPY, /* o: copying bytes in window, waiting for space */ - LIT, /* o: got literal, waiting for output space */ - WASH, /* o: got eob, possibly still output waiting */ - END, /* x: got eob and all data flushed */ - BADCODE} /* x: got error */ -inflate_codes_mode; - -/* inflate codes private state */ -struct inflate_codes_state { - - /* mode */ - inflate_codes_mode mode; /* current inflate_codes mode */ - - /* mode dependent information */ - uInt len; - union { - struct { - inflate_huft *tree; /* pointer into tree */ - uInt need; /* bits needed */ - } code; /* if LEN or DIST, where in tree */ - uInt lit; /* if LIT, literal */ - struct { - uInt get; /* bits to get for extra */ - uInt dist; /* distance back to copy from */ - } copy; /* if EXT or COPY, where and how much */ - } sub; /* submode */ - - /* mode independent information */ - Byte lbits; /* ltree bits decoded per branch */ - Byte dbits; /* dtree bits decoder per branch */ - inflate_huft *ltree; /* literal/length/eob tree */ - inflate_huft *dtree; /* distance tree */ - -}; - - -inflate_codes_statef *inflate_codes_new(uInt bl, uInt bd, inflate_huft *tl, inflate_huft *td, z_streamp z) -{ - inflate_codes_statef *c; - - if ((c = (inflate_codes_statef *) - ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) - { - c->mode = START; - c->lbits = (Byte)bl; - c->dbits = (Byte)bd; - c->ltree = tl; - c->dtree = td; - Tracev(("inflate: codes new\n")); - } - return c; -} - - -int inflate_codes(inflate_blocks_statef *s, z_streamp z, int r) -{ - uInt j; /* temporary storage */ - inflate_huft *t; /* temporary pointer */ - uInt e; /* extra bits or operation */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Byte *p; /* input data pointer */ - uInt n; /* bytes available there */ - Byte *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - Byte *f; /* pointer to copy strings from */ - inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ - - /* copy input/output information to locals (UPDATE macro restores) */ - LOAD - - /* process input and output based on current state */ - while (1) switch (c->mode) - { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ - case START: /* x: set up for LEN */ -#ifndef SLOW - if (m >= 258 && n >= 10) - { - UPDATE - r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); - LOAD - if (r != Z_OK) - { - c->mode = r == Z_STREAM_END ? WASH : BADCODE; - break; - } - } -#endif /* !SLOW */ - c->sub.code.need = c->lbits; - c->sub.code.tree = c->ltree; - c->mode = LEN; - case LEN: /* i: get length/literal/eob next */ - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e == 0) /* literal */ - { - c->sub.lit = t->base; - Tracevv((t->base >= 0x20 && t->base < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", t->base)); - c->mode = LIT; - break; - } - if (e & 16) /* length */ - { - c->sub.copy.get = e & 15; - c->len = t->base; - c->mode = LENEXT; - break; - } - if ((e & 64) == 0) /* next table */ - { - c->sub.code.need = e; - c->sub.code.tree = t + t->base; - break; - } - if (e & 32) /* end of block */ - { - Tracevv(("inflate: end of block\n")); - c->mode = WASH; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = (char*)"invalid literal/length code"; - r = Z_DATA_ERROR; - LEAVE - case LENEXT: /* i: getting length extra (have base) */ - j = c->sub.copy.get; - NEEDBITS(j) - c->len += (uInt)b & inflate_mask[j]; - DUMPBITS(j) - c->sub.code.need = c->dbits; - c->sub.code.tree = c->dtree; - Tracevv(("inflate: length %u\n", c->len)); - c->mode = DIST; - case DIST: /* i: get distance next */ - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e & 16) /* distance */ - { - c->sub.copy.get = e & 15; - c->sub.copy.dist = t->base; - c->mode = DISTEXT; - break; - } - if ((e & 64) == 0) /* next table */ - { - c->sub.code.need = e; - c->sub.code.tree = t + t->base; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = (char*)"invalid distance code"; - r = Z_DATA_ERROR; - LEAVE - case DISTEXT: /* i: getting distance extra */ - j = c->sub.copy.get; - NEEDBITS(j) - c->sub.copy.dist += (uInt)b & inflate_mask[j]; - DUMPBITS(j) - Tracevv(("inflate: distance %u\n", c->sub.copy.dist)); - c->mode = COPY; - case COPY: /* o: copying bytes in window, waiting for space */ -#ifndef __TURBOC__ /* Turbo C bug for following expression */ - f = (uInt)(q - s->window) < c->sub.copy.dist ? - s->end - (c->sub.copy.dist - (q - s->window)) : - q - c->sub.copy.dist; -#else - f = q - c->sub.copy.dist; - if ((uInt)(q - s->window) < c->sub.copy.dist) - f = s->end - (c->sub.copy.dist - (uInt)(q - s->window)); -#endif - while (c->len) - { - NEEDOUT - OUTBYTE(*f++) - if (f == s->end) - f = s->window; - c->len--; - } - c->mode = START; - break; - case LIT: /* o: got literal, waiting for output space */ - NEEDOUT - OUTBYTE(c->sub.lit) - c->mode = START; - break; - case WASH: /* o: got eob, possibly more output */ - if (k > 7) /* return unused byte, if any */ - { - Assert(k < 16, "inflate_codes grabbed too many bytes") - k -= 8; - n++; - p--; /* can always return one */ - } - FLUSH - if (s->read != s->write) - LEAVE - c->mode = END; - case END: - r = Z_STREAM_END; - LEAVE - case BADCODE: /* x: got error */ - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -#ifdef NEED_DUMMY_RETURN - return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ -#endif -} - - -void inflate_codes_free(inflate_codes_statef *c, z_streamp z) -{ - ZFREE(z, c); - Tracev(("inflate: codes free\n")); -} - -/* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#define BASE 65521L /* largest prime smaller than 65536 */ -#define NMAX 5552 -/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ - -#undef DO1 -#undef DO2 -#undef DO4 -#undef DO8 - -#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} -#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); -#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); -#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); -#define DO16(buf) DO8(buf,0); DO8(buf,8); - -/* ========================================================================= */ -uLong adler32(uLong adler, const Byte *buf, uInt len) -{ - unsigned long s1 = adler & 0xffff; - unsigned long s2 = (adler >> 16) & 0xffff; - int k; - - if (buf == Z_NULL) return 1L; - - while (len > 0) { - k = len < NMAX ? len : NMAX; - len -= k; - while (k >= 16) { - DO16(buf); - buf += 16; - k -= 16; - } - if (k != 0) do { - s1 += *buf++; - s2 += s1; - } while (--k); - s1 %= BASE; - s2 %= BASE; - } - return (s2 << 16) | s1; -} - -/* infblock.h -- header to use infblock.c - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -extern inflate_blocks_statef * inflate_blocks_new OF(( - z_streamp z, - check_func c, /* check function */ - uInt w)); /* window size */ - -extern int inflate_blocks OF(( - inflate_blocks_statef *, - z_streamp , - int)); /* initial return code */ - -extern void inflate_blocks_reset OF(( - inflate_blocks_statef *, - z_streamp , - uLong *)); /* check value on output */ - -extern int inflate_blocks_free OF(( - inflate_blocks_statef *, - z_streamp)); - -extern void inflate_set_dictionary OF(( - inflate_blocks_statef *s, - const Byte *d, /* dictionary */ - uInt n)); /* dictionary length */ - -extern int inflate_blocks_sync_point OF(( - inflate_blocks_statef *s)); - -typedef enum { - imMETHOD, /* waiting for method byte */ - imFLAG, /* waiting for flag byte */ - imDICT4, /* four dictionary check bytes to go */ - imDICT3, /* three dictionary check bytes to go */ - imDICT2, /* two dictionary check bytes to go */ - imDICT1, /* one dictionary check byte to go */ - imDICT0, /* waiting for inflateSetDictionary */ - imBLOCKS, /* decompressing blocks */ - imCHECK4, /* four check bytes to go */ - imCHECK3, /* three check bytes to go */ - imCHECK2, /* two check bytes to go */ - imCHECK1, /* one check byte to go */ - imDONE, /* finished check, done */ - imBAD} /* got an error--stay here */ -inflate_mode; - -/* inflate private state */ -struct internal_state { - - /* mode */ - inflate_mode mode; /* current inflate mode */ - - /* mode dependent information */ - union { - uInt method; /* if FLAGS, method byte */ - struct { - uLong was; /* computed check value */ - uLong need; /* stream check value */ - } check; /* if CHECK, check values to compare */ - uInt marker; /* if BAD, inflateSync's marker bytes count */ - } sub; /* submode */ - - /* mode independent information */ - int nowrap; /* flag for no wrapper */ - uInt wbits; /* log2(window size) (8..15, defaults to 15) */ - inflate_blocks_statef - *blocks; /* current inflate_blocks state */ - -}; - - -int inflateReset(z_streamp z) -{ - if (z == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - z->total_in = z->total_out = 0; - z->msg = Z_NULL; - z->state->mode = z->state->nowrap ? imBLOCKS : imMETHOD; - inflate_blocks_reset(z->state->blocks, z, Z_NULL); - Tracev(("inflate: reset\n")); - return Z_OK; -} - - -int inflateEnd(z_streamp z) -{ - if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) - return Z_STREAM_ERROR; - if (z->state->blocks != Z_NULL) - inflate_blocks_free(z->state->blocks, z); - ZFREE(z, z->state); - z->state = Z_NULL; - Tracev(("inflate: end\n")); - return Z_OK; -} - - - -int inflateInit2_(z_streamp z, int w, const char *version, int stream_size) -{ - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != sizeof(z_stream)) - return Z_VERSION_ERROR; - - /* initialize state */ - if (z == Z_NULL) - return Z_STREAM_ERROR; - z->msg = Z_NULL; - if (z->zalloc == Z_NULL) - { - z->zalloc = (void *(*)(void *, unsigned, unsigned))zcalloc; - z->opaque = (voidp)0; - } - if (z->zfree == Z_NULL) z->zfree = (void (*)(void *, void *))zcfree; - if ((z->state = (struct internal_state *) - ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) - return Z_MEM_ERROR; - z->state->blocks = Z_NULL; - - /* handle undocumented nowrap option (no zlib header or check) */ - z->state->nowrap = 0; - if (w < 0) - { - w = - w; - z->state->nowrap = 1; - } - - /* set window size */ - if (w < 8 || w > 15) - { - inflateEnd(z); - return Z_STREAM_ERROR; - } - z->state->wbits = (uInt)w; - - /* create inflate_blocks state */ - if ((z->state->blocks = - inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) - == Z_NULL) - { - inflateEnd(z); - return Z_MEM_ERROR; - } - Tracev(("inflate: allocated\n")); - - /* reset state */ - inflateReset(z); - return Z_OK; -} - - -int inflateInit_(z_streamp z, const char *version, int stream_size) -{ - return inflateInit2_(z, DEF_WBITS, version, stream_size); -} - - -#define iNEEDBYTE {if(z->avail_in==0)return r;r=f;} -#define iNEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) - -int inflate(z_streamp z, int f) -{ - int r; - uInt b; - - if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) - return Z_STREAM_ERROR; - f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; - r = Z_BUF_ERROR; - while (1) switch (z->state->mode) - { - case imMETHOD: - iNEEDBYTE - if (((z->state->sub.method = iNEXTBYTE) & 0xf) != Z_DEFLATED) - { - z->state->mode = imBAD; - z->msg = (char*)"unknown compression method"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - if ((z->state->sub.method >> 4) + 8 > z->state->wbits) - { - z->state->mode = imBAD; - z->msg = (char*)"invalid window size"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - z->state->mode = imFLAG; - case imFLAG: - iNEEDBYTE - b = iNEXTBYTE; - if (((z->state->sub.method << 8) + b) % 31) - { - z->state->mode = imBAD; - z->msg = (char*)"incorrect header check"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - Tracev(("inflate: zlib header ok\n")); - if (!(b & PRESET_DICT)) - { - z->state->mode = imBLOCKS; - break; - } - z->state->mode = imDICT4; - case imDICT4: - iNEEDBYTE - z->state->sub.check.need = (uLong)iNEXTBYTE << 24; - z->state->mode = imDICT3; - case imDICT3: - iNEEDBYTE - z->state->sub.check.need += (uLong)iNEXTBYTE << 16; - z->state->mode = imDICT2; - case imDICT2: - iNEEDBYTE - z->state->sub.check.need += (uLong)iNEXTBYTE << 8; - z->state->mode = imDICT1; - case imDICT1: - iNEEDBYTE - z->state->sub.check.need += (uLong)iNEXTBYTE; - z->adler = z->state->sub.check.need; - z->state->mode = imDICT0; - return Z_NEED_DICT; - case imDICT0: - z->state->mode = imBAD; - z->msg = (char*)"need dictionary"; - z->state->sub.marker = 0; /* can try inflateSync */ - return Z_STREAM_ERROR; - case imBLOCKS: - r = inflate_blocks(z->state->blocks, z, r); - if (r == Z_DATA_ERROR) - { - z->state->mode = imBAD; - z->state->sub.marker = 0; /* can try inflateSync */ - break; - } - if (r == Z_OK) - r = f; - if (r != Z_STREAM_END) - return r; - r = f; - inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); - if (z->state->nowrap) - { - z->state->mode = imDONE; - break; - } - z->state->mode = imCHECK4; - case imCHECK4: - iNEEDBYTE - z->state->sub.check.need = (uLong)iNEXTBYTE << 24; - z->state->mode = imCHECK3; - case imCHECK3: - iNEEDBYTE - z->state->sub.check.need += (uLong)iNEXTBYTE << 16; - z->state->mode = imCHECK2; - case imCHECK2: - iNEEDBYTE - z->state->sub.check.need += (uLong)iNEXTBYTE << 8; - z->state->mode = imCHECK1; - case imCHECK1: - iNEEDBYTE - z->state->sub.check.need += (uLong)iNEXTBYTE; - - if (z->state->sub.check.was != z->state->sub.check.need) - { - z->state->mode = imBAD; - z->msg = (char*)"incorrect data check"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - Tracev(("inflate: zlib check ok\n")); - z->state->mode = imDONE; - case imDONE: - return Z_STREAM_END; - case imBAD: - return Z_DATA_ERROR; - default: - return Z_STREAM_ERROR; - } -#ifdef NEED_DUMMY_RETURN - return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ -#endif -} - - -int inflateSetDictionary(z_streamp z, const Byte *dictionary, uInt dictLength) -{ - uInt length = dictLength; - - if (z == Z_NULL || z->state == Z_NULL || z->state->mode != imDICT0) - return Z_STREAM_ERROR; - - if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; - z->adler = 1L; - - if (length >= ((uInt)1<state->wbits)) - { - length = (1<state->wbits)-1; - dictionary += dictLength - length; - } - inflate_set_dictionary(z->state->blocks, dictionary, length); - z->state->mode = imBLOCKS; - return Z_OK; -} - - -int inflateSync(z_streamp z) -{ - uInt n; /* number of bytes to look at */ - Byte *p; /* pointer to bytes */ - uInt m; /* number of marker bytes found in a row */ - uLong r, w; /* temporaries to save total_in and total_out */ - - /* set up */ - if (z == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - if (z->state->mode != imBAD) - { - z->state->mode = imBAD; - z->state->sub.marker = 0; - } - if ((n = z->avail_in) == 0) - return Z_BUF_ERROR; - p = z->next_in; - m = z->state->sub.marker; - - /* search */ - while (n && m < 4) - { - static const Byte mark[4] = {0, 0, 0xff, 0xff}; - if (*p == mark[m]) - m++; - else if (*p) - m = 0; - else - m = 4 - m; - p++, n--; - } - - /* restore */ - z->total_in += p - z->next_in; - z->next_in = p; - z->avail_in = n; - z->state->sub.marker = m; - - /* return no joy or set up to restart on a new block */ - if (m != 4) - return Z_DATA_ERROR; - r = z->total_in; w = z->total_out; - inflateReset(z); - z->total_in = r; z->total_out = w; - z->state->mode = imBLOCKS; - return Z_OK; -} - - -/* Returns true if inflate is currently at the end of a block generated - * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP - * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH - * but removes the length bytes of the resulting empty stored block. When - * decompressing, PPP checks that at the end of input packet, inflate is - * waiting for these length bytes. - */ -int inflateSyncPoint(z_streamp z) -{ - if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL) - return Z_STREAM_ERROR; - return inflate_blocks_sync_point(z->state->blocks); -} - -voidp zcalloc (voidp opaque, unsigned items, unsigned size) -{ - if (opaque) items += size - size; /* make compiler happy */ - return (voidp)malloc(items*size); -} - -void zcfree (voidp opaque, voidp ptr) -{ - free(ptr); - if (opaque) return; /* make compiler happy */ -} - +/***************************************************************************** + * name: unzip.c + * + * desc: IO on .zip files using portions of zlib + * + * + *****************************************************************************/ + +#include +#include +#include +#include "unzip.h" + +typedef unsigned char byte; + +/* unzip.h -- IO for uncompress .zip files using zlib + Version 0.15 beta, Mar 19th, 1998, + + Copyright (C) 1998 Gilles Vollant + + This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + Encryption and multi volume ZipFile (span) are not supported. + Old compressions used by old PKZip 1.x are not supported + + THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE + CAN CHANGE IN FUTURE VERSION !! + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + +*/ +/* for more info about .ZIP format, see + ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip */ + +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.1.3, July 9th, 1998 + + Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef _ZCONF_H +#define _ZCONF_H + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +#define OF(args) args +#endif + +typedef unsigned char Byte; /* 8 bits */ +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ +typedef Byte *voidp; + +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#endif /* _ZCONF_H */ + +#define ZLIB_VERSION "1.1.3" + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +/* Allowed flush values; see deflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +const char * zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +int deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +int deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + 0.1% larger than avail_in plus 12 bytes. If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so (that is, total_in bytes). + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). +*/ + + +int deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +int inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +int inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may some + introduce some output latency (reading input without producing any output) + except when forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much + output as possible to the output buffer. The flushing behavior of inflate is + not specified for values of the flush parameter other than Z_SYNC_FLUSH + and Z_FINISH, but the current implementation actually flushes as much output + as possible anyway. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster routine + may be used for the single inflate() call. + + If a preset dictionary is needed at this point (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the + dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise + it sets strm->adler to the adler32 checksum of all output produced + so (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or + an error code as described below. At the end of the stream, inflate() + checks that its computed adler32 checksum is equal to that saved by the + compressor and returns Z_STREAM_END only if the checksum is correct. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect + adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent + (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if no progress is possible or if there was not + enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR + case, the application may then call inflateSync to look for a good + compression block. +*/ + + +int inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +int deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match). Filtered data consists mostly of small values with a + somewhat random distribution. In this case, the compression algorithm is + tuned to compress them better. The effect of Z_FILTERED is to force more + Huffman coding and less string matching; it is somewhat intermediate + between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects + the compression ratio but not the correctness of the compressed output even + if it is not set appropriately. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +int deflateSetDictionary OF((z_streamp strm, + const Byte *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. + + Upon return of this function, strm->adler is set to the Adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +int deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +int deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +int deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +/* +int inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. If a compressed stream with a larger window size is given as + input, inflate() will return with the error code Z_DATA_ERROR instead of + trying to allocate a larger window. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative + memLevel). msg is set to null if there is no error message. inflateInit2 + does not perform any decompression apart from reading the zlib header if + present: this will be done by inflate(). (So next_in and avail_in may be + modified, but next_out and avail_out are unchanged.) +*/ + +int inflateSetDictionary OF((z_streamp strm, + const Byte *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate + if this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +int inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +int inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +int compress OF((Byte *dest, uLong *destLen, + const Byte *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least 0.1% larger than + sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +int compress2 OF((Byte *dest, uLong *destLen, + const Byte *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +int uncompress OF((Byte *dest, uLong *destLen, + const Byte *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ + + +typedef voidp gzFile; + +gzFile gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h". (See the description + of deflateInit2 for more information about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +gzFile gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +int gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +int gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +int gzwrite OF((gzFile file, + const voidp buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +int gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ + +int gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +char * gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +int gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +int gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +int gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +long gzseek OF((gzFile file, + long offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +int gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +long gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +int gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +int gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +const char * gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +uLong adler32 OF((uLong adler, const Byte *buf, uInt len)); + +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +uLong crc32 OF((uLong crc, const Byte *buf, uInt len)); +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +// private stuff to not include cmdlib.h +/* +============================================================================ + + BYTE ORDER FUNCTIONS + +============================================================================ +*/ + +#ifdef _SGI_SOURCE +#define __BIG_ENDIAN__ +#endif + +#ifdef __BIG_ENDIAN__ + +short __LittleShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short __BigShort (short l) +{ + return l; +} + + +int __LittleLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int __BigLong (int l) +{ + return l; +} + + +float __LittleFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float __BigFloat (float l) +{ + return l; +} + + +#else + + +short __BigShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short __LittleShort (short l) +{ + return l; +} + + +int __BigLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int __LittleLong (int l) +{ + return l; +} + +float __BigFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float __LittleFloat (float l) +{ + return l; +} + + + +#endif + + + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +int deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +int inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +int deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +int inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) + + +const char * zError OF((int err)); +int inflateSyncPoint OF((z_streamp z)); +const uLong * get_crc_table OF((void)); + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + + /* Common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#define zmemcpy memcpy +#define zmemcmp memcmp +#define zmemzero(dest, len) memset(dest, 0, len) + +/* Diagnostic functions */ +#ifdef _ZIP_DEBUG_ + int z_verbose = 0; +# define Assert(cond,msg) assert(cond); + //{if(!(cond)) Sys_Error(msg);} +# define Trace(x) {if (z_verbose>=0) Sys_Error x ;} +# define Tracev(x) {if (z_verbose>0) Sys_Error x ;} +# define Tracevv(x) {if (z_verbose>1) Sys_Error x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) Sys_Error x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) Sys_Error x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +typedef uLong (*check_func) OF((uLong check, const Byte *buf, uInt len)); +voidp zcalloc OF((voidp opaque, unsigned items, unsigned size)); +void zcfree OF((voidp opaque, voidp ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidp)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + + +#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \ + !defined(CASESENSITIVITYDEFAULT_NO) +#define CASESENSITIVITYDEFAULT_NO +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (65536) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + +/* +static int unzlocal_getByte(FILE *fin,int *pi) +{ + unsigned char c; + int err = fread(&c, 1, 1, fin); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ferror(fin)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} +*/ + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +static int unzlocal_getShort (FILE* fin, uLong *pX) +{ + short v; + + fread( &v, sizeof(v), 1, fin ); + + *pX = __LittleShort( v); + return UNZ_OK; + +/* + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +*/ +} + +static int unzlocal_getLong (FILE *fin, uLong *pX) +{ + int v; + + fread( &v, sizeof(v), 1, fin ); + + *pX = __LittleLong( v); + return UNZ_OK; + +/* + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +*/ +} + + +/* My own strcmpi / strcasecmp */ +static int strcmpcasenosensitive_internal (const char* fileName1,const char* fileName2) +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int unzStringFileNameCompare (const char* fileName1,const char* fileName2,int iCaseSensitivity) +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#define BUFREADCOMMENT (0x400) + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +static uLong unzlocal_SearchCentralDir(FILE *fin) +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack=0xffff; /* maximum size of global comment */ + uLong uPosFound=0; + + if (fseek(fin,0,SEEK_END) != 0) + return 0; + + + uSizeFile = ftell( fin ); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)malloc(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (fseek(fin,uReadPos,SEEK_SET)!=0) + break; + + if (fread(buf,(uInt)uReadSize,1,fin)!=1) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + free(buf); + return uPosFound; +} + +extern unzFile unzReOpen (const char* path, unzFile file) +{ + unz_s *s; + FILE * fin; + + fin=fopen(path,"rb"); + if (fin==NULL) + return NULL; + + s=(unz_s*)malloc(sizeof(unz_s)); + memcpy(s, (unz_s*)file, sizeof(unz_s)); + + s->file = fin; + return (unzFile)s; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer + "zlib/zlib109.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +extern unzFile unzOpen (const char* path) +{ + unz_s us; + unz_s *s; + uLong central_pos,uL; + FILE * fin ; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + fin=fopen(path,"rb"); + if (fin==NULL) + return NULL; + + central_pos = unzlocal_SearchCentralDir(fin); + if (central_pos==0) + err=UNZ_ERRNO; + + if (fseek(fin,central_pos,SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unzlocal_getLong(fin,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir */ + if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* zipfile comment length */ + if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + fclose(s->file); + free(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int unzGetGlobalInfo (unzFile file,unz_global_info *pglobal_info) +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + + +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +static void unzlocal_DosDateToTmuDate (uLong ulDosDate, tm_unz* ptm) +{ + uLong uDate; + uDate = (uLong)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +static int unzlocal_GetCurrentFileInfoInternal (unzFile file, + unz_file_info *pfile_info, + unz_file_info_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize) +{ + unz_s* s; + unz_file_info file_info; + unz_file_info_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + + if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + + if ((err==UNZ_OK) && (extraField!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_extrafile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek += file_info.size_file_extra - uSizeRead; + } + else + lSeek+=file_info.size_file_extra; + + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentfile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int unzGetCurrentFileInfo ( unzFile file, unz_file_info *pfile_info, + char *szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char *szComment, uLong commentBufferSize) +{ + return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int unzGoToFirstFile (unzFile file) +{ + int err=UNZ_OK; + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int unzGoToNextFile (unzFile file) +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) +{ + unz_s* s; + int err; + + + uLong num_fileSaved; + uLong pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + unzGetCurrentFileInfo(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + return err; +} + + +/* + Read the static header of the current zipfile + Check the coherency of the static header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in static header + (filename and size of extra field data) +*/ +static int unzlocal_CheckCurrentFileCoherencyHeader (unz_s* s, uInt* piSizeVar, + uLong *poffset_local_extrafield, + uInt *psize_local_extrafield) +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (fseek(s->file,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + + if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int unzOpenCurrentFile (unzFile file) +{ + int err=UNZ_OK; + int Store; + uInt iSizeVar; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uLong offset_local_extrafield; /* offset of the static extra field */ + uInt size_local_extrafield; /* size of the static extra field */ + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, + &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip_read_info_s*) + malloc(sizeof(file_in_zip_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)malloc(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + free(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if ((s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + Store = s->cur_file_info.compression_method==0; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->compression_method = + s->cur_file_info.compression_method; + pfile_in_zip_read_info->file=s->file; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if (!Store) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidp)0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=1; + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + + s->pfile_in_zip_read = pfile_in_zip_read_info; + return UNZ_OK; +} + + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int unzReadCurrentFile (unzFile file, void *buf, unsigned len) +{ + int err=UNZ_OK; + uInt iRead = 0; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->read_buffer == NULL)) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Byte*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if (len>pfile_in_zip_read_info->rest_read_uncompressed) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (s->cur_file_info.compressed_size == pfile_in_zip_read_info->rest_read_compressed) + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + if (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1, + pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Byte*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if (pfile_in_zip_read_info->compression_method==0) + { + uInt uDoCopy,i ; + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else + { + uLong uTotalOutBefore,uTotalOutAfter; + const Byte *bufBefore; + uLong uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern long unztell (unzFile file) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (long)pfile_in_zip_read_info->stream.total_out; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int unzeof (unzFile file) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the static-header version of the extra field (sometimes, there is + more info in the static-header version than in the central-header) + + if buf==NULL, it return the size of the static extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int unzGetLocalExtrafield (unzFile file,void *buf,unsigned len) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uInt read_now; + uLong size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int unzCloseCurrentFile (unzFile file) +{ + int err=UNZ_OK; + + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + free(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised) + inflateEnd(&pfile_in_zip_read_info->stream); + + pfile_in_zip_read_info->stream_initialised = 0; + free(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int unzGetGlobalComment (unzFile file, char *szComment, uLong uSizeBuf) +{ + unz_s* s; + uLong uReadThis ; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (fseek(s->file,s->central_pos+22,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (fread(szComment,(uInt)uReadThis,1,s->file)!=1) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef DYNAMIC_CRC_TABLE + +static int crc_table_empty = 1; +static uLong crc_table[256]; +static void make_crc_table OF((void)); + +/* + Generate a table for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The table is simply the CRC of all possible eight bit values. This is all + the information needed to generate CRC's on data a byte at a time for all + combinations of CRC register values and incoming bytes. +*/ +static void make_crc_table() +{ + uLong c; + int n, k; + uLong poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* make exclusive-or pattern from polynomial (0xedb88320L) */ + poly = 0L; + for (n = 0; n < sizeof(p)/sizeof(Byte); n++) + poly |= 1L << (31 - p[n]); + + for (n = 0; n < 256; n++) + { + c = (uLong)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[n] = c; + } + crc_table_empty = 0; +} +#else +/* ======================================================================== + * Table of CRC-32's of all single-byte values (made by make_crc_table) + */ +static const uLong crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; +#endif + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const uLong * get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) make_crc_table(); +#endif + return (const uLong *)crc_table; +} + +/* ========================================================================= */ +#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); + +/* ========================================================================= */ +uLong crc32(uLong crc, const Byte *buf, uInt len) +{ + if (buf == Z_NULL) return 0L; +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif + crc = crc ^ 0xffffffffL; + while (len >= 8) + { + DO8(buf); + len -= 8; + } + if (len) do { + DO1(buf); + } while (--len); + return crc ^ 0xffffffffL; +} + +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_blocks_state; +typedef struct inflate_blocks_state inflate_blocks_statef; + +extern inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +extern int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +extern void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLong *)); /* check value on output */ + +extern int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp)); + +extern void inflate_set_dictionary OF(( + inflate_blocks_statef *s, + const Byte *d, /* dictionary */ + uInt n)); /* dictionary length */ + +extern int inflate_blocks_sync_point OF(( + inflate_blocks_statef *s)); + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* Table for deflate from PKZIP's appnote.txt. */ +static const uInt border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). */ + +typedef struct inflate_huft_s inflate_huft; + +struct inflate_huft_s { + union { + struct { + Byte Exop; /* number of extra bits or operation */ + Byte Bits; /* number of bits in this code or subcode */ + } what; + uInt pad; /* pad structure to a power of 2 (4 bytes for */ + } word; /* 16-bit, 8 bytes for 32-bit int's) */ + uInt base; /* literal, length base, distance base, + or table offset */ +}; + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1004 huft structures (850 for length/literals + and 154 for distances, the latter actually the result of an + exhaustive search). The actual maximum is not known, but the + value below is more than safe. */ +#define MANY 1440 + +extern int inflate_trees_bits OF(( + uInt *, /* 19 code lengths */ + uInt *, /* bits tree desired/actual depth */ + inflate_huft * *, /* bits tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +extern int inflate_trees_dynamic OF(( + uInt, /* number of literal/length codes */ + uInt, /* number of distance codes */ + uInt *, /* that many (total) code lengths */ + uInt *, /* literal desired/actual bit depth */ + uInt *, /* distance desired/actual bit depth */ + inflate_huft * *, /* literal/length tree result */ + inflate_huft * *, /* distance tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +extern int inflate_trees_fixed OF(( + uInt *, /* literal desired/actual bit depth */ + uInt *, /* distance desired/actual bit depth */ + inflate_huft * *, /* literal/length tree result */ + inflate_huft * *, /* distance tree result */ + z_streamp)); /* for memory allocation */ + + +/* infcodes.h -- header to use infcodes.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_codes_state; +typedef struct inflate_codes_state inflate_codes_statef; + +extern inflate_codes_statef *inflate_codes_new OF(( + uInt, uInt, + inflate_huft *, inflate_huft *, + z_streamp )); + +extern int inflate_codes OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +extern void inflate_codes_free OF(( + inflate_codes_statef *, + z_streamp )); + +/* infutil.h -- types and macros common to blocks and codes + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#ifndef _INFUTIL_H +#define _INFUTIL_H + +typedef enum { + TYPE, /* get type bits (3, including end bit) */ + LENS, /* get lengths for stored */ + STORED, /* processing stored block */ + TABLE, /* get table lengths */ + BTREE, /* get bit lengths tree for a dynamic block */ + DTREE, /* get length, distance trees for a dynamic block */ + CODES, /* processing fixed or dynamic block */ + DRY, /* output remaining window bytes */ + DONE, /* finished last block, done */ + BAD} /* got a data error--stuck here */ +inflate_block_mode; + +/* inflate blocks semi-private state */ +struct inflate_blocks_state { + + /* mode */ + inflate_block_mode mode; /* current inflate_block mode */ + + /* mode dependent information */ + union { + uInt left; /* if STORED, bytes left to copy */ + struct { + uInt table; /* table lengths (14 bits) */ + uInt index; /* index into blens (or border) */ + uInt *blens; /* bit lengths of codes */ + uInt bb; /* bit length tree depth */ + inflate_huft *tb; /* bit length decoding tree */ + } trees; /* if DTREE, decoding info for trees */ + struct { + inflate_codes_statef + *codes; + } decode; /* if CODES, current state */ + } sub; /* submode */ + uInt last; /* true if this block is the last block */ + + /* mode independent information */ + uInt bitk; /* bits in bit buffer */ + uLong bitb; /* bit buffer */ + inflate_huft *hufts; /* single malloc for tree space */ + Byte *window; /* sliding window */ + Byte *end; /* one byte after sliding window */ + Byte *read; /* window read pointer */ + Byte *write; /* window write pointer */ + check_func checkfn; /* check function */ + uLong check; /* check on output */ + +}; + + +/* defines for inflate input/output */ +/* update pointers and return */ +#define UPDBITS {s->bitb=b;s->bitk=k;} +#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} +#define UPDOUT {s->write=q;} +#define UPDATE {UPDBITS UPDIN UPDOUT} +#define LEAVE {UPDATE return inflate_flush(s,z,r);} +/* get bytes and bits */ +#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} +#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} +#define NEXTBYTE (n--,*p++) +#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} +/* output bytes */ +#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) +#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} +#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} +#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} +#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} +#define OUTBYTE(a) {*q++=(Byte)(a);m--;} +/* load static pointers */ +#define LOAD {LOADIN LOADOUT} + +/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ +extern uInt inflate_mask[17]; + +/* copy as much as possible from the sliding window to the output area */ +extern int inflate_flush OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +#endif + + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarily, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + + +void inflate_blocks_reset(inflate_blocks_statef *s, z_streamp z, uLong *c) +{ + if (c != Z_NULL) + *c = s->check; + if (s->mode == BTREE || s->mode == DTREE) + ZFREE(z, s->sub.trees.blens); + if (s->mode == CODES) + inflate_codes_free(s->sub.decode.codes, z); + s->mode = TYPE; + s->bitk = 0; + s->bitb = 0; + s->read = s->write = s->window; + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(0L, (const Byte *)Z_NULL, 0); + Tracev(("inflate: blocks reset\n")); +} + + +inflate_blocks_statef *inflate_blocks_new(z_streamp z, check_func c, uInt w) +{ + inflate_blocks_statef *s; + + if ((s = (inflate_blocks_statef *)ZALLOC + (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) + return s; + if ((s->hufts = + (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) + { + ZFREE(z, s); + return Z_NULL; + } + if ((s->window = (Byte *)ZALLOC(z, 1, w)) == Z_NULL) + { + ZFREE(z, s->hufts); + ZFREE(z, s); + return Z_NULL; + } + s->end = s->window + w; + s->checkfn = c; + s->mode = TYPE; + Tracev(("inflate: blocks allocated\n")); + inflate_blocks_reset(s, z, Z_NULL); + return s; +} + + +int inflate_blocks(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt t; /* temporary storage */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Byte *p; /* input data pointer */ + uInt n; /* bytes available there */ + Byte *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input based on current state */ + while (1) switch (s->mode) + { + case TYPE: + NEEDBITS(3) + t = (uInt)b & 7; + s->last = t & 1; + switch (t >> 1) + { + case 0: /* stored */ + Tracev(("inflate: stored block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + t = k & 7; /* go to byte boundary */ + DUMPBITS(t) + s->mode = LENS; /* get length of stored block */ + break; + case 1: /* fixed */ + Tracev(("inflate: fixed codes block%s\n", + s->last ? " (last)" : "")); + { + uInt bl, bd; + inflate_huft *tl, *td; + + inflate_trees_fixed(&bl, &bd, &tl, &td, z); + s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); + if (s->sub.decode.codes == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + } + DUMPBITS(3) + s->mode = CODES; + break; + case 2: /* dynamic */ + Tracev(("inflate: dynamic codes block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + s->mode = TABLE; + break; + case 3: /* illegal */ + DUMPBITS(3) + s->mode = BAD; + z->msg = (char*)"invalid block type"; + r = Z_DATA_ERROR; + LEAVE + } + break; + case LENS: + NEEDBITS(32) + if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) + { + s->mode = BAD; + z->msg = (char*)"invalid stored block lengths"; + r = Z_DATA_ERROR; + LEAVE + } + s->sub.left = (uInt)b & 0xffff; + b = k = 0; /* dump bits */ + Tracev(("inflate: stored length %u\n", s->sub.left)); + s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); + break; + case STORED: + if (n == 0) + LEAVE + NEEDOUT + t = s->sub.left; + if (t > n) t = n; + if (t > m) t = m; + zmemcpy(q, p, t); + p += t; n -= t; + q += t; m -= t; + if ((s->sub.left -= t) != 0) + break; + Tracev(("inflate: stored end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + s->mode = s->last ? DRY : TYPE; + break; + case TABLE: + NEEDBITS(14) + s->sub.trees.table = t = (uInt)b & 0x3fff; +#ifndef PKZIP_BUG_WORKAROUND + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) + { + s->mode = BAD; + z->msg = (char*)"too many length or distance symbols"; + r = Z_DATA_ERROR; + LEAVE + } +#endif + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if ((s->sub.trees.blens = (uInt*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + DUMPBITS(14) + s->sub.trees.index = 0; + Tracev(("inflate: table sizes ok\n")); + s->mode = BTREE; + case BTREE: + while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) + { + NEEDBITS(3) + s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; + DUMPBITS(3) + } + while (s->sub.trees.index < 19) + s->sub.trees.blens[border[s->sub.trees.index++]] = 0; + s->sub.trees.bb = 7; + t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, + &s->sub.trees.tb, s->hufts, z); + if (t != Z_OK) + { + ZFREE(z, s->sub.trees.blens); + r = t; + if (r == Z_DATA_ERROR) + s->mode = BAD; + LEAVE + } + s->sub.trees.index = 0; + Tracev(("inflate: bits tree ok\n")); + s->mode = DTREE; + case DTREE: + while (t = s->sub.trees.table, + s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) + { + inflate_huft *h; + uInt i, j, c; + + t = s->sub.trees.bb; + NEEDBITS(t) + h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); + t = h->bits; + c = h->base; + if (c < 16) + { + DUMPBITS(t) + s->sub.trees.blens[s->sub.trees.index++] = c; + } + else /* c == 16..18 */ + { + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + NEEDBITS(t + i) + DUMPBITS(t) + j += (uInt)b & inflate_mask[i]; + DUMPBITS(i) + i = s->sub.trees.index; + t = s->sub.trees.table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)) + { + ZFREE(z, s->sub.trees.blens); + s->mode = BAD; + z->msg = (char*)"invalid bit length repeat"; + r = Z_DATA_ERROR; + LEAVE + } + c = c == 16 ? s->sub.trees.blens[i - 1] : 0; + do { + s->sub.trees.blens[i++] = c; + } while (--j); + s->sub.trees.index = i; + } + } + s->sub.trees.tb = Z_NULL; + { + uInt bl, bd; + inflate_huft *tl, *td; + inflate_codes_statef *c; + + bl = 9; /* must be <= 9 for lookahead assumptions */ + bd = 6; /* must be <= 9 for lookahead assumptions */ + t = s->sub.trees.table; + t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + s->sub.trees.blens, &bl, &bd, &tl, &td, + s->hufts, z); + ZFREE(z, s->sub.trees.blens); + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) + s->mode = BAD; + r = t; + LEAVE + } + Tracev(("inflate: trees ok\n")); + if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.codes = c; + } + s->mode = CODES; + case CODES: + UPDATE + if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) + return inflate_flush(s, z, r); + r = Z_OK; + inflate_codes_free(s->sub.decode.codes, z); + LOAD + Tracev(("inflate: codes end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + if (!s->last) + { + s->mode = TYPE; + break; + } + s->mode = DRY; + case DRY: + FLUSH + if (s->read != s->write) + LEAVE + s->mode = DONE; + case DONE: + r = Z_STREAM_END; + LEAVE + case BAD: + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +int inflate_blocks_free(inflate_blocks_statef *s, z_streamp z) +{ + inflate_blocks_reset(s, z, Z_NULL); + ZFREE(z, s->window); + ZFREE(z, s->hufts); + ZFREE(z, s); + Tracev(("inflate: blocks freed\n")); + return Z_OK; +} + + +void inflate_set_dictionary(inflate_blocks_statef *s, const Byte *d, uInt n) +{ + zmemcpy(s->window, d, n); + s->read = s->write = s->window + n; +} + + +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. + * IN assertion: s != Z_NULL + */ +int inflate_blocks_sync_point(inflate_blocks_statef *s) +{ + return s->mode == LENS; +} + +/* And'ing with mask[n] masks the lower n bits */ +uInt inflate_mask[17] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +/* copy as much as possible from the sliding window to the output area */ +int inflate_flush(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt n; + Byte *p; + Byte *q; + + /* static copies of source and destination pointers */ + p = z->next_out; + q = s->read; + + /* compute number of bytes to copy as as end of window */ + n = (uInt)((q <= s->write ? s->write : s->end) - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy as as end of window */ + zmemcpy(p, q, n); + p += n; + q += n; + + /* see if more to copy at beginning of window */ + if (q == s->end) + { + /* wrap pointers */ + q = s->window; + if (s->write == s->end) + s->write = s->window; + + /* compute bytes to copy */ + n = (uInt)(s->write - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy */ + zmemcpy(p, q, n); + p += n; + q += n; + } + + /* update pointers */ + z->next_out = p; + s->read = q; + + /* done */ + return r; +} + +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +const char inflate_copyright[] = + " inflate 1.1.3 Copyright 1995-1998 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + + +static int huft_build OF(( + uInt *, /* code lengths in bits */ + uInt, /* number of codes */ + uInt, /* number of "simple" codes */ + const uInt *, /* list of base values for non-simple codes */ + const uInt *, /* list of extra bits for non-simple codes */ + inflate_huft **, /* result: starting table */ + uInt *, /* maximum lookup bits (returns actual) */ + inflate_huft *, /* space for trees */ + uInt *, /* hufts used in space */ + uInt * )); /* space for values */ + +/* Tables for deflate from PKZIP's appnote.txt. */ +static const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* see note #13 above about 258 */ +static const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ +static const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +static const uInt cpdext[30] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ +#define BMAX 15 /* maximum bit length of any code */ + +static int huft_build(uInt *b, uInt n, uInt s, const uInt *d, const uInt *e, inflate_huft ** t, uInt *m, inflate_huft *hp, uInt *hn, uInt *v) +//uInt *b; /* code lengths in bits (all assumed <= BMAX) */ +//uInt n; /* number of codes (assumed <= 288) */ +//uInt s; /* number of simple-valued codes (0..s-1) */ +//const uInt *d; /* list of base values for non-simple codes */ +//const uInt *e; /* list of extra bits for non-simple codes */ +//inflate_huft ** t; /* result: starting table */ +//uInt *m; /* maximum lookup bits, returns actual */ +//inflate_huft *hp; /* space for trees */ +//uInt *hn; /* hufts used in space */ +//uInt *v; /* working area: values in order of bit length */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + if the given code set is incomplete (the tables are still built in this + case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of + lengths), or Z_MEM_ERROR if not enough memory. */ +{ + + uInt a; /* counter for codes of length k */ + uInt c[BMAX+1]; /* bit length count table */ + uInt f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register uInt i; /* counter, current code */ + register uInt j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */ + register uInt *p; /* pointer into c[], b[], or v[] */ + inflate_huft *q; /* points to current table */ + struct inflate_huft_s r; /* table entry for structure assignment */ + inflate_huft *u[BMAX]; /* table stack */ + register int w; /* bits before this table == (l * h) */ + uInt x[BMAX+1]; /* bit offsets, then code stack */ + uInt *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + uInt z; /* number of entries in current table */ + + + /* Generate counts for each bit length */ + p = c; +#define C0 *p++ = 0; +#define C2 C0 C0 C0 C0 +#define C4 C2 C2 C2 C2 + C4 /* clear c[]--assume BMAX+1 is 16 */ + p = b; i = n; + do { + c[*p++]++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (inflate_huft *)Z_NULL; + *m = 0; + return Z_OK; + } + + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((uInt)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((uInt)l > i) + l = i; + *m = l; + + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return Z_DATA_ERROR; + if ((y -= c[i]) < 0) + return Z_DATA_ERROR; + c[i] += y; + + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + n = x[g]; /* set n to length of v */ + + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ + q = (inflate_huft *)Z_NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = g - w; + z = z > (uInt)l ? l : z; /* table size upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + if (j < z) + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate new table */ + if (*hn + z > MANY) /* (note: doesn't matter for fixed) */ + return Z_MEM_ERROR; /* not enough memory */ + u[h] = q = hp + *hn; + *hn += z; + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.bits = (Byte)l; /* bits to dump before this table */ + r.exop = (Byte)j; /* bits in this table */ + j = i >> (w - l); + r.base = (uInt)(q - u[h-1] - j); /* offset to this table */ + u[h-1][j] = r; /* connect to last table */ + } + else + *t = q; /* first table is returned result */ + } + + /* set up table entry in r */ + r.bits = (Byte)(k - w); + if (p >= v + n) + r.exop = 128 + 64; /* out of values--invalid code */ + else if (*p < s) + { + r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ + r.base = *p++; /* simple code is just the value */ + } + else + { + r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ + r.base = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + mask = (1 << w) - 1; /* needed on HP, cc -O bug */ + while ((i & mask) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + mask = (1 << w) - 1; + } + } + } + + + /* Return Z_BUF_ERROR if we were given an incomplete table */ + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; +} + + +int inflate_trees_bits(uInt *c, uInt *bb, inflate_huft * *tb, inflate_huft *hp, z_streamp z) +//uInt *c; /* 19 code lengths */ +//uInt *bb; /* bits tree desired/actual depth */ +//inflate_huft * *tb; /* bits tree result */ +//inflate_huft *hp; /* space for trees */ +//z_streamp z; /* for messages */ +{ + int r; + uInt hn = 0; /* hufts used in space */ + uInt *v; /* work area for huft_build */ + + if ((v = (uInt*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + r = huft_build(c, 19, 19, (uInt*)Z_NULL, (uInt*)Z_NULL, + tb, bb, hp, &hn, v); + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed dynamic bit lengths tree"; + else if (r == Z_BUF_ERROR || *bb == 0) + { + z->msg = (char*)"incomplete dynamic bit lengths tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +} + + +int inflate_trees_dynamic(uInt nl, uInt nd, uInt *c, uInt *bl, uInt *bd, inflate_huft * *tl, inflate_huft * *td, inflate_huft *hp, z_streamp z) +//uInt nl; /* number of literal/length codes */ +//uInt nd; /* number of distance codes */ +//uInt *c; /* that many (total) code lengths */ +//uInt *bl; /* literal desired/actual bit depth */ +//uInt *bd; /* distance desired/actual bit depth */ +//inflate_huft * *tl; /* literal/length tree result */ +//inflate_huft * *td; /* distance tree result */ +//inflate_huft *hp; /* space for trees */ +//z_streamp z; /* for messages */ +{ + int r; + uInt hn = 0; /* hufts used in space */ + uInt *v; /* work area for huft_build */ + + /* allocate work area */ + if ((v = (uInt*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + + /* build literal/length tree */ + r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); + if (r != Z_OK || *bl == 0) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed literal/length tree"; + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; + } + + /* build distance tree */ + r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); + if (r != Z_OK || (*bd == 0 && nl > 257)) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed distance tree"; + else if (r == Z_BUF_ERROR) { +#ifdef PKZIP_BUG_WORKAROUND + r = Z_OK; + } +#else + z->msg = (char*)"incomplete distance tree"; + r = Z_DATA_ERROR; + } + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"empty distance tree with lengths"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +#endif + } + + /* done */ + ZFREE(z, v); + return Z_OK; +} + +/* inffixed.h -- table for decoding fixed codes + * Generated automatically by the maketree.c program + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +static uInt fixed_bl = 9; +static uInt fixed_bd = 5; +static inflate_huft fixed_tl[] = { + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} + }; +static inflate_huft fixed_td[] = { + {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, + {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, + {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, + {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, + {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, + {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, + {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, + {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} + }; + +int inflate_trees_fixed(uInt *bl, uInt *bd, inflate_huft * *tl, inflate_huft * *td, z_streamp z) +//uInt *bl; /* literal desired/actual bit depth */ +//uInt *bd; /* distance desired/actual bit depth */ +//inflate_huft * *tl; /* literal/length tree result */ +//inflate_huft * *td; /* distance tree result */ +//z_streamp z; /* for memory allocation */ +{ + *bl = fixed_bl; + *bd = fixed_bd; + *tl = fixed_tl; + *td = fixed_td; + return Z_OK; +} + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* macros for bit input with no checking and for returning unused bytes */ +#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;} + +/* Called with number of bytes left to write in window at least 258 + (the maximum string length) and number of input bytes available + at least ten. The ten bytes are six bytes for the longest length/ + distance pair plus four bytes for overloading the bit buffer. */ + +int inflate_fast(uInt bl, uInt bd, inflate_huft *tl, inflate_huft *td, inflate_blocks_statef *s, z_streamp z) +{ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Byte *p; /* input data pointer */ + uInt n; /* bytes available there */ + Byte *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + uInt ml; /* mask for literal/length tree */ + uInt md; /* mask for distance tree */ + uInt c; /* bytes to copy */ + uInt d; /* distance back to copy from */ + Byte *r; /* copy source pointer */ + + /* load input, output, bit values */ + LOAD + + /* initialize masks */ + ml = inflate_mask[bl]; + md = inflate_mask[bd]; + + /* do until not enough input or output space for fast loop */ + do { /* assume called with m >= 258 && n >= 10 */ + /* get literal/length code */ + GRABBITS(20) /* max bits for literal/length code */ + if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + continue; + } + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits for length */ + e &= 15; + c = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv(("inflate: * length %u\n", c)); + + /* decode distance base of block to copy */ + GRABBITS(15); /* max bits for distance code */ + e = (t = td + ((uInt)b & md))->exop; + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits to add to distance base */ + e &= 15; + GRABBITS(e) /* get extra bits (up to 13) */ + d = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv(("inflate: * distance %u\n", d)); + + /* do the copy */ + m -= c; + if ((uInt)(q - s->window) >= d) /* offset before dest */ + { /* just copy */ + r = q - d; + *q++ = *r++; c--; /* minimum count is three, */ + *q++ = *r++; c--; /* so unroll loop a little */ + } + else /* else offset after destination */ + { + e = d - (uInt)(q - s->window); /* bytes from offset to end */ + r = s->end - e; /* pointer to offset */ + if (c > e) /* if source crosses, */ + { + c -= e; /* copy to end of window */ + do { + *q++ = *r++; + } while (--e); + r = s->window; /* copy rest from start of window */ + } + } + do { /* copy all or what's left */ + *q++ = *r++; + } while (--c); + break; + } + else if ((e & 64) == 0) + { + t += t->base; + e = (t += ((uInt)b & inflate_mask[e]))->exop; + } + else + { + z->msg = (char*)"invalid distance code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + break; + } + if ((e & 64) == 0) + { + t += t->base; + if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + break; + } + } + else if (e & 32) + { + Tracevv(("inflate: * end of block\n")); + UNGRAB + UPDATE + return Z_STREAM_END; + } + else + { + z->msg = (char*)"invalid literal/length code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + } while (m >= 258 && n >= 10); + + /* not enough input or output--restore pointers and return */ + UNGRAB + UPDATE + return Z_OK; +} + +/* infcodes.c -- process literals and length/distance pairs + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + START, /* x: set up for LEN */ + LEN, /* i: get length/literal/eob next */ + LENEXT, /* i: getting length extra (have base) */ + DIST, /* i: get distance next */ + DISTEXT, /* i: getting distance extra */ + COPY, /* o: copying bytes in window, waiting for space */ + LIT, /* o: got literal, waiting for output space */ + WASH, /* o: got eob, possibly still output waiting */ + END, /* x: got eob and all data flushed */ + BADCODE} /* x: got error */ +inflate_codes_mode; + +/* inflate codes private state */ +struct inflate_codes_state { + + /* mode */ + inflate_codes_mode mode; /* current inflate_codes mode */ + + /* mode dependent information */ + uInt len; + union { + struct { + inflate_huft *tree; /* pointer into tree */ + uInt need; /* bits needed */ + } code; /* if LEN or DIST, where in tree */ + uInt lit; /* if LIT, literal */ + struct { + uInt get; /* bits to get for extra */ + uInt dist; /* distance back to copy from */ + } copy; /* if EXT or COPY, where and how much */ + } sub; /* submode */ + + /* mode independent information */ + Byte lbits; /* ltree bits decoded per branch */ + Byte dbits; /* dtree bits decoder per branch */ + inflate_huft *ltree; /* literal/length/eob tree */ + inflate_huft *dtree; /* distance tree */ + +}; + + +inflate_codes_statef *inflate_codes_new(uInt bl, uInt bd, inflate_huft *tl, inflate_huft *td, z_streamp z) +{ + inflate_codes_statef *c; + + if ((c = (inflate_codes_statef *) + ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) + { + c->mode = START; + c->lbits = (Byte)bl; + c->dbits = (Byte)bd; + c->ltree = tl; + c->dtree = td; + Tracev(("inflate: codes new\n")); + } + return c; +} + + +int inflate_codes(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt j; /* temporary storage */ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Byte *p; /* input data pointer */ + uInt n; /* bytes available there */ + Byte *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + Byte *f; /* pointer to copy strings from */ + inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input and output based on current state */ + while (1) switch (c->mode) + { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + case START: /* x: set up for LEN */ +#ifndef SLOW + if (m >= 258 && n >= 10) + { + UPDATE + r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); + LOAD + if (r != Z_OK) + { + c->mode = r == Z_STREAM_END ? WASH : BADCODE; + break; + } + } +#endif /* !SLOW */ + c->sub.code.need = c->lbits; + c->sub.code.tree = c->ltree; + c->mode = LEN; + case LEN: /* i: get length/literal/eob next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e == 0) /* literal */ + { + c->sub.lit = t->base; + Tracevv((t->base >= 0x20 && t->base < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", t->base)); + c->mode = LIT; + break; + } + if (e & 16) /* length */ + { + c->sub.copy.get = e & 15; + c->len = t->base; + c->mode = LENEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + if (e & 32) /* end of block */ + { + Tracevv(("inflate: end of block\n")); + c->mode = WASH; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid literal/length code"; + r = Z_DATA_ERROR; + LEAVE + case LENEXT: /* i: getting length extra (have base) */ + j = c->sub.copy.get; + NEEDBITS(j) + c->len += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + c->sub.code.need = c->dbits; + c->sub.code.tree = c->dtree; + Tracevv(("inflate: length %u\n", c->len)); + c->mode = DIST; + case DIST: /* i: get distance next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e & 16) /* distance */ + { + c->sub.copy.get = e & 15; + c->sub.copy.dist = t->base; + c->mode = DISTEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid distance code"; + r = Z_DATA_ERROR; + LEAVE + case DISTEXT: /* i: getting distance extra */ + j = c->sub.copy.get; + NEEDBITS(j) + c->sub.copy.dist += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + Tracevv(("inflate: distance %u\n", c->sub.copy.dist)); + c->mode = COPY; + case COPY: /* o: copying bytes in window, waiting for space */ +#ifndef __TURBOC__ /* Turbo C bug for following expression */ + f = (uInt)(q - s->window) < c->sub.copy.dist ? + s->end - (c->sub.copy.dist - (q - s->window)) : + q - c->sub.copy.dist; +#else + f = q - c->sub.copy.dist; + if ((uInt)(q - s->window) < c->sub.copy.dist) + f = s->end - (c->sub.copy.dist - (uInt)(q - s->window)); +#endif + while (c->len) + { + NEEDOUT + OUTBYTE(*f++) + if (f == s->end) + f = s->window; + c->len--; + } + c->mode = START; + break; + case LIT: /* o: got literal, waiting for output space */ + NEEDOUT + OUTBYTE(c->sub.lit) + c->mode = START; + break; + case WASH: /* o: got eob, possibly more output */ + if (k > 7) /* return unused byte, if any */ + { + Assert(k < 16, "inflate_codes grabbed too many bytes") + k -= 8; + n++; + p--; /* can always return one */ + } + FLUSH + if (s->read != s->write) + LEAVE + c->mode = END; + case END: + r = Z_STREAM_END; + LEAVE + case BADCODE: /* x: got error */ + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} + + +void inflate_codes_free(inflate_codes_statef *c, z_streamp z) +{ + ZFREE(z, c); + Tracev(("inflate: codes free\n")); +} + +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#define BASE 65521L /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#undef DO1 +#undef DO2 +#undef DO4 +#undef DO8 + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* ========================================================================= */ +uLong adler32(uLong adler, const Byte *buf, uInt len) +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} + +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +extern inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +extern int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +extern void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLong *)); /* check value on output */ + +extern int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp)); + +extern void inflate_set_dictionary OF(( + inflate_blocks_statef *s, + const Byte *d, /* dictionary */ + uInt n)); /* dictionary length */ + +extern int inflate_blocks_sync_point OF(( + inflate_blocks_statef *s)); + +typedef enum { + imMETHOD, /* waiting for method byte */ + imFLAG, /* waiting for flag byte */ + imDICT4, /* four dictionary check bytes to go */ + imDICT3, /* three dictionary check bytes to go */ + imDICT2, /* two dictionary check bytes to go */ + imDICT1, /* one dictionary check byte to go */ + imDICT0, /* waiting for inflateSetDictionary */ + imBLOCKS, /* decompressing blocks */ + imCHECK4, /* four check bytes to go */ + imCHECK3, /* three check bytes to go */ + imCHECK2, /* two check bytes to go */ + imCHECK1, /* one check byte to go */ + imDONE, /* finished check, done */ + imBAD} /* got an error--stay here */ +inflate_mode; + +/* inflate private state */ +struct internal_state { + + /* mode */ + inflate_mode mode; /* current inflate mode */ + + /* mode dependent information */ + union { + uInt method; /* if FLAGS, method byte */ + struct { + uLong was; /* computed check value */ + uLong need; /* stream check value */ + } check; /* if CHECK, check values to compare */ + uInt marker; /* if BAD, inflateSync's marker bytes count */ + } sub; /* submode */ + + /* mode independent information */ + int nowrap; /* flag for no wrapper */ + uInt wbits; /* log2(window size) (8..15, defaults to 15) */ + inflate_blocks_statef + *blocks; /* current inflate_blocks state */ + +}; + + +int inflateReset(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + z->total_in = z->total_out = 0; + z->msg = Z_NULL; + z->state->mode = z->state->nowrap ? imBLOCKS : imMETHOD; + inflate_blocks_reset(z->state->blocks, z, Z_NULL); + Tracev(("inflate: reset\n")); + return Z_OK; +} + + +int inflateEnd(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->blocks != Z_NULL) + inflate_blocks_free(z->state->blocks, z); + ZFREE(z, z->state); + z->state = Z_NULL; + Tracev(("inflate: end\n")); + return Z_OK; +} + + + +int inflateInit2_(z_streamp z, int w, const char *version, int stream_size) +{ + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != sizeof(z_stream)) + return Z_VERSION_ERROR; + + /* initialize state */ + if (z == Z_NULL) + return Z_STREAM_ERROR; + z->msg = Z_NULL; + if (z->zalloc == Z_NULL) + { + z->zalloc = (void *(*)(void *, unsigned, unsigned))zcalloc; + z->opaque = (voidp)0; + } + if (z->zfree == Z_NULL) z->zfree = (void (*)(void *, void *))zcfree; + if ((z->state = (struct internal_state *) + ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) + return Z_MEM_ERROR; + z->state->blocks = Z_NULL; + + /* handle undocumented nowrap option (no zlib header or check) */ + z->state->nowrap = 0; + if (w < 0) + { + w = - w; + z->state->nowrap = 1; + } + + /* set window size */ + if (w < 8 || w > 15) + { + inflateEnd(z); + return Z_STREAM_ERROR; + } + z->state->wbits = (uInt)w; + + /* create inflate_blocks state */ + if ((z->state->blocks = + inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) + == Z_NULL) + { + inflateEnd(z); + return Z_MEM_ERROR; + } + Tracev(("inflate: allocated\n")); + + /* reset state */ + inflateReset(z); + return Z_OK; +} + + +int inflateInit_(z_streamp z, const char *version, int stream_size) +{ + return inflateInit2_(z, DEF_WBITS, version, stream_size); +} + + +#define iNEEDBYTE {if(z->avail_in==0)return r;r=f;} +#define iNEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) + +int inflate(z_streamp z, int f) +{ + int r; + uInt b; + + if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) + return Z_STREAM_ERROR; + f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; + r = Z_BUF_ERROR; + while (1) switch (z->state->mode) + { + case imMETHOD: + iNEEDBYTE + if (((z->state->sub.method = iNEXTBYTE) & 0xf) != Z_DEFLATED) + { + z->state->mode = imBAD; + z->msg = (char*)"unknown compression method"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + if ((z->state->sub.method >> 4) + 8 > z->state->wbits) + { + z->state->mode = imBAD; + z->msg = (char*)"invalid window size"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + z->state->mode = imFLAG; + case imFLAG: + iNEEDBYTE + b = iNEXTBYTE; + if (((z->state->sub.method << 8) + b) % 31) + { + z->state->mode = imBAD; + z->msg = (char*)"incorrect header check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev(("inflate: zlib header ok\n")); + if (!(b & PRESET_DICT)) + { + z->state->mode = imBLOCKS; + break; + } + z->state->mode = imDICT4; + case imDICT4: + iNEEDBYTE + z->state->sub.check.need = (uLong)iNEXTBYTE << 24; + z->state->mode = imDICT3; + case imDICT3: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 16; + z->state->mode = imDICT2; + case imDICT2: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 8; + z->state->mode = imDICT1; + case imDICT1: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE; + z->adler = z->state->sub.check.need; + z->state->mode = imDICT0; + return Z_NEED_DICT; + case imDICT0: + z->state->mode = imBAD; + z->msg = (char*)"need dictionary"; + z->state->sub.marker = 0; /* can try inflateSync */ + return Z_STREAM_ERROR; + case imBLOCKS: + r = inflate_blocks(z->state->blocks, z, r); + if (r == Z_DATA_ERROR) + { + z->state->mode = imBAD; + z->state->sub.marker = 0; /* can try inflateSync */ + break; + } + if (r == Z_OK) + r = f; + if (r != Z_STREAM_END) + return r; + r = f; + inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); + if (z->state->nowrap) + { + z->state->mode = imDONE; + break; + } + z->state->mode = imCHECK4; + case imCHECK4: + iNEEDBYTE + z->state->sub.check.need = (uLong)iNEXTBYTE << 24; + z->state->mode = imCHECK3; + case imCHECK3: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 16; + z->state->mode = imCHECK2; + case imCHECK2: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 8; + z->state->mode = imCHECK1; + case imCHECK1: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE; + + if (z->state->sub.check.was != z->state->sub.check.need) + { + z->state->mode = imBAD; + z->msg = (char*)"incorrect data check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev(("inflate: zlib check ok\n")); + z->state->mode = imDONE; + case imDONE: + return Z_STREAM_END; + case imBAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} + + +int inflateSetDictionary(z_streamp z, const Byte *dictionary, uInt dictLength) +{ + uInt length = dictLength; + + if (z == Z_NULL || z->state == Z_NULL || z->state->mode != imDICT0) + return Z_STREAM_ERROR; + + if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; + z->adler = 1L; + + if (length >= ((uInt)1<state->wbits)) + { + length = (1<state->wbits)-1; + dictionary += dictLength - length; + } + inflate_set_dictionary(z->state->blocks, dictionary, length); + z->state->mode = imBLOCKS; + return Z_OK; +} + + +int inflateSync(z_streamp z) +{ + uInt n; /* number of bytes to look at */ + Byte *p; /* pointer to bytes */ + uInt m; /* number of marker bytes found in a row */ + uLong r, w; /* temporaries to save total_in and total_out */ + + /* set up */ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->mode != imBAD) + { + z->state->mode = imBAD; + z->state->sub.marker = 0; + } + if ((n = z->avail_in) == 0) + return Z_BUF_ERROR; + p = z->next_in; + m = z->state->sub.marker; + + /* search */ + while (n && m < 4) + { + static const Byte mark[4] = {0, 0, 0xff, 0xff}; + if (*p == mark[m]) + m++; + else if (*p) + m = 0; + else + m = 4 - m; + p++, n--; + } + + /* restore */ + z->total_in += p - z->next_in; + z->next_in = p; + z->avail_in = n; + z->state->sub.marker = m; + + /* return no joy or set up to restart on a new block */ + if (m != 4) + return Z_DATA_ERROR; + r = z->total_in; w = z->total_out; + inflateReset(z); + z->total_in = r; z->total_out = w; + z->state->mode = imBLOCKS; + return Z_OK; +} + + +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH + * but removes the length bytes of the resulting empty stored block. When + * decompressing, PPP checks that at the end of input packet, inflate is + * waiting for these length bytes. + */ +int inflateSyncPoint(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL) + return Z_STREAM_ERROR; + return inflate_blocks_sync_point(z->state->blocks); +} + +voidp zcalloc (voidp opaque, unsigned items, unsigned size) +{ + if (opaque) items += size - size; /* make compiler happy */ + return (voidp)malloc(items*size); +} + +void zcfree (voidp opaque, voidp ptr) +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + diff --git a/libs/splines/math_angles.cpp b/libs/splines/math_angles.cpp index 1c75fa55..153f5436 100644 --- a/libs/splines/math_angles.cpp +++ b/libs/splines/math_angles.cpp @@ -1,150 +1,150 @@ -/* -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 -*/ - -#include "q_shared.h" -#include - -angles_t ang_zero( 0.0f, 0.0f, 0.0f ); - -void toAngles( mat3_t &src, angles_t &dst ) { - double theta; - double cp; - double sp; - - sp = src[ 0 ][ 2 ]; - - // cap off our sin value so that we don't get any NANs - if ( sp > 1.0 ) { - sp = 1.0; - } else if ( sp < -1.0 ) { - sp = -1.0; - } - - theta = -asin( sp ); - cp = cos( theta ); - - if ( cp > 8192 * FLT_EPSILON ) { - dst.pitch = theta * 180 / M_PI; - dst.yaw = atan2( src[ 0 ][ 1 ], src[ 0 ][ 0 ] ) * 180 / M_PI; - dst.roll = atan2( src[ 1 ][ 2 ], src[ 2 ][ 2 ] ) * 180 / M_PI; - } else { - dst.pitch = theta * 180 / M_PI; - dst.yaw = -atan2( src[ 1 ][ 0 ], src[ 1 ][ 1 ] ) * 180 / M_PI; - dst.roll = 0; - } -} - -void toAngles( quat_t &src, angles_t &dst ) { - mat3_t temp; - - toMatrix( src, temp ); - toAngles( temp, dst ); -} - -void toAngles( idVec3 &src, angles_t &dst ) { - dst.pitch = src[ 0 ]; - dst.yaw = src[ 1 ]; - dst.roll = src[ 2 ]; -} - -void angles_t::toVectors( idVec3 *forward, idVec3 *right, idVec3 *up ) { - float angle; - static float sr, sp, sy, cr, cp, cy; // static to help MS compiler fp bugs - - angle = yaw * ( M_PI * 2 / 360 ); - sy = sin( angle ); - cy = cos( angle ); - - angle = pitch * ( M_PI * 2 / 360 ); - sp = sin( angle ); - cp = cos( angle ); - - angle = roll * ( M_PI * 2 / 360 ); - sr = sin( angle ); - cr = cos( angle ); - - if ( forward ) { - forward->set( cp * cy, cp * sy, -sp ); - } - - if ( right ) { - right->set( -sr * sp * cy + cr * sy, -sr * sp * sy + -cr * cy, -sr * cp ); - } - - if ( up ) { - up->set( cr * sp * cy + -sr * -sy, cr * sp * sy + -sr * cy, cr * cp ); - } -} - -idVec3 angles_t::toForward( void ) { - float angle; - static float sp, sy, cp, cy; // static to help MS compiler fp bugs - - angle = yaw * ( M_PI * 2 / 360 ); - sy = sin( angle ); - cy = cos( angle ); - - angle = pitch * ( M_PI * 2 / 360 ); - sp = sin( angle ); - cp = cos( angle ); - - return idVec3( cp * cy, cp * sy, -sp ); -} - -/* -================= -Normalize360 - -returns angles normalized to the range [0 <= angle < 360] -================= -*/ -angles_t& angles_t::Normalize360( void ) { - pitch = (360.0 / 65536) * ( ( int )( pitch * ( 65536 / 360.0 ) ) & 65535 ); - yaw = (360.0 / 65536) * ( ( int )( yaw * ( 65536 / 360.0 ) ) & 65535 ); - roll = (360.0 / 65536) * ( ( int )( roll * ( 65536 / 360.0 ) ) & 65535 ); - - return *this; -} - - -/* -================= -Normalize180 - -returns angles normalized to the range [-180 < angle <= 180] -================= -*/ -angles_t& angles_t::Normalize180( void ) { - Normalize360(); - - if ( pitch > 180.0 ) { - pitch -= 360.0; - } - - if ( yaw > 180.0 ) { - yaw -= 360.0; - } - - if ( roll > 180.0 ) { - roll -= 360.0; - } - return *this; -} +/* +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 +*/ + +#include "q_shared.h" +#include + +angles_t ang_zero( 0.0f, 0.0f, 0.0f ); + +void toAngles( mat3_t &src, angles_t &dst ) { + double theta; + double cp; + double sp; + + sp = src[ 0 ][ 2 ]; + + // cap off our sin value so that we don't get any NANs + if ( sp > 1.0 ) { + sp = 1.0; + } else if ( sp < -1.0 ) { + sp = -1.0; + } + + theta = -asin( sp ); + cp = cos( theta ); + + if ( cp > 8192 * FLT_EPSILON ) { + dst.pitch = theta * 180 / M_PI; + dst.yaw = atan2( src[ 0 ][ 1 ], src[ 0 ][ 0 ] ) * 180 / M_PI; + dst.roll = atan2( src[ 1 ][ 2 ], src[ 2 ][ 2 ] ) * 180 / M_PI; + } else { + dst.pitch = theta * 180 / M_PI; + dst.yaw = -atan2( src[ 1 ][ 0 ], src[ 1 ][ 1 ] ) * 180 / M_PI; + dst.roll = 0; + } +} + +void toAngles( quat_t &src, angles_t &dst ) { + mat3_t temp; + + toMatrix( src, temp ); + toAngles( temp, dst ); +} + +void toAngles( idVec3 &src, angles_t &dst ) { + dst.pitch = src[ 0 ]; + dst.yaw = src[ 1 ]; + dst.roll = src[ 2 ]; +} + +void angles_t::toVectors( idVec3 *forward, idVec3 *right, idVec3 *up ) { + float angle; + static float sr, sp, sy, cr, cp, cy; // static to help MS compiler fp bugs + + angle = yaw * ( M_PI * 2 / 360 ); + sy = sin( angle ); + cy = cos( angle ); + + angle = pitch * ( M_PI * 2 / 360 ); + sp = sin( angle ); + cp = cos( angle ); + + angle = roll * ( M_PI * 2 / 360 ); + sr = sin( angle ); + cr = cos( angle ); + + if ( forward ) { + forward->set( cp * cy, cp * sy, -sp ); + } + + if ( right ) { + right->set( -sr * sp * cy + cr * sy, -sr * sp * sy + -cr * cy, -sr * cp ); + } + + if ( up ) { + up->set( cr * sp * cy + -sr * -sy, cr * sp * sy + -sr * cy, cr * cp ); + } +} + +idVec3 angles_t::toForward( void ) { + float angle; + static float sp, sy, cp, cy; // static to help MS compiler fp bugs + + angle = yaw * ( M_PI * 2 / 360 ); + sy = sin( angle ); + cy = cos( angle ); + + angle = pitch * ( M_PI * 2 / 360 ); + sp = sin( angle ); + cp = cos( angle ); + + return idVec3( cp * cy, cp * sy, -sp ); +} + +/* +================= +Normalize360 + +returns angles normalized to the range [0 <= angle < 360] +================= +*/ +angles_t& angles_t::Normalize360( void ) { + pitch = (360.0 / 65536) * ( ( int )( pitch * ( 65536 / 360.0 ) ) & 65535 ); + yaw = (360.0 / 65536) * ( ( int )( yaw * ( 65536 / 360.0 ) ) & 65535 ); + roll = (360.0 / 65536) * ( ( int )( roll * ( 65536 / 360.0 ) ) & 65535 ); + + return *this; +} + + +/* +================= +Normalize180 + +returns angles normalized to the range [-180 < angle <= 180] +================= +*/ +angles_t& angles_t::Normalize180( void ) { + Normalize360(); + + if ( pitch > 180.0 ) { + pitch -= 360.0; + } + + if ( yaw > 180.0 ) { + yaw -= 360.0; + } + + if ( roll > 180.0 ) { + roll -= 360.0; + } + return *this; +} diff --git a/libs/splines/math_matrix.cpp b/libs/splines/math_matrix.cpp index e357c87e..f725fcf1 100644 --- a/libs/splines/math_matrix.cpp +++ b/libs/splines/math_matrix.cpp @@ -1,134 +1,134 @@ -/* -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 -*/ - -#include "q_shared.h" - -mat3_t mat3_default( idVec3( 1, 0, 0 ), idVec3( 0, 1, 0 ), idVec3( 0, 0, 1 ) ); - -void toMatrix( quat_t const &src, mat3_t &dst ) { - float wx, wy, wz; - float xx, yy, yz; - float xy, xz, zz; - float x2, y2, z2; - - x2 = src.x + src.x; - y2 = src.y + src.y; - z2 = src.z + src.z; - - xx = src.x * x2; - xy = src.x * y2; - xz = src.x * z2; - - yy = src.y * y2; - yz = src.y * z2; - zz = src.z * z2; - - wx = src.w * x2; - wy = src.w * y2; - wz = src.w * z2; - - dst[ 0 ][ 0 ] = 1.0f - ( yy + zz ); - dst[ 0 ][ 1 ] = xy - wz; - dst[ 0 ][ 2 ] = xz + wy; - - dst[ 1 ][ 0 ] = xy + wz; - dst[ 1 ][ 1 ] = 1.0f - ( xx + zz ); - dst[ 1 ][ 2 ] = yz - wx; - - dst[ 2 ][ 0 ] = xz - wy; - dst[ 2 ][ 1 ] = yz + wx; - dst[ 2 ][ 2 ] = 1.0f - ( xx + yy ); -} - -void toMatrix( angles_t const &src, mat3_t &dst ) { - float angle; - static float sr, sp, sy, cr, cp, cy; // static to help MS compiler fp bugs - - angle = src.yaw * ( M_PI * 2.0f / 360.0f ); - sy = sin( angle ); - cy = cos( angle ); - - angle = src.pitch * ( M_PI * 2.0f / 360.0f ); - sp = sin( angle ); - cp = cos( angle ); - - angle = src.roll * ( M_PI * 2.0f / 360.0f ); - sr = sin( angle ); - cr = cos( angle ); - - dst[ 0 ].set( cp * cy, cp * sy, -sp ); - dst[ 1 ].set( sr * sp * cy + cr * -sy, sr * sp * sy + cr * cy, sr * cp ); - dst[ 2 ].set( cr * sp * cy + -sr * -sy, cr * sp * sy + -sr * cy, cr * cp ); -} - -void toMatrix( idVec3 const &src, mat3_t &dst ) { - angles_t sup = src; - toMatrix(sup, dst); -} - -void mat3_t::ProjectVector( const idVec3 &src, idVec3 &dst ) const { - dst.x = src * mat[ 0 ]; - dst.y = src * mat[ 1 ]; - dst.z = src * mat[ 2 ]; -} - -void mat3_t::UnprojectVector( const idVec3 &src, idVec3 &dst ) const { - dst = mat[ 0 ] * src.x + mat[ 1 ] * src.y + mat[ 2 ] * src.z; -} - -void mat3_t::Transpose( mat3_t &matrix ) { - int i; - int j; - - for( i = 0; i < 3; i++ ) { - for( j = 0; j < 3; j++ ) { - matrix[ i ][ j ] = mat[ j ][ i ]; - } - } -} - -void mat3_t::Transpose( void ) { - float temp; - int i; - int j; - - for( i = 0; i < 3; i++ ) { - for( j = i + 1; j < 3; j++ ) { - temp = mat[ i ][ j ]; - mat[ i ][ j ] = mat[ j ][ i ]; - mat[ j ][ i ] = temp; - } - } -} - -mat3_t mat3_t::Inverse( void ) const { - mat3_t inv( *this ); - - inv.Transpose(); - - return inv; -} - -void mat3_t::Clear( void ) { - mat[0].set( 1, 0, 0 ); - mat[1].set( 0, 1, 0 ); - mat[2].set( 0, 0, 1 ); -} +/* +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 +*/ + +#include "q_shared.h" + +mat3_t mat3_default( idVec3( 1, 0, 0 ), idVec3( 0, 1, 0 ), idVec3( 0, 0, 1 ) ); + +void toMatrix( quat_t const &src, mat3_t &dst ) { + float wx, wy, wz; + float xx, yy, yz; + float xy, xz, zz; + float x2, y2, z2; + + x2 = src.x + src.x; + y2 = src.y + src.y; + z2 = src.z + src.z; + + xx = src.x * x2; + xy = src.x * y2; + xz = src.x * z2; + + yy = src.y * y2; + yz = src.y * z2; + zz = src.z * z2; + + wx = src.w * x2; + wy = src.w * y2; + wz = src.w * z2; + + dst[ 0 ][ 0 ] = 1.0f - ( yy + zz ); + dst[ 0 ][ 1 ] = xy - wz; + dst[ 0 ][ 2 ] = xz + wy; + + dst[ 1 ][ 0 ] = xy + wz; + dst[ 1 ][ 1 ] = 1.0f - ( xx + zz ); + dst[ 1 ][ 2 ] = yz - wx; + + dst[ 2 ][ 0 ] = xz - wy; + dst[ 2 ][ 1 ] = yz + wx; + dst[ 2 ][ 2 ] = 1.0f - ( xx + yy ); +} + +void toMatrix( angles_t const &src, mat3_t &dst ) { + float angle; + static float sr, sp, sy, cr, cp, cy; // static to help MS compiler fp bugs + + angle = src.yaw * ( M_PI * 2.0f / 360.0f ); + sy = sin( angle ); + cy = cos( angle ); + + angle = src.pitch * ( M_PI * 2.0f / 360.0f ); + sp = sin( angle ); + cp = cos( angle ); + + angle = src.roll * ( M_PI * 2.0f / 360.0f ); + sr = sin( angle ); + cr = cos( angle ); + + dst[ 0 ].set( cp * cy, cp * sy, -sp ); + dst[ 1 ].set( sr * sp * cy + cr * -sy, sr * sp * sy + cr * cy, sr * cp ); + dst[ 2 ].set( cr * sp * cy + -sr * -sy, cr * sp * sy + -sr * cy, cr * cp ); +} + +void toMatrix( idVec3 const &src, mat3_t &dst ) { + angles_t sup = src; + toMatrix(sup, dst); +} + +void mat3_t::ProjectVector( const idVec3 &src, idVec3 &dst ) const { + dst.x = src * mat[ 0 ]; + dst.y = src * mat[ 1 ]; + dst.z = src * mat[ 2 ]; +} + +void mat3_t::UnprojectVector( const idVec3 &src, idVec3 &dst ) const { + dst = mat[ 0 ] * src.x + mat[ 1 ] * src.y + mat[ 2 ] * src.z; +} + +void mat3_t::Transpose( mat3_t &matrix ) { + int i; + int j; + + for( i = 0; i < 3; i++ ) { + for( j = 0; j < 3; j++ ) { + matrix[ i ][ j ] = mat[ j ][ i ]; + } + } +} + +void mat3_t::Transpose( void ) { + float temp; + int i; + int j; + + for( i = 0; i < 3; i++ ) { + for( j = i + 1; j < 3; j++ ) { + temp = mat[ i ][ j ]; + mat[ i ][ j ] = mat[ j ][ i ]; + mat[ j ][ i ] = temp; + } + } +} + +mat3_t mat3_t::Inverse( void ) const { + mat3_t inv( *this ); + + inv.Transpose(); + + return inv; +} + +void mat3_t::Clear( void ) { + mat[0].set( 1, 0, 0 ); + mat[1].set( 0, 1, 0 ); + mat[2].set( 0, 0, 1 ); +} diff --git a/libs/splines/math_quaternion.cpp b/libs/splines/math_quaternion.cpp index 588ece23..5eab53b8 100644 --- a/libs/splines/math_quaternion.cpp +++ b/libs/splines/math_quaternion.cpp @@ -1,78 +1,78 @@ -/* -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 -*/ - -#include "math_quaternion.h" -#include "math_matrix.h" - -void toQuat( idVec3 &src, quat_t &dst ) { - dst.x = src.x; - dst.y = src.y; - dst.z = src.z; - dst.w = 0.0f; -} - -void toQuat( angles_t &src, quat_t &dst ) { - mat3_t temp; - - toMatrix( src, temp ); - toQuat( temp, dst ); -} - -void toQuat( mat3_t &src, quat_t &dst ) { - float trace; - float s; - int i; - int j; - int k; - - static int next[ 3 ] = { 1, 2, 0 }; - - trace = src[ 0 ][ 0 ] + src[ 1 ][ 1 ] + src[ 2 ][ 2 ]; - if ( trace > 0.0f ) { - s = ( float )sqrt( trace + 1.0f ); - dst.w = s * 0.5f; - s = 0.5f / s; - - dst.x = ( src[ 2 ][ 1 ] - src[ 1 ][ 2 ] ) * s; - dst.y = ( src[ 0 ][ 2 ] - src[ 2 ][ 0 ] ) * s; - dst.z = ( src[ 1 ][ 0 ] - src[ 0 ][ 1 ] ) * s; - } else { - i = 0; - if ( src[ 1 ][ 1 ] > src[ 0 ][ 0 ] ) { - i = 1; - } - if ( src[ 2 ][ 2 ] > src[ i ][ i ] ) { - i = 2; - } - - j = next[ i ]; - k = next[ j ]; - - s = ( float )sqrt( ( src[ i ][ i ] - ( src[ j ][ j ] + src[ k ][ k ] ) ) + 1.0f ); - dst[ i ] = s * 0.5f; - - s = 0.5f / s; - - dst.w = ( src[ k ][ j ] - src[ j ][ k ] ) * s; - dst[ j ] = ( src[ j ][ i ] + src[ i ][ j ] ) * s; - dst[ k ] = ( src[ k ][ i ] + src[ i ][ k ] ) * s; - } -} +/* +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 +*/ + +#include "math_quaternion.h" +#include "math_matrix.h" + +void toQuat( idVec3 &src, quat_t &dst ) { + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; + dst.w = 0.0f; +} + +void toQuat( angles_t &src, quat_t &dst ) { + mat3_t temp; + + toMatrix( src, temp ); + toQuat( temp, dst ); +} + +void toQuat( mat3_t &src, quat_t &dst ) { + float trace; + float s; + int i; + int j; + int k; + + static int next[ 3 ] = { 1, 2, 0 }; + + trace = src[ 0 ][ 0 ] + src[ 1 ][ 1 ] + src[ 2 ][ 2 ]; + if ( trace > 0.0f ) { + s = ( float )sqrt( trace + 1.0f ); + dst.w = s * 0.5f; + s = 0.5f / s; + + dst.x = ( src[ 2 ][ 1 ] - src[ 1 ][ 2 ] ) * s; + dst.y = ( src[ 0 ][ 2 ] - src[ 2 ][ 0 ] ) * s; + dst.z = ( src[ 1 ][ 0 ] - src[ 0 ][ 1 ] ) * s; + } else { + i = 0; + if ( src[ 1 ][ 1 ] > src[ 0 ][ 0 ] ) { + i = 1; + } + if ( src[ 2 ][ 2 ] > src[ i ][ i ] ) { + i = 2; + } + + j = next[ i ]; + k = next[ j ]; + + s = ( float )sqrt( ( src[ i ][ i ] - ( src[ j ][ j ] + src[ k ][ k ] ) ) + 1.0f ); + dst[ i ] = s * 0.5f; + + s = 0.5f / s; + + dst.w = ( src[ k ][ j ] - src[ j ][ k ] ) * s; + dst[ j ] = ( src[ j ][ i ] + src[ i ][ j ] ) * s; + dst[ k ] = ( src[ k ][ i ] + src[ i ][ k ] ) * s; + } +} diff --git a/libs/splines/math_vector.cpp b/libs/splines/math_vector.cpp index 7237de52..dfbcfc6b 100644 --- a/libs/splines/math_vector.cpp +++ b/libs/splines/math_vector.cpp @@ -1,143 +1,143 @@ -/* -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 -*/ - -#include "math_vector.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h - -#define LERP_DELTA 1e-6 - -idVec3 vec_zero( 0.0f, 0.0f, 0.0f ); - -Bounds boundsZero; - -float idVec3::toYaw( void ) { - float yaw; - - if ( ( y == 0 ) && ( x == 0 ) ) { - yaw = 0; - } else { - yaw = atan2( y, x ) * 180 / M_PI; - if ( yaw < 0 ) { - yaw += 360; - } - } - - return yaw; -} - -float idVec3::toPitch( void ) { - float forward; - float pitch; - - if ( ( x == 0 ) && ( y == 0 ) ) { - if ( z > 0 ) { - pitch = 90; - } else { - pitch = 270; - } - } else { - forward = ( float )idSqrt( x * x + y * y ); - pitch = atan2( z, forward ) * 180 / M_PI; - if ( pitch < 0 ) { - pitch += 360; - } - } - - return pitch; -} - -/* -angles_t idVec3::toAngles( void ) { - float forward; - float yaw; - float pitch; - - if ( ( x == 0 ) && ( y == 0 ) ) { - yaw = 0; - if ( z > 0 ) { - pitch = 90; - } else { - pitch = 270; - } - } else { - yaw = atan2( y, x ) * 180 / M_PI; - if ( yaw < 0 ) { - yaw += 360; - } - - forward = ( float )idSqrt( x * x + y * y ); - pitch = atan2( z, forward ) * 180 / M_PI; - if ( pitch < 0 ) { - pitch += 360; - } - } - - return angles_t( -pitch, yaw, 0 ); -} -*/ - -idVec3 LerpVector( idVec3 &w1, idVec3 &w2, const float t ) { - float omega, cosom, sinom, scale0, scale1; - - cosom = w1 * w2; - if ( ( 1.0 - cosom ) > LERP_DELTA ) { - omega = acos( cosom ); - sinom = sin( omega ); - scale0 = sin( ( 1.0 - t ) * omega ) / sinom; - scale1 = sin( t * omega ) / sinom; - } else { - scale0 = 1.0 - t; - scale1 = t; - } - - return ( w1 * scale0 + w2 * scale1 ); -} - -/* -============= -idVec3::string - -This is just a convenience function -for printing vectors -============= -*/ -char *idVec3::string( void ) { - static int index = 0; - static char str[ 8 ][ 36 ]; - char *s; - - // use an array so that multiple toString's won't collide - s = str[ index ]; - index = (index + 1)&7; - - sprintf( s, "%.2f %.2f %.2f", x, y, z ); - - return s; -} +/* +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 +*/ + +#include "math_vector.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h + +#define LERP_DELTA 1e-6 + +idVec3 vec_zero( 0.0f, 0.0f, 0.0f ); + +Bounds boundsZero; + +float idVec3::toYaw( void ) { + float yaw; + + if ( ( y == 0 ) && ( x == 0 ) ) { + yaw = 0; + } else { + yaw = atan2( y, x ) * 180 / M_PI; + if ( yaw < 0 ) { + yaw += 360; + } + } + + return yaw; +} + +float idVec3::toPitch( void ) { + float forward; + float pitch; + + if ( ( x == 0 ) && ( y == 0 ) ) { + if ( z > 0 ) { + pitch = 90; + } else { + pitch = 270; + } + } else { + forward = ( float )idSqrt( x * x + y * y ); + pitch = atan2( z, forward ) * 180 / M_PI; + if ( pitch < 0 ) { + pitch += 360; + } + } + + return pitch; +} + +/* +angles_t idVec3::toAngles( void ) { + float forward; + float yaw; + float pitch; + + if ( ( x == 0 ) && ( y == 0 ) ) { + yaw = 0; + if ( z > 0 ) { + pitch = 90; + } else { + pitch = 270; + } + } else { + yaw = atan2( y, x ) * 180 / M_PI; + if ( yaw < 0 ) { + yaw += 360; + } + + forward = ( float )idSqrt( x * x + y * y ); + pitch = atan2( z, forward ) * 180 / M_PI; + if ( pitch < 0 ) { + pitch += 360; + } + } + + return angles_t( -pitch, yaw, 0 ); +} +*/ + +idVec3 LerpVector( idVec3 &w1, idVec3 &w2, const float t ) { + float omega, cosom, sinom, scale0, scale1; + + cosom = w1 * w2; + if ( ( 1.0 - cosom ) > LERP_DELTA ) { + omega = acos( cosom ); + sinom = sin( omega ); + scale0 = sin( ( 1.0 - t ) * omega ) / sinom; + scale1 = sin( t * omega ) / sinom; + } else { + scale0 = 1.0 - t; + scale1 = t; + } + + return ( w1 * scale0 + w2 * scale1 ); +} + +/* +============= +idVec3::string + +This is just a convenience function +for printing vectors +============= +*/ +char *idVec3::string( void ) { + static int index = 0; + static char str[ 8 ][ 36 ]; + char *s; + + // use an array so that multiple toString's won't collide + s = str[ index ]; + index = (index + 1)&7; + + sprintf( s, "%.2f %.2f %.2f", x, y, z ); + + return s; +} diff --git a/libs/splines/q_parse.cpp b/libs/splines/q_parse.cpp index 7709d2ba..17fd12ed 100644 --- a/libs/splines/q_parse.cpp +++ b/libs/splines/q_parse.cpp @@ -1,535 +1,535 @@ -/* -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 -*/ - -// q_parse.c -- support for parsing text files - -#include "q_shared.h" - -/* -============================================================================ - -PARSING - -============================================================================ -*/ - -// multiple character punctuation tokens -static const char *punctuation[] = { - "+=", "-=", "*=", "/=", "&=", "|=", "++", "--", - "&&", "||", "<=", ">=", "==", "!=", - NULL -}; - -typedef struct { - char token[MAX_TOKEN_CHARS]; - int lines; - qboolean ungetToken; - char parseFile[MAX_QPATH]; -} parseInfo_t; - -#define MAX_PARSE_INFO 16 -static parseInfo_t parseInfo[MAX_PARSE_INFO]; -static int parseInfoNum; -static parseInfo_t *pi = &parseInfo[0]; - -/* -=================== -Com_BeginParseSession -=================== -*/ -void Com_BeginParseSession( const char *filename ) { - if ( parseInfoNum == MAX_PARSE_INFO - 1 ) { - Com_Error( ERR_FATAL, "Com_BeginParseSession: session overflow" ); - } - parseInfoNum++; - pi = &parseInfo[parseInfoNum]; - - pi->lines = 1; - Q_strncpyz( pi->parseFile, filename, sizeof( pi->parseFile ) ); -} - -/* -=================== -Com_EndParseSession -=================== -*/ -void Com_EndParseSession( void ) { - if ( parseInfoNum == 0 ) { - Com_Error( ERR_FATAL, "Com_EndParseSession: session underflow" ); - } - parseInfoNum--; - pi = &parseInfo[parseInfoNum]; -} - -/* -=================== -Com_GetCurrentParseLine -=================== -*/ -int Com_GetCurrentParseLine( void ) { - return pi->lines; -} - -/* -=================== -Com_ScriptError - -Prints the script name and line number in the message -=================== -*/ -void Com_ScriptError( const char *msg, ... ) { - va_list argptr; - char string[32000]; - - va_start( argptr, msg ); - vsprintf( string, msg,argptr ); - va_end( argptr ); - - Com_Error( ERR_DROP, "File %s, line %i: %s", pi->parseFile, pi->lines, string ); -} - -void Com_ScriptWarning( const char *msg, ... ) { - va_list argptr; - char string[32000]; - - va_start( argptr, msg ); - vsprintf( string, msg,argptr ); - va_end( argptr ); - - Com_Printf( "File %s, line %i: %s", pi->parseFile, pi->lines, string ); -} - - -/* -=================== -Com_UngetToken - -Calling this will make the next Com_Parse return -the current token instead of advancing the pointer -=================== -*/ -void Com_UngetToken( void ) { - if ( pi->ungetToken ) { - Com_ScriptError( "UngetToken called twice" ); - } - pi->ungetToken = qtrue; -} - - -static const char *SkipWhitespace( const char (*data), qboolean *hasNewLines ) { - int c; - - while( (c = *data) <= ' ') { - if( !c ) { - return NULL; - } - if( c == '\n' ) { - pi->lines++; - *hasNewLines = qtrue; - } - data++; - } - - return data; -} - -/* -============== -Com_ParseExt - -Parse a token out of a string -Will never return NULL, just empty strings. -An empty string will only be returned at end of file. - -If "allowLineBreaks" is qtrue then an empty -string will be returned if the next token is -a newline. -============== -*/ -static char *Com_ParseExt( const char *(*data_p), qboolean allowLineBreaks ) { - int c = 0, len; - qboolean hasNewLines = qfalse; - const char *data; - const char **punc; - - if ( !data_p ) { - Com_Error( ERR_FATAL, "Com_ParseExt: NULL data_p" ); - } - - data = *data_p; - len = 0; - pi->token[0] = 0; - - // make sure incoming data is valid - if ( !data ) { - *data_p = NULL; - return pi->token; - } - - // skip any leading whitespace - while ( 1 ) { - // skip whitespace - data = SkipWhitespace( data, &hasNewLines ); - if ( !data ) { - *data_p = NULL; - return pi->token; - } - if ( hasNewLines && !allowLineBreaks ) { - *data_p = data; - return pi->token; - } - - c = *data; - - // skip double slash comments - if ( c == '/' && data[1] == '/' ) { - while (*data && *data != '\n') { - data++; - } - continue; - } - - // skip /* */ comments - if ( c=='/' && data[1] == '*' ) { - while ( *data && ( *data != '*' || data[1] != '/' ) ) { - if( *data == '\n' ) { - pi->lines++; - } - data++; - } - if ( *data ) { - data += 2; - } - continue; - } - - // a real token to parse - break; - } - - // handle quoted strings - if ( c == '\"' ) { - data++; - while( 1 ) { - c = *data++; - if ( ( c=='\\' ) && ( *data == '\"' ) ) { - // allow quoted strings to use \" to indicate the " character - data++; - } else if ( c=='\"' || !c ) { - pi->token[len] = 0; - *data_p = ( char * ) data; - return pi->token; - } else if( *data == '\n' ) { - pi->lines++; - } - if ( len < MAX_TOKEN_CHARS - 1 ) { - pi->token[len] = c; - len++; - } - } - } - - // check for a number - // is this parsing of negative numbers going to cause expression problems - if ( ( c >= '0' && c <= '9' ) || ( c == '-' && data[ 1 ] >= '0' && data[ 1 ] <= '9' ) || - ( c == '.' && data[ 1 ] >= '0' && data[ 1 ] <= '9' ) ) { - do { - - if (len < MAX_TOKEN_CHARS - 1) { - pi->token[len] = c; - len++; - } - data++; - - c = *data; - } while ( ( c >= '0' && c <= '9' ) || c == '.' ); - - // parse the exponent - if ( c == 'e' || c == 'E' ) { - if (len < MAX_TOKEN_CHARS - 1) { - pi->token[len] = c; - len++; - } - data++; - c = *data; - - if ( c == '-' || c == '+' ) { - if (len < MAX_TOKEN_CHARS - 1) { - pi->token[len] = c; - len++; - } - data++; - c = *data; - } - - do { - if (len < MAX_TOKEN_CHARS - 1) { - pi->token[len] = c; - len++; - } - data++; - - c = *data; - } while ( c >= '0' && c <= '9' ); - } - - if (len == MAX_TOKEN_CHARS) { - len = 0; - } - pi->token[len] = 0; - - *data_p = ( char * ) data; - return pi->token; - } - - // check for a regular word - // we still allow forward and back slashes in name tokens for pathnames - // and also colons for drive letters - if ( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == '_' || c == '/' || c == '\\' ) { - do { - if (len < MAX_TOKEN_CHARS - 1) { - pi->token[len] = c; - len++; - } - data++; - - c = *data; - } while ( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == '_' - || ( c >= '0' && c <= '9' ) || c == '/' || c == '\\' || c == ':' || c == '.' ); - - if (len == MAX_TOKEN_CHARS) { - len = 0; - } - pi->token[len] = 0; - - *data_p = ( char * ) data; - return pi->token; - } - - // check for multi-character punctuation token - for ( punc = punctuation ; *punc ; punc++ ) { - int l; - int j; - - l = strlen( *punc ); - for ( j = 0 ; j < l ; j++ ) { - if ( data[j] != (*punc)[j] ) { - break; - } - } - if ( j == l ) { - // a valid multi-character punctuation - memcpy( pi->token, *punc, l ); - pi->token[l] = 0; - data += l; - *data_p = (char *)data; - return pi->token; - } - } - - // single character punctuation - pi->token[0] = *data; - pi->token[1] = 0; - data++; - *data_p = (char *)data; - - return pi->token; -} - -/* -=================== -Com_Parse -=================== -*/ -const char *Com_Parse( const char *(*data_p) ) { - if ( pi->ungetToken ) { - pi->ungetToken = qfalse; - return pi->token; - } - return Com_ParseExt( data_p, qtrue ); -} - -/* -=================== -Com_ParseOnLine -=================== -*/ -const char *Com_ParseOnLine( const char *(*data_p) ) { - if ( pi->ungetToken ) { - pi->ungetToken = qfalse; - return pi->token; - } - return Com_ParseExt( data_p, qfalse ); -} - - - -/* -================== -Com_MatchToken -================== -*/ -void Com_MatchToken( const char *(*buf_p), const char *match, qboolean warning ) { - const char *token; - - token = Com_Parse( buf_p ); - if ( strcmp( token, match ) ) { - if (warning) { - Com_ScriptWarning( "MatchToken: %s != %s", token, match ); - } else { - Com_ScriptError( "MatchToken: %s != %s", token, match ); - } - } -} - - -/* -================= -Com_SkipBracedSection - -The next token should be an open brace. -Skips until a matching close brace is found. -Internal brace depths are properly skipped. -================= -*/ -void Com_SkipBracedSection( const char *(*program) ) { - const char *token; - int depth; - - depth = 0; - do { - token = Com_Parse( program ); - if( token[1] == 0 ) { - if( token[0] == '{' ) { - depth++; - } - else if( token[0] == '}' ) { - depth--; - } - } - } while( depth && *program ); -} - -/* -================= -Com_SkipRestOfLine -================= -*/ -void Com_SkipRestOfLine ( const char *(*data) ) { - const char *p; - int c; - - p = *data; - while ( (c = *p++) != 0 ) { - if ( c == '\n' ) { - pi->lines++; - break; - } - } - - *data = p; -} - -/* -==================== -Com_ParseRestOfLine -==================== -*/ -const char *Com_ParseRestOfLine( const char *(*data_p) ) { - static char line[MAX_TOKEN_CHARS]; - const char *token; - - line[0] = 0; - while( 1 ) { - token = Com_ParseOnLine( data_p ); - if ( !token[0] ) { - break; - } - if ( line[0] ) { - Q_strcat( line, sizeof(line), " " ); - } - Q_strcat( line, sizeof(line), token ); - } - - return line; -} - - -float Com_ParseFloat( const char *(*buf_p) ) { - const char *token; - - token = Com_Parse( buf_p ); - if ( !token[0] ) { - return 0; - } - return atof( token ); -} - -int Com_ParseInt( const char *(*buf_p) ) { - const char *token; - - token = Com_Parse( buf_p ); - if ( !token[0] ) { - return 0; - } - return (int)atof( token ); -} - - - -void Com_Parse1DMatrix( const char *(*buf_p), int x, float *m ) { - const char *token; - int i; - - Com_MatchToken( buf_p, "(" ); - - for (i = 0 ; i < x ; i++) { - token = Com_Parse(buf_p); - m[i] = atof(token); - } - - Com_MatchToken( buf_p, ")" ); -} - -void Com_Parse2DMatrix( const char *(*buf_p), int y, int x, float *m ) { - int i; - - Com_MatchToken( buf_p, "(" ); - - for (i = 0 ; i < y ; i++) { - Com_Parse1DMatrix (buf_p, x, m + i * x); - } - - Com_MatchToken( buf_p, ")" ); -} - -void Com_Parse3DMatrix( const char *(*buf_p), int z, int y, int x, float *m ) { - int i; - - Com_MatchToken( buf_p, "(" ); - - for (i = 0 ; i < z ; i++) { - Com_Parse2DMatrix (buf_p, y, x, m + i * x*y); - } - - Com_MatchToken( buf_p, ")" ); -} - +/* +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 +*/ + +// q_parse.c -- support for parsing text files + +#include "q_shared.h" + +/* +============================================================================ + +PARSING + +============================================================================ +*/ + +// multiple character punctuation tokens +static const char *punctuation[] = { + "+=", "-=", "*=", "/=", "&=", "|=", "++", "--", + "&&", "||", "<=", ">=", "==", "!=", + NULL +}; + +typedef struct { + char token[MAX_TOKEN_CHARS]; + int lines; + qboolean ungetToken; + char parseFile[MAX_QPATH]; +} parseInfo_t; + +#define MAX_PARSE_INFO 16 +static parseInfo_t parseInfo[MAX_PARSE_INFO]; +static int parseInfoNum; +static parseInfo_t *pi = &parseInfo[0]; + +/* +=================== +Com_BeginParseSession +=================== +*/ +void Com_BeginParseSession( const char *filename ) { + if ( parseInfoNum == MAX_PARSE_INFO - 1 ) { + Com_Error( ERR_FATAL, "Com_BeginParseSession: session overflow" ); + } + parseInfoNum++; + pi = &parseInfo[parseInfoNum]; + + pi->lines = 1; + Q_strncpyz( pi->parseFile, filename, sizeof( pi->parseFile ) ); +} + +/* +=================== +Com_EndParseSession +=================== +*/ +void Com_EndParseSession( void ) { + if ( parseInfoNum == 0 ) { + Com_Error( ERR_FATAL, "Com_EndParseSession: session underflow" ); + } + parseInfoNum--; + pi = &parseInfo[parseInfoNum]; +} + +/* +=================== +Com_GetCurrentParseLine +=================== +*/ +int Com_GetCurrentParseLine( void ) { + return pi->lines; +} + +/* +=================== +Com_ScriptError + +Prints the script name and line number in the message +=================== +*/ +void Com_ScriptError( const char *msg, ... ) { + va_list argptr; + char string[32000]; + + va_start( argptr, msg ); + vsprintf( string, msg,argptr ); + va_end( argptr ); + + Com_Error( ERR_DROP, "File %s, line %i: %s", pi->parseFile, pi->lines, string ); +} + +void Com_ScriptWarning( const char *msg, ... ) { + va_list argptr; + char string[32000]; + + va_start( argptr, msg ); + vsprintf( string, msg,argptr ); + va_end( argptr ); + + Com_Printf( "File %s, line %i: %s", pi->parseFile, pi->lines, string ); +} + + +/* +=================== +Com_UngetToken + +Calling this will make the next Com_Parse return +the current token instead of advancing the pointer +=================== +*/ +void Com_UngetToken( void ) { + if ( pi->ungetToken ) { + Com_ScriptError( "UngetToken called twice" ); + } + pi->ungetToken = qtrue; +} + + +static const char *SkipWhitespace( const char (*data), qboolean *hasNewLines ) { + int c; + + while( (c = *data) <= ' ') { + if( !c ) { + return NULL; + } + if( c == '\n' ) { + pi->lines++; + *hasNewLines = qtrue; + } + data++; + } + + return data; +} + +/* +============== +Com_ParseExt + +Parse a token out of a string +Will never return NULL, just empty strings. +An empty string will only be returned at end of file. + +If "allowLineBreaks" is qtrue then an empty +string will be returned if the next token is +a newline. +============== +*/ +static char *Com_ParseExt( const char *(*data_p), qboolean allowLineBreaks ) { + int c = 0, len; + qboolean hasNewLines = qfalse; + const char *data; + const char **punc; + + if ( !data_p ) { + Com_Error( ERR_FATAL, "Com_ParseExt: NULL data_p" ); + } + + data = *data_p; + len = 0; + pi->token[0] = 0; + + // make sure incoming data is valid + if ( !data ) { + *data_p = NULL; + return pi->token; + } + + // skip any leading whitespace + while ( 1 ) { + // skip whitespace + data = SkipWhitespace( data, &hasNewLines ); + if ( !data ) { + *data_p = NULL; + return pi->token; + } + if ( hasNewLines && !allowLineBreaks ) { + *data_p = data; + return pi->token; + } + + c = *data; + + // skip double slash comments + if ( c == '/' && data[1] == '/' ) { + while (*data && *data != '\n') { + data++; + } + continue; + } + + // skip /* */ comments + if ( c=='/' && data[1] == '*' ) { + while ( *data && ( *data != '*' || data[1] != '/' ) ) { + if( *data == '\n' ) { + pi->lines++; + } + data++; + } + if ( *data ) { + data += 2; + } + continue; + } + + // a real token to parse + break; + } + + // handle quoted strings + if ( c == '\"' ) { + data++; + while( 1 ) { + c = *data++; + if ( ( c=='\\' ) && ( *data == '\"' ) ) { + // allow quoted strings to use \" to indicate the " character + data++; + } else if ( c=='\"' || !c ) { + pi->token[len] = 0; + *data_p = ( char * ) data; + return pi->token; + } else if( *data == '\n' ) { + pi->lines++; + } + if ( len < MAX_TOKEN_CHARS - 1 ) { + pi->token[len] = c; + len++; + } + } + } + + // check for a number + // is this parsing of negative numbers going to cause expression problems + if ( ( c >= '0' && c <= '9' ) || ( c == '-' && data[ 1 ] >= '0' && data[ 1 ] <= '9' ) || + ( c == '.' && data[ 1 ] >= '0' && data[ 1 ] <= '9' ) ) { + do { + + if (len < MAX_TOKEN_CHARS - 1) { + pi->token[len] = c; + len++; + } + data++; + + c = *data; + } while ( ( c >= '0' && c <= '9' ) || c == '.' ); + + // parse the exponent + if ( c == 'e' || c == 'E' ) { + if (len < MAX_TOKEN_CHARS - 1) { + pi->token[len] = c; + len++; + } + data++; + c = *data; + + if ( c == '-' || c == '+' ) { + if (len < MAX_TOKEN_CHARS - 1) { + pi->token[len] = c; + len++; + } + data++; + c = *data; + } + + do { + if (len < MAX_TOKEN_CHARS - 1) { + pi->token[len] = c; + len++; + } + data++; + + c = *data; + } while ( c >= '0' && c <= '9' ); + } + + if (len == MAX_TOKEN_CHARS) { + len = 0; + } + pi->token[len] = 0; + + *data_p = ( char * ) data; + return pi->token; + } + + // check for a regular word + // we still allow forward and back slashes in name tokens for pathnames + // and also colons for drive letters + if ( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == '_' || c == '/' || c == '\\' ) { + do { + if (len < MAX_TOKEN_CHARS - 1) { + pi->token[len] = c; + len++; + } + data++; + + c = *data; + } while ( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == '_' + || ( c >= '0' && c <= '9' ) || c == '/' || c == '\\' || c == ':' || c == '.' ); + + if (len == MAX_TOKEN_CHARS) { + len = 0; + } + pi->token[len] = 0; + + *data_p = ( char * ) data; + return pi->token; + } + + // check for multi-character punctuation token + for ( punc = punctuation ; *punc ; punc++ ) { + int l; + int j; + + l = strlen( *punc ); + for ( j = 0 ; j < l ; j++ ) { + if ( data[j] != (*punc)[j] ) { + break; + } + } + if ( j == l ) { + // a valid multi-character punctuation + memcpy( pi->token, *punc, l ); + pi->token[l] = 0; + data += l; + *data_p = (char *)data; + return pi->token; + } + } + + // single character punctuation + pi->token[0] = *data; + pi->token[1] = 0; + data++; + *data_p = (char *)data; + + return pi->token; +} + +/* +=================== +Com_Parse +=================== +*/ +const char *Com_Parse( const char *(*data_p) ) { + if ( pi->ungetToken ) { + pi->ungetToken = qfalse; + return pi->token; + } + return Com_ParseExt( data_p, qtrue ); +} + +/* +=================== +Com_ParseOnLine +=================== +*/ +const char *Com_ParseOnLine( const char *(*data_p) ) { + if ( pi->ungetToken ) { + pi->ungetToken = qfalse; + return pi->token; + } + return Com_ParseExt( data_p, qfalse ); +} + + + +/* +================== +Com_MatchToken +================== +*/ +void Com_MatchToken( const char *(*buf_p), const char *match, qboolean warning ) { + const char *token; + + token = Com_Parse( buf_p ); + if ( strcmp( token, match ) ) { + if (warning) { + Com_ScriptWarning( "MatchToken: %s != %s", token, match ); + } else { + Com_ScriptError( "MatchToken: %s != %s", token, match ); + } + } +} + + +/* +================= +Com_SkipBracedSection + +The next token should be an open brace. +Skips until a matching close brace is found. +Internal brace depths are properly skipped. +================= +*/ +void Com_SkipBracedSection( const char *(*program) ) { + const char *token; + int depth; + + depth = 0; + do { + token = Com_Parse( program ); + if( token[1] == 0 ) { + if( token[0] == '{' ) { + depth++; + } + else if( token[0] == '}' ) { + depth--; + } + } + } while( depth && *program ); +} + +/* +================= +Com_SkipRestOfLine +================= +*/ +void Com_SkipRestOfLine ( const char *(*data) ) { + const char *p; + int c; + + p = *data; + while ( (c = *p++) != 0 ) { + if ( c == '\n' ) { + pi->lines++; + break; + } + } + + *data = p; +} + +/* +==================== +Com_ParseRestOfLine +==================== +*/ +const char *Com_ParseRestOfLine( const char *(*data_p) ) { + static char line[MAX_TOKEN_CHARS]; + const char *token; + + line[0] = 0; + while( 1 ) { + token = Com_ParseOnLine( data_p ); + if ( !token[0] ) { + break; + } + if ( line[0] ) { + Q_strcat( line, sizeof(line), " " ); + } + Q_strcat( line, sizeof(line), token ); + } + + return line; +} + + +float Com_ParseFloat( const char *(*buf_p) ) { + const char *token; + + token = Com_Parse( buf_p ); + if ( !token[0] ) { + return 0; + } + return atof( token ); +} + +int Com_ParseInt( const char *(*buf_p) ) { + const char *token; + + token = Com_Parse( buf_p ); + if ( !token[0] ) { + return 0; + } + return (int)atof( token ); +} + + + +void Com_Parse1DMatrix( const char *(*buf_p), int x, float *m ) { + const char *token; + int i; + + Com_MatchToken( buf_p, "(" ); + + for (i = 0 ; i < x ; i++) { + token = Com_Parse(buf_p); + m[i] = atof(token); + } + + Com_MatchToken( buf_p, ")" ); +} + +void Com_Parse2DMatrix( const char *(*buf_p), int y, int x, float *m ) { + int i; + + Com_MatchToken( buf_p, "(" ); + + for (i = 0 ; i < y ; i++) { + Com_Parse1DMatrix (buf_p, x, m + i * x); + } + + Com_MatchToken( buf_p, ")" ); +} + +void Com_Parse3DMatrix( const char *(*buf_p), int z, int y, int x, float *m ) { + int i; + + Com_MatchToken( buf_p, "(" ); + + for (i = 0 ; i < z ; i++) { + Com_Parse2DMatrix (buf_p, y, x, m + i * x*y); + } + + Com_MatchToken( buf_p, ")" ); +} + diff --git a/libs/splines/q_shared.cpp b/libs/splines/q_shared.cpp index 39fccee9..57a899b9 100644 --- a/libs/splines/q_shared.cpp +++ b/libs/splines/q_shared.cpp @@ -1,976 +1,976 @@ -/* -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 -*/ - -// q_shared.c -- stateless support routines that are included in each code dll -#include "q_shared.h" - -/* -============================================================================ - -GROWLISTS - -============================================================================ -*/ - -// malloc / free all in one place for debugging -extern "C" void *Com_Allocate( int bytes ); -extern "C" void Com_Dealloc( void *ptr ); - -void Com_InitGrowList( growList_t *list, int maxElements ) { - list->maxElements = maxElements; - list->currentElements = 0; - list->elements = (void **)Com_Allocate( list->maxElements * sizeof( void * ) ); -} - -int Com_AddToGrowList( growList_t *list, void *data ) { - void **old; - - if ( list->currentElements != list->maxElements ) { - list->elements[list->currentElements] = data; - return list->currentElements++; - } - - // grow, reallocate and move - old = list->elements; - - if ( list->maxElements < 0 ) { - Com_Error( ERR_FATAL, "Com_AddToGrowList: maxElements = %i", list->maxElements ); - } - - if ( list->maxElements == 0 ) { - // initialize the list to hold 100 elements - Com_InitGrowList( list, 100 ); - return Com_AddToGrowList( list, data ); - } - - list->maxElements *= 2; - - Com_DPrintf( "Resizing growlist to %i maxElements\n", list->maxElements ); - - list->elements = (void **)Com_Allocate( list->maxElements * sizeof( void * ) ); - - if ( !list->elements ) { - Com_Error( ERR_DROP, "Growlist alloc failed" ); - } - - memcpy( list->elements, old, list->currentElements * sizeof( void * ) ); - - Com_Dealloc( old ); - - return Com_AddToGrowList( list, data ); -} - -void *Com_GrowListElement( const growList_t *list, int index ) { - if ( index < 0 || index >= list->currentElements ) { - Com_Error( ERR_DROP, "Com_GrowListElement: %i out of range of %i", - index, list->currentElements ); - } - return list->elements[index]; -} - -int Com_IndexForGrowListElement( const growList_t *list, const void *element ) { - int i; - - for ( i = 0 ; i < list->currentElements ; i++ ) { - if ( list->elements[i] == element ) { - return i; - } - } - return -1; -} - -//============================================================================ - - -float Com_Clamp( float min, float max, float value ) { - if ( value < min ) { - return min; - } - if ( value > max ) { - return max; - } - return value; -} - -/* -============ -Com_StringContains -============ -*/ -const char *Com_StringContains( const char *str1, const char *str2, int casesensitive) { - int len, i, j; - - len = strlen(str1) - strlen(str2); - for (i = 0; i <= len; i++, str1++) { - for (j = 0; str2[j]; j++) { - if (casesensitive) { - if (str1[j] != str2[j]) { - break; - } - } - else { - if (toupper(str1[j]) != toupper(str2[j])) { - break; - } - } - } - if (!str2[j]) { - return str1; - } - } - return NULL; -} - -/* -============ -Com_Filter -============ -*/ -int Com_Filter( const char *filter, const char *name, int casesensitive) -{ - char buf[MAX_TOKEN_CHARS]; - const char *ptr; - int i, found; - - while(*filter) { - if (*filter == '*') { - filter++; - for (i = 0; *filter; i++) { - if (*filter == '*' || *filter == '?') break; - buf[i] = *filter; - filter++; - } - buf[i] = '\0'; - if (strlen(buf)) { - ptr = Com_StringContains(name, buf, casesensitive); - if (!ptr) return qfalse; - name = ptr + strlen(buf); - } - } - else if (*filter == '?') { - filter++; - name++; - } - else if (*filter == '[' && *(filter+1) == '[') { - filter++; - } - else if (*filter == '[') { - filter++; - found = qfalse; - while(*filter && !found) { - if (*filter == ']' && *(filter+1) != ']') break; - if (*(filter+1) == '-' && *(filter+2) && (*(filter+2) != ']' || *(filter+3) == ']')) { - if (casesensitive) { - if (*name >= *filter && *name <= *(filter+2)) found = qtrue; - } - else { - if (toupper(*name) >= toupper(*filter) && - toupper(*name) <= toupper(*(filter+2))) found = qtrue; - } - filter += 3; - } - else { - if (casesensitive) { - if (*filter == *name) found = qtrue; - } - else { - if (toupper(*filter) == toupper(*name)) found = qtrue; - } - filter++; - } - } - if (!found) return qfalse; - while(*filter) { - if (*filter == ']' && *(filter+1) != ']') break; - filter++; - } - filter++; - name++; - } - else { - if (casesensitive) { - if (*filter != *name) return qfalse; - } - else { - if (toupper(*filter) != toupper(*name)) return qfalse; - } - filter++; - name++; - } - } - return qtrue; -} - - -/* -================ -Com_HashString - -================ -*/ -int Com_HashString( const char *fname ) { - int i; - long hash; - char letter; - - hash = 0; - i = 0; - while (fname[i] != '\0') { - letter = tolower(fname[i]); - if (letter =='.') break; // don't include extension - if (letter =='\\') letter = '/'; // damn path names - hash+=(long)(letter)*(i+119); - i++; - } - hash &= (FILE_HASH_SIZE-1); - return hash; -} - - -/* -============ -Com_SkipPath -============ -*/ -char *Com_SkipPath (char *pathname) -{ - char *last; - - last = pathname; - while (*pathname) - { - if (*pathname=='/') - last = pathname+1; - pathname++; - } - return last; -} - -/* -============ -Com_StripExtension -============ -*/ -void Com_StripExtension( const char *in, char *out ) { - while ( *in && *in != '.' ) { - *out++ = *in++; - } - *out = 0; -} - - -/* -================== -Com_DefaultExtension -================== -*/ -void Com_DefaultExtension (char *path, int maxSize, const char *extension ) { - char oldPath[MAX_QPATH]; - char *src; - -// -// if path doesn't have a .EXT, append extension -// (extension should include the .) -// - src = path + strlen(path) - 1; - - while (*src != '/' && src != path) { - if ( *src == '.' ) { - return; // it has an extension - } - src--; - } - - Q_strncpyz( oldPath, path, sizeof( oldPath ) ); - Com_sprintf( path, maxSize, "%s%s", oldPath, extension ); -} - -/* -============================================================================ - - BYTE ORDER FUNCTIONS - -============================================================================ -*/ - -// can't just use function pointers, or dll linkage can -// mess up when qcommon is included in multiple places -static short (*_BigShort) (short l); -static short (*_LittleShort) (short l); -static int (*_BigLong) (int l); -static int (*_LittleLong) (int l); -static float (*_BigFloat) (float l); -static float (*_LittleFloat) (float l); - -short BigShort(short l){return _BigShort(l);} -short LittleShort(short l) {return _LittleShort(l);} -int BigLong (int l) {return _BigLong(l);} -int LittleLong (int l) {return _LittleLong(l);} -float BigFloat (float l) {return _BigFloat(l);} -float LittleFloat (float l) {return _LittleFloat(l);} - -short ShortSwap (short l) -{ - byte b1,b2; - - b1 = l&255; - b2 = (l>>8)&255; - - return (b1<<8) + b2; -} - -short ShortNoSwap (short l) -{ - return l; -} - -int LongSwap (int l) -{ - byte b1,b2,b3,b4; - - b1 = l&255; - b2 = (l>>8)&255; - b3 = (l>>16)&255; - b4 = (l>>24)&255; - - return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; -} - -int LongNoSwap (int l) -{ - return l; -} - -float FloatSwap (float f) -{ - union - { - float f; - byte b[4]; - } dat1, dat2; - - - dat1.f = f; - dat2.b[0] = dat1.b[3]; - dat2.b[1] = dat1.b[2]; - dat2.b[2] = dat1.b[1]; - dat2.b[3] = dat1.b[0]; - return dat2.f; -} - -float FloatNoSwap (float f) -{ - return f; -} - -/* -================ -Swap_Init -================ -*/ -void Swap_Init (void) -{ - byte swaptest[2] = {1,0}; - -// set the byte swapping variables in a portable manner - if ( *(short *)swaptest == 1) - { - _BigShort = ShortSwap; - _LittleShort = ShortNoSwap; - _BigLong = LongSwap; - _LittleLong = LongNoSwap; - _BigFloat = FloatSwap; - _LittleFloat = FloatNoSwap; - } - else - { - _BigShort = ShortNoSwap; - _LittleShort = ShortSwap; - _BigLong = LongNoSwap; - _LittleLong = LongSwap; - _BigFloat = FloatNoSwap; - _LittleFloat = FloatSwap; - } - -} - -/* -=============== -Com_ParseInfos -=============== -*/ -int Com_ParseInfos( const char *buf, int max, char infos[][MAX_INFO_STRING] ) { - const char *token; - int count; - char key[MAX_TOKEN_CHARS]; - - count = 0; - - while ( 1 ) { - token = Com_Parse( &buf ); - if ( !token[0] ) { - break; - } - if ( strcmp( token, "{" ) ) { - Com_Printf( "Missing { in info file\n" ); - break; - } - - if ( count == max ) { - Com_Printf( "Max infos exceeded\n" ); - break; - } - - infos[count][0] = 0; - while ( 1 ) { - token = Com_Parse( &buf ); - if ( !token[0] ) { - Com_Printf( "Unexpected end of info file\n" ); - break; - } - if ( !strcmp( token, "}" ) ) { - break; - } - Q_strncpyz( key, token, sizeof( key ) ); - - token = Com_ParseOnLine( &buf ); - if ( !token[0] ) { - token = ""; - } - Info_SetValueForKey( infos[count], key, token ); - } - count++; - } - - return count; -} - - - -/* -============================================================================ - - LIBRARY REPLACEMENT FUNCTIONS - -============================================================================ -*/ - -int Q_isprint( int c ) -{ - if ( c >= 0x20 && c <= 0x7E ) - return ( 1 ); - return ( 0 ); -} - -int Q_islower( int c ) -{ - if (c >= 'a' && c <= 'z') - return ( 1 ); - return ( 0 ); -} - -int Q_isupper( int c ) -{ - if (c >= 'A' && c <= 'Z') - return ( 1 ); - return ( 0 ); -} - -int Q_isalpha( int c ) -{ - if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) - return ( 1 ); - return ( 0 ); -} - -char* Q_strrchr( const char* string, int c ) -{ - char cc = c; - char *s; - char *sp=(char *)0; - - s = (char*)string; - - while (*s) - { - if (*s == cc) - sp = s; - s++; - } - if (cc == 0) - sp = s; - - return sp; -} - -/* -============= -Q_strncpyz - -Safe strncpy that ensures a trailing zero -============= -*/ -void Q_strncpyz( char *dest, const char *src, int destsize ) { - if ( !src ) { - Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" ); - } - if ( destsize < 1 ) { - Com_Error(ERR_FATAL,"Q_strncpyz: destsize < 1" ); - } - - strncpy( dest, src, destsize-1 ); - dest[destsize-1] = 0; -} - -int Q_stricmpn (const char *s1, const char *s2, int n) { - int c1, c2; - - do { - c1 = *s1++; - c2 = *s2++; - - if (!n--) { - return 0; // strings are equal until end point - } - - if (c1 != c2) { - if (c1 >= 'a' && c1 <= 'z') { - c1 -= ('a' - 'A'); - } - if (c2 >= 'a' && c2 <= 'z') { - c2 -= ('a' - 'A'); - } - if (c1 != c2) { - return c1 < c2 ? -1 : 1; - } - } - } while (c1); - - return 0; // strings are equal -} - -int Q_strncmp (const char *s1, const char *s2, int n) { - int c1, c2; - - do { - c1 = *s1++; - c2 = *s2++; - - if (!n--) { - return 0; // strings are equal until end point - } - - if (c1 != c2) { - return c1 < c2 ? -1 : 1; - } - } while (c1); - - return 0; // strings are equal -} - -int Q_stricmp (const char *s1, const char *s2) { - return Q_stricmpn (s1, s2, 99999); -} - - -char *Q_strlwr( char *s1 ) { - char *s; - - s = s1; - while ( *s ) { - *s = tolower(*s); - s++; - } - return s1; -} - -char *Q_strupr( char *s1 ) { - char *s; - - s = s1; - while ( *s ) { - *s = toupper(*s); - s++; - } - return s1; -} - - -// never goes past bounds or leaves without a terminating 0 -void Q_strcat( char *dest, int size, const char *src ) { - int l1; - - l1 = strlen( dest ); - if ( l1 >= size ) { - Com_Error( ERR_FATAL, "Q_strcat: already overflowed" ); - } - Q_strncpyz( dest + l1, src, size - l1 ); -} - - -int Q_PrintStrlen( const char *string ) { - int len; - const char *p; - - if( !string ) { - return 0; - } - - len = 0; - p = string; - while( *p ) { - if( Q_IsColorString( p ) ) { - p += 2; - continue; - } - p++; - len++; - } - - return len; -} - - -char *Q_CleanStr( char *string ) { - char* d; - char* s; - int c; - - s = string; - d = string; - while ((c = *s) != 0 ) { - if ( Q_IsColorString( s ) ) { - s++; - } - else if ( c >= 0x20 && c <= 0x7E ) { - *d++ = c; - } - s++; - } - *d = '\0'; - - return string; -} - - -void QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) { - int len; - va_list argptr; - char bigbuffer[32000]; // big, but small enough to fit in PPC stack - - va_start (argptr,fmt); - len = vsprintf (bigbuffer,fmt,argptr); - va_end (argptr); - if ( len >= sizeof( bigbuffer ) ) { - Com_Error( ERR_FATAL, "Com_sprintf: overflowed bigbuffer" ); - } - if (len >= size) { - Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size); - } - Q_strncpyz (dest, bigbuffer, size ); -} - - -/* -============ -va - -does a varargs printf into a temp buffer, so I don't need to have -varargs versions of all text functions. -FIXME: make this buffer size safe someday -============ -*/ -char * QDECL va( char *format, ... ) { - va_list argptr; - static char string[2][32000]; // in case va is called by nested functions - static int index = 0; - char *buf; - - buf = string[index & 1]; - index++; - - va_start (argptr, format); - vsprintf (buf, format,argptr); - va_end (argptr); - - return buf; -} - - -/* -===================================================================== - - INFO STRINGS - -===================================================================== -*/ - -/* -=============== -Info_ValueForKey - -Searches the string for the given -key and returns the associated value, or an empty string. -FIXME: overflow check? -=============== -*/ -char *Info_ValueForKey( const char *s, const char *key ) { - char pkey[MAX_INFO_KEY]; - static char value[2][MAX_INFO_VALUE]; // use two buffers so compares - // work without stomping on each other - static int valueindex = 0; - char *o; - - if ( !s || !key ) { - return ""; - } - - if ( strlen( s ) >= MAX_INFO_STRING ) { - Com_Error( ERR_DROP, "Info_ValueForKey: oversize infostring" ); - } - - valueindex ^= 1; - if (*s == '\\') - s++; - while (1) - { - o = pkey; - while (*s != '\\') - { - if (!*s) - return ""; - *o++ = *s++; - } - *o = 0; - s++; - - o = value[valueindex]; - - while (*s != '\\' && *s) - { - *o++ = *s++; - } - *o = 0; - - if (!Q_stricmp (key, pkey) ) - return value[valueindex]; - - if (!*s) - break; - s++; - } - - return ""; -} - - -/* -=================== -Info_NextPair - -Used to itterate through all the key/value pairs in an info string -=================== -*/ -void Info_NextPair( const char *(*head), char key[MAX_INFO_KEY], char value[MAX_INFO_VALUE] ) { - char *o; - const char *s; - - s = *head; - - if ( *s == '\\' ) { - s++; - } - key[0] = 0; - value[0] = 0; - - o = key; - while ( *s != '\\' ) { - if ( !*s ) { - *o = 0; - *head = s; - return; - } - *o++ = *s++; - } - *o = 0; - s++; - - o = value; - while ( *s != '\\' && *s ) { - *o++ = *s++; - } - *o = 0; - - *head = s; -} - - -/* -=================== -Info_RemoveKey -=================== -*/ -void Info_RemoveKey( char *s, const char *key ) { - char *start; - char pkey[MAX_INFO_KEY]; - char value[MAX_INFO_VALUE]; - char *o; - - if ( strlen( s ) >= MAX_INFO_STRING ) { - Com_Error( ERR_DROP, "Info_RemoveKey: oversize infostring" ); - } - - if (strchr (key, '\\')) { - return; - } - - while (1) - { - start = s; - if (*s == '\\') - s++; - o = pkey; - while (*s != '\\') - { - if (!*s) - return; - *o++ = *s++; - } - *o = 0; - s++; - - o = value; - while (*s != '\\' && *s) - { - if (!*s) - return; - *o++ = *s++; - } - *o = 0; - - if (!strcmp (key, pkey) ) - { - strcpy (start, s); // remove this part - return; - } - - if (!*s) - return; - } - -} - - -/* -================== -Info_Validate - -Some characters are illegal in info strings because they -can mess up the server's parsing -================== -*/ -qboolean Info_Validate( const char *s ) { - if ( strchr( s, '\"' ) ) { - return qfalse; - } - if ( strchr( s, ';' ) ) { - return qfalse; - } - return qtrue; -} - -/* -================== -Info_SetValueForKey - -Changes or adds a key/value pair -================== -*/ -void Info_SetValueForKey( char *s, const char *key, const char *value ) { - char newi[MAX_INFO_STRING]; - - if ( strlen( s ) >= MAX_INFO_STRING ) { - Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" ); - } - - if (strchr (key, '\\') || strchr (value, '\\')) - { - Com_Printf ("Can't use keys or values with a \\\n"); - return; - } - - if (strchr (key, ';') || strchr (value, ';')) - { - Com_Printf ("Can't use keys or values with a semicolon\n"); - return; - } - - if (strchr (key, '\"') || strchr (value, '\"')) - { - Com_Printf ("Can't use keys or values with a \"\n"); - return; - } - - Info_RemoveKey (s, key); - if (!value || !strlen(value)) - return; - - Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value); - - if (strlen(newi) + strlen(s) > MAX_INFO_STRING) - { - Com_Printf ("Info string length exceeded\n"); - return; - } - - strcat (s, newi); -} - -//==================================================================== - - -/* -=============== -ParseHex -=============== -*/ -int ParseHex( const char *text ) { - int value; - int c; - - value = 0; - while ( ( c = *text++ ) != 0 ) { - if ( c >= '0' && c <= '9' ) { - value = value * 16 + c - '0'; - continue; - } - if ( c >= 'a' && c <= 'f' ) { - value = value * 16 + 10 + c - 'a'; - continue; - } - if ( c >= 'A' && c <= 'F' ) { - value = value * 16 + 10 + c - 'A'; - continue; - } - } - - return value; -} +/* +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 +*/ + +// q_shared.c -- stateless support routines that are included in each code dll +#include "q_shared.h" + +/* +============================================================================ + +GROWLISTS + +============================================================================ +*/ + +// malloc / free all in one place for debugging +extern "C" void *Com_Allocate( int bytes ); +extern "C" void Com_Dealloc( void *ptr ); + +void Com_InitGrowList( growList_t *list, int maxElements ) { + list->maxElements = maxElements; + list->currentElements = 0; + list->elements = (void **)Com_Allocate( list->maxElements * sizeof( void * ) ); +} + +int Com_AddToGrowList( growList_t *list, void *data ) { + void **old; + + if ( list->currentElements != list->maxElements ) { + list->elements[list->currentElements] = data; + return list->currentElements++; + } + + // grow, reallocate and move + old = list->elements; + + if ( list->maxElements < 0 ) { + Com_Error( ERR_FATAL, "Com_AddToGrowList: maxElements = %i", list->maxElements ); + } + + if ( list->maxElements == 0 ) { + // initialize the list to hold 100 elements + Com_InitGrowList( list, 100 ); + return Com_AddToGrowList( list, data ); + } + + list->maxElements *= 2; + + Com_DPrintf( "Resizing growlist to %i maxElements\n", list->maxElements ); + + list->elements = (void **)Com_Allocate( list->maxElements * sizeof( void * ) ); + + if ( !list->elements ) { + Com_Error( ERR_DROP, "Growlist alloc failed" ); + } + + memcpy( list->elements, old, list->currentElements * sizeof( void * ) ); + + Com_Dealloc( old ); + + return Com_AddToGrowList( list, data ); +} + +void *Com_GrowListElement( const growList_t *list, int index ) { + if ( index < 0 || index >= list->currentElements ) { + Com_Error( ERR_DROP, "Com_GrowListElement: %i out of range of %i", + index, list->currentElements ); + } + return list->elements[index]; +} + +int Com_IndexForGrowListElement( const growList_t *list, const void *element ) { + int i; + + for ( i = 0 ; i < list->currentElements ; i++ ) { + if ( list->elements[i] == element ) { + return i; + } + } + return -1; +} + +//============================================================================ + + +float Com_Clamp( float min, float max, float value ) { + if ( value < min ) { + return min; + } + if ( value > max ) { + return max; + } + return value; +} + +/* +============ +Com_StringContains +============ +*/ +const char *Com_StringContains( const char *str1, const char *str2, int casesensitive) { + int len, i, j; + + len = strlen(str1) - strlen(str2); + for (i = 0; i <= len; i++, str1++) { + for (j = 0; str2[j]; j++) { + if (casesensitive) { + if (str1[j] != str2[j]) { + break; + } + } + else { + if (toupper(str1[j]) != toupper(str2[j])) { + break; + } + } + } + if (!str2[j]) { + return str1; + } + } + return NULL; +} + +/* +============ +Com_Filter +============ +*/ +int Com_Filter( const char *filter, const char *name, int casesensitive) +{ + char buf[MAX_TOKEN_CHARS]; + const char *ptr; + int i, found; + + while(*filter) { + if (*filter == '*') { + filter++; + for (i = 0; *filter; i++) { + if (*filter == '*' || *filter == '?') break; + buf[i] = *filter; + filter++; + } + buf[i] = '\0'; + if (strlen(buf)) { + ptr = Com_StringContains(name, buf, casesensitive); + if (!ptr) return qfalse; + name = ptr + strlen(buf); + } + } + else if (*filter == '?') { + filter++; + name++; + } + else if (*filter == '[' && *(filter+1) == '[') { + filter++; + } + else if (*filter == '[') { + filter++; + found = qfalse; + while(*filter && !found) { + if (*filter == ']' && *(filter+1) != ']') break; + if (*(filter+1) == '-' && *(filter+2) && (*(filter+2) != ']' || *(filter+3) == ']')) { + if (casesensitive) { + if (*name >= *filter && *name <= *(filter+2)) found = qtrue; + } + else { + if (toupper(*name) >= toupper(*filter) && + toupper(*name) <= toupper(*(filter+2))) found = qtrue; + } + filter += 3; + } + else { + if (casesensitive) { + if (*filter == *name) found = qtrue; + } + else { + if (toupper(*filter) == toupper(*name)) found = qtrue; + } + filter++; + } + } + if (!found) return qfalse; + while(*filter) { + if (*filter == ']' && *(filter+1) != ']') break; + filter++; + } + filter++; + name++; + } + else { + if (casesensitive) { + if (*filter != *name) return qfalse; + } + else { + if (toupper(*filter) != toupper(*name)) return qfalse; + } + filter++; + name++; + } + } + return qtrue; +} + + +/* +================ +Com_HashString + +================ +*/ +int Com_HashString( const char *fname ) { + int i; + long hash; + char letter; + + hash = 0; + i = 0; + while (fname[i] != '\0') { + letter = tolower(fname[i]); + if (letter =='.') break; // don't include extension + if (letter =='\\') letter = '/'; // damn path names + hash+=(long)(letter)*(i+119); + i++; + } + hash &= (FILE_HASH_SIZE-1); + return hash; +} + + +/* +============ +Com_SkipPath +============ +*/ +char *Com_SkipPath (char *pathname) +{ + char *last; + + last = pathname; + while (*pathname) + { + if (*pathname=='/') + last = pathname+1; + pathname++; + } + return last; +} + +/* +============ +Com_StripExtension +============ +*/ +void Com_StripExtension( const char *in, char *out ) { + while ( *in && *in != '.' ) { + *out++ = *in++; + } + *out = 0; +} + + +/* +================== +Com_DefaultExtension +================== +*/ +void Com_DefaultExtension (char *path, int maxSize, const char *extension ) { + char oldPath[MAX_QPATH]; + char *src; + +// +// if path doesn't have a .EXT, append extension +// (extension should include the .) +// + src = path + strlen(path) - 1; + + while (*src != '/' && src != path) { + if ( *src == '.' ) { + return; // it has an extension + } + src--; + } + + Q_strncpyz( oldPath, path, sizeof( oldPath ) ); + Com_sprintf( path, maxSize, "%s%s", oldPath, extension ); +} + +/* +============================================================================ + + BYTE ORDER FUNCTIONS + +============================================================================ +*/ + +// can't just use function pointers, or dll linkage can +// mess up when qcommon is included in multiple places +static short (*_BigShort) (short l); +static short (*_LittleShort) (short l); +static int (*_BigLong) (int l); +static int (*_LittleLong) (int l); +static float (*_BigFloat) (float l); +static float (*_LittleFloat) (float l); + +short BigShort(short l){return _BigShort(l);} +short LittleShort(short l) {return _LittleShort(l);} +int BigLong (int l) {return _BigLong(l);} +int LittleLong (int l) {return _LittleLong(l);} +float BigFloat (float l) {return _BigFloat(l);} +float LittleFloat (float l) {return _LittleFloat(l);} + +short ShortSwap (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short ShortNoSwap (short l) +{ + return l; +} + +int LongSwap (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int LongNoSwap (int l) +{ + return l; +} + +float FloatSwap (float f) +{ + union + { + float f; + byte b[4]; + } dat1, dat2; + + + dat1.f = f; + dat2.b[0] = dat1.b[3]; + dat2.b[1] = dat1.b[2]; + dat2.b[2] = dat1.b[1]; + dat2.b[3] = dat1.b[0]; + return dat2.f; +} + +float FloatNoSwap (float f) +{ + return f; +} + +/* +================ +Swap_Init +================ +*/ +void Swap_Init (void) +{ + byte swaptest[2] = {1,0}; + +// set the byte swapping variables in a portable manner + if ( *(short *)swaptest == 1) + { + _BigShort = ShortSwap; + _LittleShort = ShortNoSwap; + _BigLong = LongSwap; + _LittleLong = LongNoSwap; + _BigFloat = FloatSwap; + _LittleFloat = FloatNoSwap; + } + else + { + _BigShort = ShortNoSwap; + _LittleShort = ShortSwap; + _BigLong = LongNoSwap; + _LittleLong = LongSwap; + _BigFloat = FloatNoSwap; + _LittleFloat = FloatSwap; + } + +} + +/* +=============== +Com_ParseInfos +=============== +*/ +int Com_ParseInfos( const char *buf, int max, char infos[][MAX_INFO_STRING] ) { + const char *token; + int count; + char key[MAX_TOKEN_CHARS]; + + count = 0; + + while ( 1 ) { + token = Com_Parse( &buf ); + if ( !token[0] ) { + break; + } + if ( strcmp( token, "{" ) ) { + Com_Printf( "Missing { in info file\n" ); + break; + } + + if ( count == max ) { + Com_Printf( "Max infos exceeded\n" ); + break; + } + + infos[count][0] = 0; + while ( 1 ) { + token = Com_Parse( &buf ); + if ( !token[0] ) { + Com_Printf( "Unexpected end of info file\n" ); + break; + } + if ( !strcmp( token, "}" ) ) { + break; + } + Q_strncpyz( key, token, sizeof( key ) ); + + token = Com_ParseOnLine( &buf ); + if ( !token[0] ) { + token = ""; + } + Info_SetValueForKey( infos[count], key, token ); + } + count++; + } + + return count; +} + + + +/* +============================================================================ + + LIBRARY REPLACEMENT FUNCTIONS + +============================================================================ +*/ + +int Q_isprint( int c ) +{ + if ( c >= 0x20 && c <= 0x7E ) + return ( 1 ); + return ( 0 ); +} + +int Q_islower( int c ) +{ + if (c >= 'a' && c <= 'z') + return ( 1 ); + return ( 0 ); +} + +int Q_isupper( int c ) +{ + if (c >= 'A' && c <= 'Z') + return ( 1 ); + return ( 0 ); +} + +int Q_isalpha( int c ) +{ + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) + return ( 1 ); + return ( 0 ); +} + +char* Q_strrchr( const char* string, int c ) +{ + char cc = c; + char *s; + char *sp=(char *)0; + + s = (char*)string; + + while (*s) + { + if (*s == cc) + sp = s; + s++; + } + if (cc == 0) + sp = s; + + return sp; +} + +/* +============= +Q_strncpyz + +Safe strncpy that ensures a trailing zero +============= +*/ +void Q_strncpyz( char *dest, const char *src, int destsize ) { + if ( !src ) { + Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" ); + } + if ( destsize < 1 ) { + Com_Error(ERR_FATAL,"Q_strncpyz: destsize < 1" ); + } + + strncpy( dest, src, destsize-1 ); + dest[destsize-1] = 0; +} + +int Q_stricmpn (const char *s1, const char *s2, int n) { + int c1, c2; + + do { + c1 = *s1++; + c2 = *s2++; + + if (!n--) { + return 0; // strings are equal until end point + } + + if (c1 != c2) { + if (c1 >= 'a' && c1 <= 'z') { + c1 -= ('a' - 'A'); + } + if (c2 >= 'a' && c2 <= 'z') { + c2 -= ('a' - 'A'); + } + if (c1 != c2) { + return c1 < c2 ? -1 : 1; + } + } + } while (c1); + + return 0; // strings are equal +} + +int Q_strncmp (const char *s1, const char *s2, int n) { + int c1, c2; + + do { + c1 = *s1++; + c2 = *s2++; + + if (!n--) { + return 0; // strings are equal until end point + } + + if (c1 != c2) { + return c1 < c2 ? -1 : 1; + } + } while (c1); + + return 0; // strings are equal +} + +int Q_stricmp (const char *s1, const char *s2) { + return Q_stricmpn (s1, s2, 99999); +} + + +char *Q_strlwr( char *s1 ) { + char *s; + + s = s1; + while ( *s ) { + *s = tolower(*s); + s++; + } + return s1; +} + +char *Q_strupr( char *s1 ) { + char *s; + + s = s1; + while ( *s ) { + *s = toupper(*s); + s++; + } + return s1; +} + + +// never goes past bounds or leaves without a terminating 0 +void Q_strcat( char *dest, int size, const char *src ) { + int l1; + + l1 = strlen( dest ); + if ( l1 >= size ) { + Com_Error( ERR_FATAL, "Q_strcat: already overflowed" ); + } + Q_strncpyz( dest + l1, src, size - l1 ); +} + + +int Q_PrintStrlen( const char *string ) { + int len; + const char *p; + + if( !string ) { + return 0; + } + + len = 0; + p = string; + while( *p ) { + if( Q_IsColorString( p ) ) { + p += 2; + continue; + } + p++; + len++; + } + + return len; +} + + +char *Q_CleanStr( char *string ) { + char* d; + char* s; + int c; + + s = string; + d = string; + while ((c = *s) != 0 ) { + if ( Q_IsColorString( s ) ) { + s++; + } + else if ( c >= 0x20 && c <= 0x7E ) { + *d++ = c; + } + s++; + } + *d = '\0'; + + return string; +} + + +void QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) { + int len; + va_list argptr; + char bigbuffer[32000]; // big, but small enough to fit in PPC stack + + va_start (argptr,fmt); + len = vsprintf (bigbuffer,fmt,argptr); + va_end (argptr); + if ( len >= sizeof( bigbuffer ) ) { + Com_Error( ERR_FATAL, "Com_sprintf: overflowed bigbuffer" ); + } + if (len >= size) { + Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size); + } + Q_strncpyz (dest, bigbuffer, size ); +} + + +/* +============ +va + +does a varargs printf into a temp buffer, so I don't need to have +varargs versions of all text functions. +FIXME: make this buffer size safe someday +============ +*/ +char * QDECL va( char *format, ... ) { + va_list argptr; + static char string[2][32000]; // in case va is called by nested functions + static int index = 0; + char *buf; + + buf = string[index & 1]; + index++; + + va_start (argptr, format); + vsprintf (buf, format,argptr); + va_end (argptr); + + return buf; +} + + +/* +===================================================================== + + INFO STRINGS + +===================================================================== +*/ + +/* +=============== +Info_ValueForKey + +Searches the string for the given +key and returns the associated value, or an empty string. +FIXME: overflow check? +=============== +*/ +char *Info_ValueForKey( const char *s, const char *key ) { + char pkey[MAX_INFO_KEY]; + static char value[2][MAX_INFO_VALUE]; // use two buffers so compares + // work without stomping on each other + static int valueindex = 0; + char *o; + + if ( !s || !key ) { + return ""; + } + + if ( strlen( s ) >= MAX_INFO_STRING ) { + Com_Error( ERR_DROP, "Info_ValueForKey: oversize infostring" ); + } + + valueindex ^= 1; + if (*s == '\\') + s++; + while (1) + { + o = pkey; + while (*s != '\\') + { + if (!*s) + return ""; + *o++ = *s++; + } + *o = 0; + s++; + + o = value[valueindex]; + + while (*s != '\\' && *s) + { + *o++ = *s++; + } + *o = 0; + + if (!Q_stricmp (key, pkey) ) + return value[valueindex]; + + if (!*s) + break; + s++; + } + + return ""; +} + + +/* +=================== +Info_NextPair + +Used to itterate through all the key/value pairs in an info string +=================== +*/ +void Info_NextPair( const char *(*head), char key[MAX_INFO_KEY], char value[MAX_INFO_VALUE] ) { + char *o; + const char *s; + + s = *head; + + if ( *s == '\\' ) { + s++; + } + key[0] = 0; + value[0] = 0; + + o = key; + while ( *s != '\\' ) { + if ( !*s ) { + *o = 0; + *head = s; + return; + } + *o++ = *s++; + } + *o = 0; + s++; + + o = value; + while ( *s != '\\' && *s ) { + *o++ = *s++; + } + *o = 0; + + *head = s; +} + + +/* +=================== +Info_RemoveKey +=================== +*/ +void Info_RemoveKey( char *s, const char *key ) { + char *start; + char pkey[MAX_INFO_KEY]; + char value[MAX_INFO_VALUE]; + char *o; + + if ( strlen( s ) >= MAX_INFO_STRING ) { + Com_Error( ERR_DROP, "Info_RemoveKey: oversize infostring" ); + } + + if (strchr (key, '\\')) { + return; + } + + while (1) + { + start = s; + if (*s == '\\') + s++; + o = pkey; + while (*s != '\\') + { + if (!*s) + return; + *o++ = *s++; + } + *o = 0; + s++; + + o = value; + while (*s != '\\' && *s) + { + if (!*s) + return; + *o++ = *s++; + } + *o = 0; + + if (!strcmp (key, pkey) ) + { + strcpy (start, s); // remove this part + return; + } + + if (!*s) + return; + } + +} + + +/* +================== +Info_Validate + +Some characters are illegal in info strings because they +can mess up the server's parsing +================== +*/ +qboolean Info_Validate( const char *s ) { + if ( strchr( s, '\"' ) ) { + return qfalse; + } + if ( strchr( s, ';' ) ) { + return qfalse; + } + return qtrue; +} + +/* +================== +Info_SetValueForKey + +Changes or adds a key/value pair +================== +*/ +void Info_SetValueForKey( char *s, const char *key, const char *value ) { + char newi[MAX_INFO_STRING]; + + if ( strlen( s ) >= MAX_INFO_STRING ) { + Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" ); + } + + if (strchr (key, '\\') || strchr (value, '\\')) + { + Com_Printf ("Can't use keys or values with a \\\n"); + return; + } + + if (strchr (key, ';') || strchr (value, ';')) + { + Com_Printf ("Can't use keys or values with a semicolon\n"); + return; + } + + if (strchr (key, '\"') || strchr (value, '\"')) + { + Com_Printf ("Can't use keys or values with a \"\n"); + return; + } + + Info_RemoveKey (s, key); + if (!value || !strlen(value)) + return; + + Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value); + + if (strlen(newi) + strlen(s) > MAX_INFO_STRING) + { + Com_Printf ("Info string length exceeded\n"); + return; + } + + strcat (s, newi); +} + +//==================================================================== + + +/* +=============== +ParseHex +=============== +*/ +int ParseHex( const char *text ) { + int value; + int c; + + value = 0; + while ( ( c = *text++ ) != 0 ) { + if ( c >= '0' && c <= '9' ) { + value = value * 16 + c - '0'; + continue; + } + if ( c >= 'a' && c <= 'f' ) { + value = value * 16 + 10 + c - 'a'; + continue; + } + if ( c >= 'A' && c <= 'F' ) { + value = value * 16 + 10 + c - 'A'; + continue; + } + } + + return value; +} diff --git a/libs/splines/splines.cpp b/libs/splines/splines.cpp index 321f1fd9..885dbc10 100644 --- a/libs/splines/splines.cpp +++ b/libs/splines/splines.cpp @@ -1,1421 +1,1421 @@ -/* -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 -*/ - -#include "q_shared.h" -#include "splines.h" - -extern "C" { -int FS_Write( const void *buffer, int len, fileHandle_t h ); -int FS_ReadFile( const char *qpath, void **buffer ); -void FS_FreeFile( void *buffer ); -fileHandle_t FS_FOpenFileWrite( const char *filename ); -void FS_FCloseFile( fileHandle_t f ); -void Cbuf_AddText( const char *text ); -void Cbuf_Execute (void); -} - -float Q_fabs( float f ) { - int tmp = * ( int * ) &f; - tmp &= 0x7FFFFFFF; - return * ( float * ) &tmp; -} - -// (SA) making a list of cameras so I can use -// the splines as targets for other things. -// Certainly better ways to do this, but this lets -// me get underway quickly with ents that need spline -// targets. -#define MAX_CAMERAS 64 - -idCameraDef camera[MAX_CAMERAS]; - -extern "C" { -qboolean loadCamera(int camNum, const char *name) { - if(camNum < 0 || camNum >= MAX_CAMERAS ) - return qfalse; - camera[camNum].clear(); - return (qboolean)camera[camNum].load(name); -} - -qboolean getCameraInfo(int camNum, int time, float *origin, float *angles, float *fov) { - idVec3 dir, org; - if(camNum < 0 || camNum >= MAX_CAMERAS ) - return qfalse; - org[0] = origin[0]; - org[1] = origin[1]; - org[2] = origin[2]; - if (camera[camNum].getCameraInfo(time, org, dir, fov)) { - origin[0] = org[0]; - origin[1] = org[1]; - origin[2] = org[2]; - angles[1] = atan2 (dir[1], dir[0])*180/3.14159; - angles[0] = asin (dir[2])*180/3.14159; - return qtrue; - } - return qfalse; -} - -void startCamera(int camNum, int time) { - if(camNum < 0 || camNum >= MAX_CAMERAS ) - return; - camera[camNum].startCamera(time); -} - -} - - -//#include "../shared/windings.h" -//#include "../qcommon/qcommon.h" -//#include "../sys/sys_public.h" -//#include "../game/game_entity.h" - -idCameraDef splineList; -idCameraDef *g_splineList = &splineList; - -idVec3 idSplineList::zero(0,0,0); - -void glLabeledPoint(idVec3 &color, idVec3 &point, float size, const char *label) { - qglColor3fv(color); - qglPointSize(size); - qglBegin(GL_POINTS); - qglVertex3fv(point); - qglEnd(); - idVec3 v = point; - v.x += 1; - v.y += 1; - v.z += 1; - qglRasterPos3fv (v); - qglCallLists (strlen(label), GL_UNSIGNED_BYTE, label); -} - - -void glBox(idVec3 &color, idVec3 &point, float size) { - idVec3 mins(point); - idVec3 maxs(point); - mins[0] -= size; - mins[1] += size; - mins[2] -= size; - maxs[0] += size; - maxs[1] -= size; - maxs[2] += size; - qglColor3fv(color); - qglBegin(GL_LINE_LOOP); - qglVertex3f(mins[0],mins[1],mins[2]); - qglVertex3f(maxs[0],mins[1],mins[2]); - qglVertex3f(maxs[0],maxs[1],mins[2]); - qglVertex3f(mins[0],maxs[1],mins[2]); - qglEnd(); - qglBegin(GL_LINE_LOOP); - qglVertex3f(mins[0],mins[1],maxs[2]); - qglVertex3f(maxs[0],mins[1],maxs[2]); - qglVertex3f(maxs[0],maxs[1],maxs[2]); - qglVertex3f(mins[0],maxs[1],maxs[2]); - qglEnd(); - - qglBegin(GL_LINES); - qglVertex3f(mins[0],mins[1],mins[2]); - qglVertex3f(mins[0],mins[1],maxs[2]); - qglVertex3f(mins[0],maxs[1],maxs[2]); - qglVertex3f(mins[0],maxs[1],mins[2]); - qglVertex3f(maxs[0],mins[1],mins[2]); - qglVertex3f(maxs[0],mins[1],maxs[2]); - qglVertex3f(maxs[0],maxs[1],maxs[2]); - qglVertex3f(maxs[0],maxs[1],mins[2]); - qglEnd(); - -} - -void splineTest() { - //g_splineList->load("p:/doom/base/maps/test_base1.camera"); -} - -void splineDraw() { - //g_splineList->addToRenderer(); -} - - -//extern void D_DebugLine( const idVec3 &color, const idVec3 &start, const idVec3 &end ); - -void debugLine(idVec3 &color, float x, float y, float z, float x2, float y2, float z2) { - idVec3 from(x, y, z); - idVec3 to(x2, y2, z2); - //D_DebugLine(color, from, to); -} - -void idSplineList::addToRenderer() { - - if (controlPoints.Num() == 0) { - return; - } - - idVec3 mins, maxs; - idVec3 yellow(1.0, 1.0, 0); - idVec3 white(1.0, 1.0, 1.0); - int i; - - for(i = 0; i < controlPoints.Num(); i++) { - VectorCopy(*controlPoints[i], mins); - VectorCopy(mins, maxs); - mins[0] -= 8; - mins[1] += 8; - mins[2] -= 8; - maxs[0] += 8; - maxs[1] -= 8; - maxs[2] += 8; - debugLine( yellow, mins[0], mins[1], mins[2], maxs[0], mins[1], mins[2]); - debugLine( yellow, maxs[0], mins[1], mins[2], maxs[0], maxs[1], mins[2]); - debugLine( yellow, maxs[0], maxs[1], mins[2], mins[0], maxs[1], mins[2]); - debugLine( yellow, mins[0], maxs[1], mins[2], mins[0], mins[1], mins[2]); - - debugLine( yellow, mins[0], mins[1], maxs[2], maxs[0], mins[1], maxs[2]); - debugLine( yellow, maxs[0], mins[1], maxs[2], maxs[0], maxs[1], maxs[2]); - debugLine( yellow, maxs[0], maxs[1], maxs[2], mins[0], maxs[1], maxs[2]); - debugLine( yellow, mins[0], maxs[1], maxs[2], mins[0], mins[1], maxs[2]); - - } - - int step = 0; - idVec3 step1; - for(i = 3; i < controlPoints.Num(); i++) { - for (float tension = 0.0f; tension < 1.001f; tension += 0.1f) { - float x = 0; - float y = 0; - float z = 0; - for (int j = 0; j < 4; j++) { - x += controlPoints[i - (3 - j)]->x * calcSpline(j, tension); - y += controlPoints[i - (3 - j)]->y * calcSpline(j, tension); - z += controlPoints[i - (3 - j)]->z * calcSpline(j, tension); - } - if (step == 0) { - step1[0] = x; - step1[1] = y; - step1[2] = z; - step = 1; - } else { - debugLine( white, step1[0], step1[1], step1[2], x, y, z); - step = 0; - } - - } - } -} - -void idSplineList::buildSpline() { - //int start = Sys_Milliseconds(); - clearSpline(); - for(int i = 3; i < controlPoints.Num(); i++) { - for (float tension = 0.0f; tension < 1.001f; tension += granularity) { - float x = 0; - float y = 0; - float z = 0; - for (int j = 0; j < 4; j++) { - x += controlPoints[i - (3 - j)]->x * calcSpline(j, tension); - y += controlPoints[i - (3 - j)]->y * calcSpline(j, tension); - z += controlPoints[i - (3 - j)]->z * calcSpline(j, tension); - } - splinePoints.Append(new idVec3(x, y, z)); - } - } - dirty = false; - //Com_Printf("Spline build took %f seconds\n", (float)(Sys_Milliseconds() - start) / 1000); -} - - -void idSplineList::draw(bool editMode) { - int i; - idVec4 yellow(1, 1, 0, 1); - - if (controlPoints.Num() == 0) { - return; - } - - if (dirty) { - buildSpline(); - } - - - qglColor3fv(controlColor); - qglPointSize(5); - - qglBegin(GL_POINTS); - for (i = 0; i < controlPoints.Num(); i++) { - qglVertex3fv(*controlPoints[i]); - } - qglEnd(); - - if (editMode) { - for(i = 0; i < controlPoints.Num(); i++) { - glBox(activeColor, *controlPoints[i], 4); - } - } - - //Draw the curve - qglColor3fv(pathColor); - qglBegin(GL_LINE_STRIP); - int count = splinePoints.Num(); - for (i = 0; i < count; i++) { - qglVertex3fv(*splinePoints[i]); - } - qglEnd(); - - if (editMode) { - qglColor3fv(segmentColor); - qglPointSize(3); - qglBegin(GL_POINTS); - for (i = 0; i < count; i++) { - qglVertex3fv(*splinePoints[i]); - } - qglEnd(); - } - if (count > 0) { - //assert(activeSegment >=0 && activeSegment < count); - if (activeSegment >=0 && activeSegment < count) { - glBox(activeColor, *splinePoints[activeSegment], 6); - glBox(yellow, *splinePoints[activeSegment], 8); - } - } - -} - -float idSplineList::totalDistance() { - - // FIXME: save dist and return - // - if (controlPoints.Num() == 0) { - return 0.0; - } - - if (dirty) { - buildSpline(); - } - - float dist = 0.0; - idVec3 temp; - int count = splinePoints.Num(); - for(int i = 1; i < count; i++) { - temp = *splinePoints[i-1]; - temp -= *splinePoints[i]; - dist += temp.Length(); - } - return dist; -} - -void idSplineList::initPosition(long bt, long totalTime) { - - if (dirty) { - buildSpline(); - } - - if (splinePoints.Num() == 0) { - return; - } - - baseTime = bt; - time = totalTime; - - // calc distance to travel ( this will soon be broken into time segments ) - splineTime.Clear(); - splineTime.Append(bt); - double dist = totalDistance(); - double distSoFar = 0.0; - idVec3 temp; - int count = splinePoints.Num(); - //for(int i = 2; i < count - 1; i++) { - for(int i = 1; i < count; i++) { - temp = *splinePoints[i-1]; - temp -= *splinePoints[i]; - distSoFar += temp.Length(); - double percent = distSoFar / dist; - percent *= totalTime; - splineTime.Append(percent + bt); - } - assert(splineTime.Num() == splinePoints.Num()); - activeSegment = 0; -} - - - -float idSplineList::calcSpline(int step, float tension) { - switch(step) { - case 0: return (pow(1 - tension, 3)) / 6; - case 1: return (3 * pow(tension, 3) - 6 * pow(tension, 2) + 4) / 6; - case 2: return (-3 * pow(tension, 3) + 3 * pow(tension, 2) + 3 * tension + 1) / 6; - case 3: return pow(tension, 3) / 6; - } - return 0.0; -} - - - -void idSplineList::updateSelection(const idVec3 &move) { - if (selected) { - dirty = true; - VectorAdd(*selected, move, *selected); - } -} - - -void idSplineList::setSelectedPoint(idVec3 *p) { - if (p) { - p->Snap(); - for(int i = 0; i < controlPoints.Num(); i++) { - if (*p == *controlPoints[i]) { - selected = controlPoints[i]; - } - } - } else { - selected = NULL; - } -} - -const idVec3 *idSplineList::getPosition(long t) { - static idVec3 interpolatedPos; - static long lastTime = -1; - - int count = splineTime.Num(); - if (count == 0) { - return &zero; - } - -// Com_Printf("Time: %d\n", t); - assert(splineTime.Num() == splinePoints.Num()); - - while (activeSegment < count) { - if (splineTime[activeSegment] >= t) { - if (activeSegment > 0 && activeSegment < count - 1) { - double timeHi = splineTime[activeSegment + 1]; - double timeLo = splineTime[activeSegment - 1]; - double percent = (timeHi - t) / (timeHi - timeLo); - // pick two bounding points - idVec3 v1 = *splinePoints[activeSegment-1]; - idVec3 v2 = *splinePoints[activeSegment+1]; - v2 *= (1.0 - percent); - v1 *= percent; - v2 += v1; - interpolatedPos = v2; - return &interpolatedPos; - } - return splinePoints[activeSegment]; - } else { - activeSegment++; - } - } - return splinePoints[count-1]; -} - -void idSplineList::parse(const char *(*text) ) { - const char *token; - //Com_MatchToken( text, "{" ); - do { - token = Com_Parse( text ); - - if ( !token[0] ) { - break; - } - if ( !Q_stricmp (token, "}") ) { - break; - } - - do { - // if token is not a brace, it is a key for a key/value pair - if ( !token[0] || !Q_stricmp (token, "(") || !Q_stricmp(token, "}")) { - break; - } - - Com_UngetToken(); - idStr key = Com_ParseOnLine(text); - const char *token = Com_Parse(text); - if (Q_stricmp(key.c_str(), "granularity") == 0) { - granularity = atof(token); - } else if (Q_stricmp(key.c_str(), "name") == 0) { - name = token; - } - token = Com_Parse(text); - - } while (1); - - if ( !Q_stricmp (token, "}") ) { - break; - } - - Com_UngetToken(); - // read the control point - idVec3 point; - Com_Parse1DMatrix( text, 3, point ); - addPoint(point.x, point.y, point.z); - } while (1); - - //Com_UngetToken(); - //Com_MatchToken( text, "}" ); - dirty = true; -} - -void idSplineList::write(fileHandle_t file, const char *p) { - idStr s = va("\t\t%s {\n", p); - FS_Write(s.c_str(), s.length(), file); - //s = va("\t\tname %s\n", name.c_str()); - //FS_Write(s.c_str(), s.length(), file); - s = va("\t\t\tgranularity %f\n", granularity); - FS_Write(s.c_str(), s.length(), file); - int count = controlPoints.Num(); - for (int i = 0; i < count; i++) { - s = va("\t\t\t( %f %f %f )\n", controlPoints[i]->x, controlPoints[i]->y, controlPoints[i]->z); - FS_Write(s.c_str(), s.length(), file); - } - s = "\t\t}\n"; - FS_Write(s.c_str(), s.length(), file); -} - - -void idCameraDef::getActiveSegmentInfo(int segment, idVec3 &origin, idVec3 &direction, float *fov) { -#if 0 - if (!cameraSpline.validTime()) { - buildCamera(); - } - double d = (double)segment / numSegments(); - getCameraInfo(d * totalTime * 1000, origin, direction, fov); -#endif -/* - if (!cameraSpline.validTime()) { - buildCamera(); - } - origin = *cameraSpline.getSegmentPoint(segment); - - - idVec3 temp; - - int numTargets = getTargetSpline()->controlPoints.Num(); - int count = cameraSpline.splineTime.Num(); - if (numTargets == 0) { - // follow the path - if (cameraSpline.getActiveSegment() < count - 1) { - temp = *cameraSpline.splinePoints[cameraSpline.getActiveSegment()+1]; - } - } else if (numTargets == 1) { - temp = *getTargetSpline()->controlPoints[0]; - } else { - temp = *getTargetSpline()->getSegmentPoint(segment); - } - - temp -= origin; - temp.Normalize(); - direction = temp; -*/ -} - -bool idCameraDef::getCameraInfo(long time, idVec3 &origin, idVec3 &direction, float *fv) { - - char buff[1024]; - - if ((time - startTime) / 1000 > totalTime) { - return false; - } - - - for (int i = 0; i < events.Num(); i++) { - if (time >= startTime + events[i]->getTime() && !events[i]->getTriggered()) { - events[i]->setTriggered(true); - if (events[i]->getType() == idCameraEvent::EVENT_TARGET) { - setActiveTargetByName(events[i]->getParam()); - getActiveTarget()->start(startTime + events[i]->getTime()); - //Com_Printf("Triggered event switch to target: %s\n",events[i]->getParam()); - } else if (events[i]->getType() == idCameraEvent::EVENT_TRIGGER) { - //idEntity *ent = NULL; - //ent = level.FindTarget( ent, events[i]->getParam()); - //if (ent) { - // ent->signal( SIG_TRIGGER ); - // ent->ProcessEvent( &EV_Activate, world ); - //} - } else if (events[i]->getType() == idCameraEvent::EVENT_FOV) { - memset(buff, 0, sizeof(buff)); - strcpy(buff, events[i]->getParam()); - const char *param1 = strtok(buff, " \t,\0"); - const char *param2 = strtok(NULL, " \t,\0"); - float len = (param2) ? atof(param2) : 0; - float newfov = (param1) ? atof(param1) : 90; - fov.reset(fov.getFOV(time), newfov, time, len); - //*fv = fov = atof(events[i]->getParam()); - } else if (events[i]->getType() == idCameraEvent::EVENT_FADEIN) { - float time = atof(events[i]->getParam()); - Cbuf_AddText(va("fade 0 0 0 0 %f", time)); - Cbuf_Execute(); - } else if (events[i]->getType() == idCameraEvent::EVENT_FADEOUT) { - float time = atof(events[i]->getParam()); - Cbuf_AddText(va("fade 0 0 0 255 %f", time)); - Cbuf_Execute(); - } else if (events[i]->getType() == idCameraEvent::EVENT_CAMERA) { - memset(buff, 0, sizeof(buff)); - strcpy(buff, events[i]->getParam()); - const char *param1 = strtok(buff, " \t,\0"); - const char *param2 = strtok(NULL, " \t,\0"); - - if(param2) { - loadCamera(atoi(param1), va("cameras/%s.camera", param2)); - startCamera(time); - } else { - loadCamera(0, va("cameras/%s.camera", events[i]->getParam())); - startCamera(time); - } - return true; - } else if (events[i]->getType() == idCameraEvent::EVENT_STOP) { - return false; - } - } - } - - origin = *cameraPosition->getPosition(time); - - *fv = fov.getFOV(time); - - idVec3 temp = origin; - - int numTargets = targetPositions.Num(); - if (numTargets == 0) { -/* - // follow the path - if (cameraSpline.getActiveSegment() < count - 1) { - temp = *cameraSpline.splinePoints[cameraSpline.getActiveSegment()+1]; - if (temp == origin) { - int index = cameraSpline.getActiveSegment() + 2; - while (temp == origin && index < count - 1) { - temp = *cameraSpline.splinePoints[index++]; - } - } - } -*/ - } else { - if( getActiveTarget()->numPoints() > 0 ) { - temp = *getActiveTarget()->getPosition(time); - } - } - - temp -= origin; - temp.Normalize(); - direction = temp; - - return true; -} - -bool idCameraDef::waitEvent(int index) { - //for (int i = 0; i < events.Num(); i++) { - // if (events[i]->getSegment() == index && events[i]->getType() == idCameraEvent::EVENT_WAIT) { - // return true; - // } - //} - return false; -} - - -#define NUM_CCELERATION_SEGS 10 -#define CELL_AMT 5 - -void idCameraDef::buildCamera() { - int i; - int lastSwitch = 0; - idList waits; - idList targets; - - totalTime = baseTime; - cameraPosition->setTime((long)totalTime * 1000); - // we have a base time layout for the path and the target path - // now we need to layer on any wait or speed changes - for (i = 0; i < events.Num(); i++) { - idCameraEvent *ev = events[i]; - events[i]->setTriggered(false); - switch (events[i]->getType()) { - case idCameraEvent::EVENT_TARGET : { - targets.Append(i); - break; - } - case idCameraEvent::EVENT_FEATHER : { - long startTime = 0; - float speed = 0; - long loopTime = 10; - float stepGoal = cameraPosition->getBaseVelocity() / (1000 / loopTime); - while (startTime <= 1000) { - cameraPosition->addVelocity(startTime, loopTime, speed); - speed += stepGoal; - if (speed > cameraPosition->getBaseVelocity()) { - speed = cameraPosition->getBaseVelocity(); - } - startTime += loopTime; - } - - startTime = (long)(totalTime * 1000 - 1000); - long endTime = startTime + 1000; - speed = cameraPosition->getBaseVelocity(); - while (startTime < endTime) { - speed -= stepGoal; - if (speed < 0) { - speed = 0; - } - cameraPosition->addVelocity(startTime, loopTime, speed); - startTime += loopTime; - } - break; - - } - case idCameraEvent::EVENT_WAIT : { - waits.Append(atof(events[i]->getParam())); - - //FIXME: this is quite hacky for Wolf E3, accel and decel needs - // do be parameter based etc.. - long startTime = events[i]->getTime() - 1000; - if (startTime < 0) { - startTime = 0; - } - float speed = cameraPosition->getBaseVelocity(); - long loopTime = 10; - float steps = speed / ((events[i]->getTime() - startTime) / loopTime); - while (startTime <= events[i]->getTime() - loopTime) { - cameraPosition->addVelocity(startTime, loopTime, speed); - speed -= steps; - startTime += loopTime; - } - cameraPosition->addVelocity(events[i]->getTime(), (long)atof(events[i]->getParam()) * 1000, 0); - - startTime = (long)(events[i]->getTime() + atof(events[i]->getParam()) * 1000); - long endTime = startTime + 1000; - speed = 0; - while (startTime <= endTime) { - cameraPosition->addVelocity(startTime, loopTime, speed); - speed += steps; - startTime += loopTime; - } - break; - } - case idCameraEvent::EVENT_TARGETWAIT : { - //targetWaits.Append(i); - break; - } - case idCameraEvent::EVENT_SPEED : { -/* - // take the average delay between up to the next five segments - float adjust = atof(events[i]->getParam()); - int index = events[i]->getSegment(); - total = 0; - count = 0; - - // get total amount of time over the remainder of the segment - for (j = index; j < cameraSpline.numSegments() - 1; j++) { - total += cameraSpline.getSegmentTime(j + 1) - cameraSpline.getSegmentTime(j); - count++; - } - - // multiply that by the adjustment - double newTotal = total * adjust; - // what is the difference.. - newTotal -= total; - totalTime += newTotal / 1000; - - // per segment difference - newTotal /= count; - int additive = newTotal; - - // now propogate that difference out to each segment - for (j = index; j < cameraSpline.numSegments(); j++) { - cameraSpline.addSegmentTime(j, additive); - additive += newTotal; - } - break; -*/ - } - } - } - - - for (i = 0; i < waits.Num(); i++) { - totalTime += waits[i]; - } - - // on a new target switch, we need to take time to this point ( since last target switch ) - // and allocate it across the active target, then reset time to this point - long timeSoFar = 0; - long total = (long)(totalTime * 1000); - for (i = 0; i < targets.Num(); i++) { - long t; - if (i < targets.Num() - 1) { - t = events[targets[i+1]]->getTime(); - } else { - t = total - timeSoFar; - } - // t is how much time to use for this target - setActiveTargetByName(events[targets[i]]->getParam()); - getActiveTarget()->setTime(t); - timeSoFar += t; - } - - -} - -void idCameraDef::startCamera(long t) { - cameraPosition->clearVelocities(); - cameraPosition->start(t); - buildCamera(); - fov.reset(90, 90, t, 0); - //for (int i = 0; i < targetPositions.Num(); i++) { - // targetPositions[i]-> - //} - startTime = t; - cameraRunning = true; -} - - -void idCameraDef::parse(const char *(*text) ) { - - const char *token; - do { - token = Com_Parse( text ); - - if ( !token[0] ) { - break; - } - if ( !Q_stricmp (token, "}") ) { - break; - } - - if (Q_stricmp(token, "time") == 0) { - baseTime = Com_ParseFloat(text); - } - else if (Q_stricmp(token, "camera_fixed") == 0) { - cameraPosition = new idFixedPosition(); - cameraPosition->parse(text); - } - else if (Q_stricmp(token, "camera_interpolated") == 0) { - cameraPosition = new idInterpolatedPosition(); - cameraPosition->parse(text); - } - else if (Q_stricmp(token, "camera_spline") == 0) { - cameraPosition = new idSplinePosition(); - cameraPosition->parse(text); - } - else if (Q_stricmp(token, "target_fixed") == 0) { - idFixedPosition *pos = new idFixedPosition(); - pos->parse(text); - targetPositions.Append(pos); - } - else if (Q_stricmp(token, "target_interpolated") == 0) { - idInterpolatedPosition *pos = new idInterpolatedPosition(); - pos->parse(text); - targetPositions.Append(pos); - } - else if (Q_stricmp(token, "target_spline") == 0) { - idSplinePosition *pos = new idSplinePosition(); - pos->parse(text); - targetPositions.Append(pos); - } - else if (Q_stricmp(token, "fov") == 0) { - fov.parse(text); - } - else if (Q_stricmp(token, "event") == 0) { - idCameraEvent *event = new idCameraEvent(); - event->parse(text); - addEvent(event); - } - - - } while (1); - - if ( !cameraPosition ) { - Com_Printf( "no camera position specified\n" ); - // prevent a crash later on - cameraPosition = new idFixedPosition(); - } - - Com_UngetToken(); - Com_MatchToken( text, "}" ); - -} - -bool idCameraDef::load(const char *filename) { - char *buf; - const char *buf_p; - int length = FS_ReadFile( filename, (void **)&buf ); - if ( !buf ) { - return false; - } - - clear(); - Com_BeginParseSession( filename ); - buf_p = buf; - parse(&buf_p); - Com_EndParseSession(); - FS_FreeFile( buf ); - - return true; -} - -void idCameraDef::save(const char *filename) { - fileHandle_t file = FS_FOpenFileWrite(filename); - if (file) { - int i; - idStr s = "cameraPathDef { \n"; - FS_Write(s.c_str(), s.length(), file); - s = va("\ttime %f\n", baseTime); - FS_Write(s.c_str(), s.length(), file); - - cameraPosition->write(file, va("camera_%s",cameraPosition->typeStr())); - - for (i = 0; i < numTargets(); i++) { - targetPositions[i]->write(file, va("target_%s", targetPositions[i]->typeStr())); - } - - for (i = 0; i < events.Num(); i++) { - events[i]->write(file, "event"); - } - - fov.write(file, "fov"); - - s = "}\n"; - FS_Write(s.c_str(), s.length(), file); - } - FS_FCloseFile(file); -} - -int idCameraDef::sortEvents(const void *p1, const void *p2) { - idCameraEvent *ev1 = (idCameraEvent*)(p1); - idCameraEvent *ev2 = (idCameraEvent*)(p2); - - if (ev1->getTime() > ev2->getTime()) { - return -1; - } - if (ev1->getTime() < ev2->getTime()) { - return 1; - } - return 0; -} - -void idCameraDef::addEvent(idCameraEvent *event) { - events.Append(event); - //events.Sort(&sortEvents); - -} -void idCameraDef::addEvent(idCameraEvent::eventType t, const char *param, long time) { - addEvent(new idCameraEvent(t, param, time)); - buildCamera(); -} - -void idCameraDef::removeEvent(int index) { - events.RemoveIndex(index); - buildCamera(); -} - - -const char *idCameraEvent::eventStr[] = { - "NA", - "WAIT", - "TARGETWAIT", - "SPEED", - "TARGET", - "SNAPTARGET", - "FOV", - "CMD", - "TRIGGER", - "STOP", - "CAMERA", - "FADEOUT", - "FADEIN", - "FEATHER" -}; - -void idCameraEvent::parse(const char *(*text) ) { - const char *token; - Com_MatchToken( text, "{" ); - do { - token = Com_Parse( text ); - - if ( !token[0] ) { - break; - } - if ( !strcmp (token, "}") ) { - break; - } - - // here we may have to jump over brush epairs ( only used in editor ) - do { - // if token is not a brace, it is a key for a key/value pair - if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) { - break; - } - - Com_UngetToken(); - idStr key = Com_ParseOnLine(text); - const char *token = Com_Parse(text); - if (Q_stricmp(key.c_str(), "type") == 0) { - type = static_cast(atoi(token)); - } else if (Q_stricmp(key.c_str(), "param") == 0) { - paramStr = token; - } else if (Q_stricmp(key.c_str(), "time") == 0) { - time = atoi(token); - } - token = Com_Parse(text); - - } while (1); - - if ( !strcmp (token, "}") ) { - break; - } - - } while (1); - - Com_UngetToken(); - Com_MatchToken( text, "}" ); -} - -void idCameraEvent::write(fileHandle_t file, const char *name) { - idStr s = va("\t%s {\n", name); - FS_Write(s.c_str(), s.length(), file); - s = va("\t\ttype %d\n", static_cast(type)); - FS_Write(s.c_str(), s.length(), file); - s = va("\t\tparam \"%s\"\n", paramStr.c_str()); - FS_Write(s.c_str(), s.length(), file); - s = va("\t\ttime %d\n", time); - FS_Write(s.c_str(), s.length(), file); - s = "\t}\n"; - FS_Write(s.c_str(), s.length(), file); -} - - -const char *idCameraPosition::positionStr[] = { - "Fixed", - "Interpolated", - "Spline", -}; - - - -const idVec3 *idInterpolatedPosition::getPosition(long t) { - static idVec3 interpolatedPos; - - float velocity = getVelocity(t); - float timePassed = t - lastTime; - lastTime = t; - - // convert to seconds - timePassed /= 1000; - - float distToTravel = timePassed * velocity; - - idVec3 temp = startPos; - temp -= endPos; - float distance = temp.Length(); - - distSoFar += distToTravel; - float percent = (float)(distSoFar) / distance; - - if (percent > 1.0) { - percent = 1.0; - } else if (percent < 0.0) { - percent = 0.0; - } - - // the following line does a straigt calc on percentage of time - // float percent = (float)(startTime + time - t) / time; - - idVec3 v1 = startPos; - idVec3 v2 = endPos; - v1 *= (1.0 - percent); - v2 *= percent; - v1 += v2; - interpolatedPos = v1; - return &interpolatedPos; -} - - -void idCameraFOV::parse(const char *(*text) ) { - const char *token; - Com_MatchToken( text, "{" ); - do { - token = Com_Parse( text ); - - if ( !token[0] ) { - break; - } - if ( !strcmp (token, "}") ) { - break; - } - - // here we may have to jump over brush epairs ( only used in editor ) - do { - // if token is not a brace, it is a key for a key/value pair - if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) { - break; - } - - Com_UngetToken(); - idStr key = Com_ParseOnLine(text); - const char *token = Com_Parse(text); - if (Q_stricmp(key.c_str(), "fov") == 0) { - fov = atof(token); - } else if (Q_stricmp(key.c_str(), "startFOV") == 0) { - startFOV = atof(token); - } else if (Q_stricmp(key.c_str(), "endFOV") == 0) { - endFOV = atof(token); - } else if (Q_stricmp(key.c_str(), "time") == 0) { - time = atoi(token); - } - token = Com_Parse(text); - - } while (1); - - if ( !strcmp (token, "}") ) { - break; - } - - } while (1); - - Com_UngetToken(); - Com_MatchToken( text, "}" ); -} - -bool idCameraPosition::parseToken(const char *key, const char *(*text)) { - const char *token = Com_Parse(text); - if (Q_stricmp(key, "time") == 0) { - time = atol(token); - return true; - } else if (Q_stricmp(key, "type") == 0) { - type = static_cast(atoi(token)); - return true; - } else if (Q_stricmp(key, "velocity") == 0) { - long t = atol(token); - token = Com_Parse(text); - long d = atol(token); - token = Com_Parse(text); - float s = atof(token); - addVelocity(t, d, s); - return true; - } else if (Q_stricmp(key, "baseVelocity") == 0) { - baseVelocity = atof(token); - return true; - } else if (Q_stricmp(key, "name") == 0) { - name = token; - return true; - } else if (Q_stricmp(key, "time") == 0) { - time = atoi(token); - return true; - } - Com_UngetToken(); - return false; -} - - - -void idFixedPosition::parse(const char *(*text) ) { - const char *token; - Com_MatchToken( text, "{" ); - do { - token = Com_Parse( text ); - - if ( !token[0] ) { - break; - } - if ( !strcmp (token, "}") ) { - break; - } - - // here we may have to jump over brush epairs ( only used in editor ) - do { - // if token is not a brace, it is a key for a key/value pair - if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) { - break; - } - - Com_UngetToken(); - idStr key = Com_ParseOnLine(text); - - const char *token = Com_Parse(text); - if (Q_stricmp(key.c_str(), "pos") == 0) { - Com_UngetToken(); - Com_Parse1DMatrix( text, 3, pos ); - } else { - Com_UngetToken(); - idCameraPosition::parseToken(key.c_str(), text); - } - token = Com_Parse(text); - - } while (1); - - if ( !strcmp (token, "}") ) { - break; - } - - } while (1); - - Com_UngetToken(); - Com_MatchToken( text, "}" ); -} - -void idInterpolatedPosition::parse(const char *(*text) ) { - const char *token; - Com_MatchToken( text, "{" ); - do { - token = Com_Parse( text ); - - if ( !token[0] ) { - break; - } - if ( !strcmp (token, "}") ) { - break; - } - - // here we may have to jump over brush epairs ( only used in editor ) - do { - // if token is not a brace, it is a key for a key/value pair - if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) { - break; - } - - Com_UngetToken(); - idStr key = Com_ParseOnLine(text); - - const char *token = Com_Parse(text); - if (Q_stricmp(key.c_str(), "startPos") == 0) { - Com_UngetToken(); - Com_Parse1DMatrix( text, 3, startPos ); - } else if (Q_stricmp(key.c_str(), "endPos") == 0) { - Com_UngetToken(); - Com_Parse1DMatrix( text, 3, endPos ); - } else { - Com_UngetToken(); - idCameraPosition::parseToken(key.c_str(), text); - } - token = Com_Parse(text); - - } while (1); - - if ( !strcmp (token, "}") ) { - break; - } - - } while (1); - - Com_UngetToken(); - Com_MatchToken( text, "}" ); -} - - -void idSplinePosition::parse(const char *(*text) ) { - const char *token; - Com_MatchToken( text, "{" ); - do { - token = Com_Parse( text ); - - if ( !token[0] ) { - break; - } - if ( !strcmp (token, "}") ) { - break; - } - - // here we may have to jump over brush epairs ( only used in editor ) - do { - // if token is not a brace, it is a key for a key/value pair - if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) { - break; - } - - Com_UngetToken(); - idStr key = Com_ParseOnLine(text); - - const char *token = Com_Parse(text); - if (Q_stricmp(key.c_str(), "target") == 0) { - target.parse(text); - } else { - Com_UngetToken(); - idCameraPosition::parseToken(key.c_str(), text); - } - token = Com_Parse(text); - - } while (1); - - if ( !strcmp (token, "}") ) { - break; - } - - } while (1); - - Com_UngetToken(); - Com_MatchToken( text, "}" ); -} - - - -void idCameraFOV::write(fileHandle_t file, const char *p) { - idStr s = va("\t%s {\n", p); - FS_Write(s.c_str(), s.length(), file); - - s = va("\t\tfov %f\n", fov); - FS_Write(s.c_str(), s.length(), file); - - s = va("\t\tstartFOV %f\n", startFOV); - FS_Write(s.c_str(), s.length(), file); - - s = va("\t\tendFOV %f\n", endFOV); - FS_Write(s.c_str(), s.length(), file); - - s = va("\t\ttime %i\n", time); - FS_Write(s.c_str(), s.length(), file); - - s = "\t}\n"; - FS_Write(s.c_str(), s.length(), file); -} - - -void idCameraPosition::write(fileHandle_t file, const char *p) { - - idStr s = va("\t\ttime %i\n", time); - FS_Write(s.c_str(), s.length(), file); - - s = va("\t\ttype %i\n", static_cast(type)); - FS_Write(s.c_str(), s.length(), file); - - s = va("\t\tname %s\n", name.c_str()); - FS_Write(s.c_str(), s.length(), file); - - s = va("\t\tbaseVelocity %f\n", baseVelocity); - FS_Write(s.c_str(), s.length(), file); - - for (int i = 0; i < velocities.Num(); i++) { - s = va("\t\tvelocity %i %i %f\n", velocities[i]->startTime, velocities[i]->time, velocities[i]->speed); - FS_Write(s.c_str(), s.length(), file); - } - -} - -void idFixedPosition::write(fileHandle_t file, const char *p) { - idStr s = va("\t%s {\n", p); - FS_Write(s.c_str(), s.length(), file); - idCameraPosition::write(file, p); - s = va("\t\tpos ( %f %f %f )\n", pos.x, pos.y, pos.z); - FS_Write(s.c_str(), s.length(), file); - s = "\t}\n"; - FS_Write(s.c_str(), s.length(), file); -} - -void idInterpolatedPosition::write(fileHandle_t file, const char *p) { - idStr s = va("\t%s {\n", p); - FS_Write(s.c_str(), s.length(), file); - idCameraPosition::write(file, p); - s = va("\t\tstartPos ( %f %f %f )\n", startPos.x, startPos.y, startPos.z); - FS_Write(s.c_str(), s.length(), file); - s = va("\t\tendPos ( %f %f %f )\n", endPos.x, endPos.y, endPos.z); - FS_Write(s.c_str(), s.length(), file); - s = "\t}\n"; - FS_Write(s.c_str(), s.length(), file); -} - -void idSplinePosition::write(fileHandle_t file, const char *p) { - idStr s = va("\t%s {\n", p); - FS_Write(s.c_str(), s.length(), file); - idCameraPosition::write(file, p); - target.write(file, "target"); - s = "\t}\n"; - FS_Write(s.c_str(), s.length(), file); -} - -void idCameraDef::addTarget(const char *name, idCameraPosition::positionType type) { - const char *text = (name == NULL) ? va("target0%d", numTargets()+1) : name; - idCameraPosition *pos = newFromType(type); - if (pos) { - pos->setName(name); - targetPositions.Append(pos); - activeTarget = numTargets()-1; - if (activeTarget == 0) { - // first one - addEvent(idCameraEvent::EVENT_TARGET, name, 0); - } - } -} - -const idVec3 *idSplinePosition::getPosition(long t) { - static idVec3 interpolatedPos; - - float velocity = getVelocity(t); - float timePassed = t - lastTime; - lastTime = t; - - // convert to seconds - timePassed /= 1000; - - float distToTravel = timePassed * velocity; - - distSoFar += distToTravel; - double tempDistance = target.totalDistance(); - - double percent = (double)(distSoFar) / tempDistance; - - double targetDistance = percent * tempDistance; - tempDistance = 0; - - double lastDistance1,lastDistance2; - lastDistance1 = lastDistance2 = 0; - idVec3 temp; - int count = target.numSegments(); - int i; - for(i = 1; i < count; i++) { - temp = *target.getSegmentPoint(i-1); - temp -= *target.getSegmentPoint(i); - tempDistance += temp.Length(); - if (i & 1) { - lastDistance1 = tempDistance; - } else { - lastDistance2 = tempDistance; - } - if (tempDistance >= targetDistance) { - break; - } - } - - if ( i >= count - 1) { - interpolatedPos = *target.getSegmentPoint(i-1); - } else { -#if 0 - double timeHi = target.getSegmentTime(i + 1); - double timeLo = target.getSegmentTime(i - 1); - double percent = (timeHi - t) / (timeHi - timeLo); - idVec3 v1 = *target.getSegmentPoint(i - 1); - idVec3 v2 = *target.getSegmentPoint(i + 1); - v2 *= (1.0 - percent); - v1 *= percent; - v2 += v1; - interpolatedPos = v2; -#else - if (lastDistance1 > lastDistance2) { - double d = lastDistance2; - lastDistance2 = lastDistance1; - lastDistance1 = d; - } - - idVec3 v1 = *target.getSegmentPoint(i - 1); - idVec3 v2 = *target.getSegmentPoint(i); - double percent = (lastDistance2 - targetDistance) / (lastDistance2 - lastDistance1); - v2 *= (1.0 - percent); - v1 *= percent; - v2 += v1; - interpolatedPos = v2; -#endif - } - return &interpolatedPos; - -} - - - +/* +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 +*/ + +#include "q_shared.h" +#include "splines.h" + +extern "C" { +int FS_Write( const void *buffer, int len, fileHandle_t h ); +int FS_ReadFile( const char *qpath, void **buffer ); +void FS_FreeFile( void *buffer ); +fileHandle_t FS_FOpenFileWrite( const char *filename ); +void FS_FCloseFile( fileHandle_t f ); +void Cbuf_AddText( const char *text ); +void Cbuf_Execute (void); +} + +float Q_fabs( float f ) { + int tmp = * ( int * ) &f; + tmp &= 0x7FFFFFFF; + return * ( float * ) &tmp; +} + +// (SA) making a list of cameras so I can use +// the splines as targets for other things. +// Certainly better ways to do this, but this lets +// me get underway quickly with ents that need spline +// targets. +#define MAX_CAMERAS 64 + +idCameraDef camera[MAX_CAMERAS]; + +extern "C" { +qboolean loadCamera(int camNum, const char *name) { + if(camNum < 0 || camNum >= MAX_CAMERAS ) + return qfalse; + camera[camNum].clear(); + return (qboolean)camera[camNum].load(name); +} + +qboolean getCameraInfo(int camNum, int time, float *origin, float *angles, float *fov) { + idVec3 dir, org; + if(camNum < 0 || camNum >= MAX_CAMERAS ) + return qfalse; + org[0] = origin[0]; + org[1] = origin[1]; + org[2] = origin[2]; + if (camera[camNum].getCameraInfo(time, org, dir, fov)) { + origin[0] = org[0]; + origin[1] = org[1]; + origin[2] = org[2]; + angles[1] = atan2 (dir[1], dir[0])*180/3.14159; + angles[0] = asin (dir[2])*180/3.14159; + return qtrue; + } + return qfalse; +} + +void startCamera(int camNum, int time) { + if(camNum < 0 || camNum >= MAX_CAMERAS ) + return; + camera[camNum].startCamera(time); +} + +} + + +//#include "../shared/windings.h" +//#include "../qcommon/qcommon.h" +//#include "../sys/sys_public.h" +//#include "../game/game_entity.h" + +idCameraDef splineList; +idCameraDef *g_splineList = &splineList; + +idVec3 idSplineList::zero(0,0,0); + +void glLabeledPoint(idVec3 &color, idVec3 &point, float size, const char *label) { + qglColor3fv(color); + qglPointSize(size); + qglBegin(GL_POINTS); + qglVertex3fv(point); + qglEnd(); + idVec3 v = point; + v.x += 1; + v.y += 1; + v.z += 1; + qglRasterPos3fv (v); + qglCallLists (strlen(label), GL_UNSIGNED_BYTE, label); +} + + +void glBox(idVec3 &color, idVec3 &point, float size) { + idVec3 mins(point); + idVec3 maxs(point); + mins[0] -= size; + mins[1] += size; + mins[2] -= size; + maxs[0] += size; + maxs[1] -= size; + maxs[2] += size; + qglColor3fv(color); + qglBegin(GL_LINE_LOOP); + qglVertex3f(mins[0],mins[1],mins[2]); + qglVertex3f(maxs[0],mins[1],mins[2]); + qglVertex3f(maxs[0],maxs[1],mins[2]); + qglVertex3f(mins[0],maxs[1],mins[2]); + qglEnd(); + qglBegin(GL_LINE_LOOP); + qglVertex3f(mins[0],mins[1],maxs[2]); + qglVertex3f(maxs[0],mins[1],maxs[2]); + qglVertex3f(maxs[0],maxs[1],maxs[2]); + qglVertex3f(mins[0],maxs[1],maxs[2]); + qglEnd(); + + qglBegin(GL_LINES); + qglVertex3f(mins[0],mins[1],mins[2]); + qglVertex3f(mins[0],mins[1],maxs[2]); + qglVertex3f(mins[0],maxs[1],maxs[2]); + qglVertex3f(mins[0],maxs[1],mins[2]); + qglVertex3f(maxs[0],mins[1],mins[2]); + qglVertex3f(maxs[0],mins[1],maxs[2]); + qglVertex3f(maxs[0],maxs[1],maxs[2]); + qglVertex3f(maxs[0],maxs[1],mins[2]); + qglEnd(); + +} + +void splineTest() { + //g_splineList->load("p:/doom/base/maps/test_base1.camera"); +} + +void splineDraw() { + //g_splineList->addToRenderer(); +} + + +//extern void D_DebugLine( const idVec3 &color, const idVec3 &start, const idVec3 &end ); + +void debugLine(idVec3 &color, float x, float y, float z, float x2, float y2, float z2) { + idVec3 from(x, y, z); + idVec3 to(x2, y2, z2); + //D_DebugLine(color, from, to); +} + +void idSplineList::addToRenderer() { + + if (controlPoints.Num() == 0) { + return; + } + + idVec3 mins, maxs; + idVec3 yellow(1.0, 1.0, 0); + idVec3 white(1.0, 1.0, 1.0); + int i; + + for(i = 0; i < controlPoints.Num(); i++) { + VectorCopy(*controlPoints[i], mins); + VectorCopy(mins, maxs); + mins[0] -= 8; + mins[1] += 8; + mins[2] -= 8; + maxs[0] += 8; + maxs[1] -= 8; + maxs[2] += 8; + debugLine( yellow, mins[0], mins[1], mins[2], maxs[0], mins[1], mins[2]); + debugLine( yellow, maxs[0], mins[1], mins[2], maxs[0], maxs[1], mins[2]); + debugLine( yellow, maxs[0], maxs[1], mins[2], mins[0], maxs[1], mins[2]); + debugLine( yellow, mins[0], maxs[1], mins[2], mins[0], mins[1], mins[2]); + + debugLine( yellow, mins[0], mins[1], maxs[2], maxs[0], mins[1], maxs[2]); + debugLine( yellow, maxs[0], mins[1], maxs[2], maxs[0], maxs[1], maxs[2]); + debugLine( yellow, maxs[0], maxs[1], maxs[2], mins[0], maxs[1], maxs[2]); + debugLine( yellow, mins[0], maxs[1], maxs[2], mins[0], mins[1], maxs[2]); + + } + + int step = 0; + idVec3 step1; + for(i = 3; i < controlPoints.Num(); i++) { + for (float tension = 0.0f; tension < 1.001f; tension += 0.1f) { + float x = 0; + float y = 0; + float z = 0; + for (int j = 0; j < 4; j++) { + x += controlPoints[i - (3 - j)]->x * calcSpline(j, tension); + y += controlPoints[i - (3 - j)]->y * calcSpline(j, tension); + z += controlPoints[i - (3 - j)]->z * calcSpline(j, tension); + } + if (step == 0) { + step1[0] = x; + step1[1] = y; + step1[2] = z; + step = 1; + } else { + debugLine( white, step1[0], step1[1], step1[2], x, y, z); + step = 0; + } + + } + } +} + +void idSplineList::buildSpline() { + //int start = Sys_Milliseconds(); + clearSpline(); + for(int i = 3; i < controlPoints.Num(); i++) { + for (float tension = 0.0f; tension < 1.001f; tension += granularity) { + float x = 0; + float y = 0; + float z = 0; + for (int j = 0; j < 4; j++) { + x += controlPoints[i - (3 - j)]->x * calcSpline(j, tension); + y += controlPoints[i - (3 - j)]->y * calcSpline(j, tension); + z += controlPoints[i - (3 - j)]->z * calcSpline(j, tension); + } + splinePoints.Append(new idVec3(x, y, z)); + } + } + dirty = false; + //Com_Printf("Spline build took %f seconds\n", (float)(Sys_Milliseconds() - start) / 1000); +} + + +void idSplineList::draw(bool editMode) { + int i; + idVec4 yellow(1, 1, 0, 1); + + if (controlPoints.Num() == 0) { + return; + } + + if (dirty) { + buildSpline(); + } + + + qglColor3fv(controlColor); + qglPointSize(5); + + qglBegin(GL_POINTS); + for (i = 0; i < controlPoints.Num(); i++) { + qglVertex3fv(*controlPoints[i]); + } + qglEnd(); + + if (editMode) { + for(i = 0; i < controlPoints.Num(); i++) { + glBox(activeColor, *controlPoints[i], 4); + } + } + + //Draw the curve + qglColor3fv(pathColor); + qglBegin(GL_LINE_STRIP); + int count = splinePoints.Num(); + for (i = 0; i < count; i++) { + qglVertex3fv(*splinePoints[i]); + } + qglEnd(); + + if (editMode) { + qglColor3fv(segmentColor); + qglPointSize(3); + qglBegin(GL_POINTS); + for (i = 0; i < count; i++) { + qglVertex3fv(*splinePoints[i]); + } + qglEnd(); + } + if (count > 0) { + //assert(activeSegment >=0 && activeSegment < count); + if (activeSegment >=0 && activeSegment < count) { + glBox(activeColor, *splinePoints[activeSegment], 6); + glBox(yellow, *splinePoints[activeSegment], 8); + } + } + +} + +float idSplineList::totalDistance() { + + // FIXME: save dist and return + // + if (controlPoints.Num() == 0) { + return 0.0; + } + + if (dirty) { + buildSpline(); + } + + float dist = 0.0; + idVec3 temp; + int count = splinePoints.Num(); + for(int i = 1; i < count; i++) { + temp = *splinePoints[i-1]; + temp -= *splinePoints[i]; + dist += temp.Length(); + } + return dist; +} + +void idSplineList::initPosition(long bt, long totalTime) { + + if (dirty) { + buildSpline(); + } + + if (splinePoints.Num() == 0) { + return; + } + + baseTime = bt; + time = totalTime; + + // calc distance to travel ( this will soon be broken into time segments ) + splineTime.Clear(); + splineTime.Append(bt); + double dist = totalDistance(); + double distSoFar = 0.0; + idVec3 temp; + int count = splinePoints.Num(); + //for(int i = 2; i < count - 1; i++) { + for(int i = 1; i < count; i++) { + temp = *splinePoints[i-1]; + temp -= *splinePoints[i]; + distSoFar += temp.Length(); + double percent = distSoFar / dist; + percent *= totalTime; + splineTime.Append(percent + bt); + } + assert(splineTime.Num() == splinePoints.Num()); + activeSegment = 0; +} + + + +float idSplineList::calcSpline(int step, float tension) { + switch(step) { + case 0: return (pow(1 - tension, 3)) / 6; + case 1: return (3 * pow(tension, 3) - 6 * pow(tension, 2) + 4) / 6; + case 2: return (-3 * pow(tension, 3) + 3 * pow(tension, 2) + 3 * tension + 1) / 6; + case 3: return pow(tension, 3) / 6; + } + return 0.0; +} + + + +void idSplineList::updateSelection(const idVec3 &move) { + if (selected) { + dirty = true; + VectorAdd(*selected, move, *selected); + } +} + + +void idSplineList::setSelectedPoint(idVec3 *p) { + if (p) { + p->Snap(); + for(int i = 0; i < controlPoints.Num(); i++) { + if (*p == *controlPoints[i]) { + selected = controlPoints[i]; + } + } + } else { + selected = NULL; + } +} + +const idVec3 *idSplineList::getPosition(long t) { + static idVec3 interpolatedPos; + static long lastTime = -1; + + int count = splineTime.Num(); + if (count == 0) { + return &zero; + } + +// Com_Printf("Time: %d\n", t); + assert(splineTime.Num() == splinePoints.Num()); + + while (activeSegment < count) { + if (splineTime[activeSegment] >= t) { + if (activeSegment > 0 && activeSegment < count - 1) { + double timeHi = splineTime[activeSegment + 1]; + double timeLo = splineTime[activeSegment - 1]; + double percent = (timeHi - t) / (timeHi - timeLo); + // pick two bounding points + idVec3 v1 = *splinePoints[activeSegment-1]; + idVec3 v2 = *splinePoints[activeSegment+1]; + v2 *= (1.0 - percent); + v1 *= percent; + v2 += v1; + interpolatedPos = v2; + return &interpolatedPos; + } + return splinePoints[activeSegment]; + } else { + activeSegment++; + } + } + return splinePoints[count-1]; +} + +void idSplineList::parse(const char *(*text) ) { + const char *token; + //Com_MatchToken( text, "{" ); + do { + token = Com_Parse( text ); + + if ( !token[0] ) { + break; + } + if ( !Q_stricmp (token, "}") ) { + break; + } + + do { + // if token is not a brace, it is a key for a key/value pair + if ( !token[0] || !Q_stricmp (token, "(") || !Q_stricmp(token, "}")) { + break; + } + + Com_UngetToken(); + idStr key = Com_ParseOnLine(text); + const char *token = Com_Parse(text); + if (Q_stricmp(key.c_str(), "granularity") == 0) { + granularity = atof(token); + } else if (Q_stricmp(key.c_str(), "name") == 0) { + name = token; + } + token = Com_Parse(text); + + } while (1); + + if ( !Q_stricmp (token, "}") ) { + break; + } + + Com_UngetToken(); + // read the control point + idVec3 point; + Com_Parse1DMatrix( text, 3, point ); + addPoint(point.x, point.y, point.z); + } while (1); + + //Com_UngetToken(); + //Com_MatchToken( text, "}" ); + dirty = true; +} + +void idSplineList::write(fileHandle_t file, const char *p) { + idStr s = va("\t\t%s {\n", p); + FS_Write(s.c_str(), s.length(), file); + //s = va("\t\tname %s\n", name.c_str()); + //FS_Write(s.c_str(), s.length(), file); + s = va("\t\t\tgranularity %f\n", granularity); + FS_Write(s.c_str(), s.length(), file); + int count = controlPoints.Num(); + for (int i = 0; i < count; i++) { + s = va("\t\t\t( %f %f %f )\n", controlPoints[i]->x, controlPoints[i]->y, controlPoints[i]->z); + FS_Write(s.c_str(), s.length(), file); + } + s = "\t\t}\n"; + FS_Write(s.c_str(), s.length(), file); +} + + +void idCameraDef::getActiveSegmentInfo(int segment, idVec3 &origin, idVec3 &direction, float *fov) { +#if 0 + if (!cameraSpline.validTime()) { + buildCamera(); + } + double d = (double)segment / numSegments(); + getCameraInfo(d * totalTime * 1000, origin, direction, fov); +#endif +/* + if (!cameraSpline.validTime()) { + buildCamera(); + } + origin = *cameraSpline.getSegmentPoint(segment); + + + idVec3 temp; + + int numTargets = getTargetSpline()->controlPoints.Num(); + int count = cameraSpline.splineTime.Num(); + if (numTargets == 0) { + // follow the path + if (cameraSpline.getActiveSegment() < count - 1) { + temp = *cameraSpline.splinePoints[cameraSpline.getActiveSegment()+1]; + } + } else if (numTargets == 1) { + temp = *getTargetSpline()->controlPoints[0]; + } else { + temp = *getTargetSpline()->getSegmentPoint(segment); + } + + temp -= origin; + temp.Normalize(); + direction = temp; +*/ +} + +bool idCameraDef::getCameraInfo(long time, idVec3 &origin, idVec3 &direction, float *fv) { + + char buff[1024]; + + if ((time - startTime) / 1000 > totalTime) { + return false; + } + + + for (int i = 0; i < events.Num(); i++) { + if (time >= startTime + events[i]->getTime() && !events[i]->getTriggered()) { + events[i]->setTriggered(true); + if (events[i]->getType() == idCameraEvent::EVENT_TARGET) { + setActiveTargetByName(events[i]->getParam()); + getActiveTarget()->start(startTime + events[i]->getTime()); + //Com_Printf("Triggered event switch to target: %s\n",events[i]->getParam()); + } else if (events[i]->getType() == idCameraEvent::EVENT_TRIGGER) { + //idEntity *ent = NULL; + //ent = level.FindTarget( ent, events[i]->getParam()); + //if (ent) { + // ent->signal( SIG_TRIGGER ); + // ent->ProcessEvent( &EV_Activate, world ); + //} + } else if (events[i]->getType() == idCameraEvent::EVENT_FOV) { + memset(buff, 0, sizeof(buff)); + strcpy(buff, events[i]->getParam()); + const char *param1 = strtok(buff, " \t,\0"); + const char *param2 = strtok(NULL, " \t,\0"); + float len = (param2) ? atof(param2) : 0; + float newfov = (param1) ? atof(param1) : 90; + fov.reset(fov.getFOV(time), newfov, time, len); + //*fv = fov = atof(events[i]->getParam()); + } else if (events[i]->getType() == idCameraEvent::EVENT_FADEIN) { + float time = atof(events[i]->getParam()); + Cbuf_AddText(va("fade 0 0 0 0 %f", time)); + Cbuf_Execute(); + } else if (events[i]->getType() == idCameraEvent::EVENT_FADEOUT) { + float time = atof(events[i]->getParam()); + Cbuf_AddText(va("fade 0 0 0 255 %f", time)); + Cbuf_Execute(); + } else if (events[i]->getType() == idCameraEvent::EVENT_CAMERA) { + memset(buff, 0, sizeof(buff)); + strcpy(buff, events[i]->getParam()); + const char *param1 = strtok(buff, " \t,\0"); + const char *param2 = strtok(NULL, " \t,\0"); + + if(param2) { + loadCamera(atoi(param1), va("cameras/%s.camera", param2)); + startCamera(time); + } else { + loadCamera(0, va("cameras/%s.camera", events[i]->getParam())); + startCamera(time); + } + return true; + } else if (events[i]->getType() == idCameraEvent::EVENT_STOP) { + return false; + } + } + } + + origin = *cameraPosition->getPosition(time); + + *fv = fov.getFOV(time); + + idVec3 temp = origin; + + int numTargets = targetPositions.Num(); + if (numTargets == 0) { +/* + // follow the path + if (cameraSpline.getActiveSegment() < count - 1) { + temp = *cameraSpline.splinePoints[cameraSpline.getActiveSegment()+1]; + if (temp == origin) { + int index = cameraSpline.getActiveSegment() + 2; + while (temp == origin && index < count - 1) { + temp = *cameraSpline.splinePoints[index++]; + } + } + } +*/ + } else { + if( getActiveTarget()->numPoints() > 0 ) { + temp = *getActiveTarget()->getPosition(time); + } + } + + temp -= origin; + temp.Normalize(); + direction = temp; + + return true; +} + +bool idCameraDef::waitEvent(int index) { + //for (int i = 0; i < events.Num(); i++) { + // if (events[i]->getSegment() == index && events[i]->getType() == idCameraEvent::EVENT_WAIT) { + // return true; + // } + //} + return false; +} + + +#define NUM_CCELERATION_SEGS 10 +#define CELL_AMT 5 + +void idCameraDef::buildCamera() { + int i; + int lastSwitch = 0; + idList waits; + idList targets; + + totalTime = baseTime; + cameraPosition->setTime((long)totalTime * 1000); + // we have a base time layout for the path and the target path + // now we need to layer on any wait or speed changes + for (i = 0; i < events.Num(); i++) { + idCameraEvent *ev = events[i]; + events[i]->setTriggered(false); + switch (events[i]->getType()) { + case idCameraEvent::EVENT_TARGET : { + targets.Append(i); + break; + } + case idCameraEvent::EVENT_FEATHER : { + long startTime = 0; + float speed = 0; + long loopTime = 10; + float stepGoal = cameraPosition->getBaseVelocity() / (1000 / loopTime); + while (startTime <= 1000) { + cameraPosition->addVelocity(startTime, loopTime, speed); + speed += stepGoal; + if (speed > cameraPosition->getBaseVelocity()) { + speed = cameraPosition->getBaseVelocity(); + } + startTime += loopTime; + } + + startTime = (long)(totalTime * 1000 - 1000); + long endTime = startTime + 1000; + speed = cameraPosition->getBaseVelocity(); + while (startTime < endTime) { + speed -= stepGoal; + if (speed < 0) { + speed = 0; + } + cameraPosition->addVelocity(startTime, loopTime, speed); + startTime += loopTime; + } + break; + + } + case idCameraEvent::EVENT_WAIT : { + waits.Append(atof(events[i]->getParam())); + + //FIXME: this is quite hacky for Wolf E3, accel and decel needs + // do be parameter based etc.. + long startTime = events[i]->getTime() - 1000; + if (startTime < 0) { + startTime = 0; + } + float speed = cameraPosition->getBaseVelocity(); + long loopTime = 10; + float steps = speed / ((events[i]->getTime() - startTime) / loopTime); + while (startTime <= events[i]->getTime() - loopTime) { + cameraPosition->addVelocity(startTime, loopTime, speed); + speed -= steps; + startTime += loopTime; + } + cameraPosition->addVelocity(events[i]->getTime(), (long)atof(events[i]->getParam()) * 1000, 0); + + startTime = (long)(events[i]->getTime() + atof(events[i]->getParam()) * 1000); + long endTime = startTime + 1000; + speed = 0; + while (startTime <= endTime) { + cameraPosition->addVelocity(startTime, loopTime, speed); + speed += steps; + startTime += loopTime; + } + break; + } + case idCameraEvent::EVENT_TARGETWAIT : { + //targetWaits.Append(i); + break; + } + case idCameraEvent::EVENT_SPEED : { +/* + // take the average delay between up to the next five segments + float adjust = atof(events[i]->getParam()); + int index = events[i]->getSegment(); + total = 0; + count = 0; + + // get total amount of time over the remainder of the segment + for (j = index; j < cameraSpline.numSegments() - 1; j++) { + total += cameraSpline.getSegmentTime(j + 1) - cameraSpline.getSegmentTime(j); + count++; + } + + // multiply that by the adjustment + double newTotal = total * adjust; + // what is the difference.. + newTotal -= total; + totalTime += newTotal / 1000; + + // per segment difference + newTotal /= count; + int additive = newTotal; + + // now propogate that difference out to each segment + for (j = index; j < cameraSpline.numSegments(); j++) { + cameraSpline.addSegmentTime(j, additive); + additive += newTotal; + } + break; +*/ + } + } + } + + + for (i = 0; i < waits.Num(); i++) { + totalTime += waits[i]; + } + + // on a new target switch, we need to take time to this point ( since last target switch ) + // and allocate it across the active target, then reset time to this point + long timeSoFar = 0; + long total = (long)(totalTime * 1000); + for (i = 0; i < targets.Num(); i++) { + long t; + if (i < targets.Num() - 1) { + t = events[targets[i+1]]->getTime(); + } else { + t = total - timeSoFar; + } + // t is how much time to use for this target + setActiveTargetByName(events[targets[i]]->getParam()); + getActiveTarget()->setTime(t); + timeSoFar += t; + } + + +} + +void idCameraDef::startCamera(long t) { + cameraPosition->clearVelocities(); + cameraPosition->start(t); + buildCamera(); + fov.reset(90, 90, t, 0); + //for (int i = 0; i < targetPositions.Num(); i++) { + // targetPositions[i]-> + //} + startTime = t; + cameraRunning = true; +} + + +void idCameraDef::parse(const char *(*text) ) { + + const char *token; + do { + token = Com_Parse( text ); + + if ( !token[0] ) { + break; + } + if ( !Q_stricmp (token, "}") ) { + break; + } + + if (Q_stricmp(token, "time") == 0) { + baseTime = Com_ParseFloat(text); + } + else if (Q_stricmp(token, "camera_fixed") == 0) { + cameraPosition = new idFixedPosition(); + cameraPosition->parse(text); + } + else if (Q_stricmp(token, "camera_interpolated") == 0) { + cameraPosition = new idInterpolatedPosition(); + cameraPosition->parse(text); + } + else if (Q_stricmp(token, "camera_spline") == 0) { + cameraPosition = new idSplinePosition(); + cameraPosition->parse(text); + } + else if (Q_stricmp(token, "target_fixed") == 0) { + idFixedPosition *pos = new idFixedPosition(); + pos->parse(text); + targetPositions.Append(pos); + } + else if (Q_stricmp(token, "target_interpolated") == 0) { + idInterpolatedPosition *pos = new idInterpolatedPosition(); + pos->parse(text); + targetPositions.Append(pos); + } + else if (Q_stricmp(token, "target_spline") == 0) { + idSplinePosition *pos = new idSplinePosition(); + pos->parse(text); + targetPositions.Append(pos); + } + else if (Q_stricmp(token, "fov") == 0) { + fov.parse(text); + } + else if (Q_stricmp(token, "event") == 0) { + idCameraEvent *event = new idCameraEvent(); + event->parse(text); + addEvent(event); + } + + + } while (1); + + if ( !cameraPosition ) { + Com_Printf( "no camera position specified\n" ); + // prevent a crash later on + cameraPosition = new idFixedPosition(); + } + + Com_UngetToken(); + Com_MatchToken( text, "}" ); + +} + +bool idCameraDef::load(const char *filename) { + char *buf; + const char *buf_p; + int length = FS_ReadFile( filename, (void **)&buf ); + if ( !buf ) { + return false; + } + + clear(); + Com_BeginParseSession( filename ); + buf_p = buf; + parse(&buf_p); + Com_EndParseSession(); + FS_FreeFile( buf ); + + return true; +} + +void idCameraDef::save(const char *filename) { + fileHandle_t file = FS_FOpenFileWrite(filename); + if (file) { + int i; + idStr s = "cameraPathDef { \n"; + FS_Write(s.c_str(), s.length(), file); + s = va("\ttime %f\n", baseTime); + FS_Write(s.c_str(), s.length(), file); + + cameraPosition->write(file, va("camera_%s",cameraPosition->typeStr())); + + for (i = 0; i < numTargets(); i++) { + targetPositions[i]->write(file, va("target_%s", targetPositions[i]->typeStr())); + } + + for (i = 0; i < events.Num(); i++) { + events[i]->write(file, "event"); + } + + fov.write(file, "fov"); + + s = "}\n"; + FS_Write(s.c_str(), s.length(), file); + } + FS_FCloseFile(file); +} + +int idCameraDef::sortEvents(const void *p1, const void *p2) { + idCameraEvent *ev1 = (idCameraEvent*)(p1); + idCameraEvent *ev2 = (idCameraEvent*)(p2); + + if (ev1->getTime() > ev2->getTime()) { + return -1; + } + if (ev1->getTime() < ev2->getTime()) { + return 1; + } + return 0; +} + +void idCameraDef::addEvent(idCameraEvent *event) { + events.Append(event); + //events.Sort(&sortEvents); + +} +void idCameraDef::addEvent(idCameraEvent::eventType t, const char *param, long time) { + addEvent(new idCameraEvent(t, param, time)); + buildCamera(); +} + +void idCameraDef::removeEvent(int index) { + events.RemoveIndex(index); + buildCamera(); +} + + +const char *idCameraEvent::eventStr[] = { + "NA", + "WAIT", + "TARGETWAIT", + "SPEED", + "TARGET", + "SNAPTARGET", + "FOV", + "CMD", + "TRIGGER", + "STOP", + "CAMERA", + "FADEOUT", + "FADEIN", + "FEATHER" +}; + +void idCameraEvent::parse(const char *(*text) ) { + const char *token; + Com_MatchToken( text, "{" ); + do { + token = Com_Parse( text ); + + if ( !token[0] ) { + break; + } + if ( !strcmp (token, "}") ) { + break; + } + + // here we may have to jump over brush epairs ( only used in editor ) + do { + // if token is not a brace, it is a key for a key/value pair + if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) { + break; + } + + Com_UngetToken(); + idStr key = Com_ParseOnLine(text); + const char *token = Com_Parse(text); + if (Q_stricmp(key.c_str(), "type") == 0) { + type = static_cast(atoi(token)); + } else if (Q_stricmp(key.c_str(), "param") == 0) { + paramStr = token; + } else if (Q_stricmp(key.c_str(), "time") == 0) { + time = atoi(token); + } + token = Com_Parse(text); + + } while (1); + + if ( !strcmp (token, "}") ) { + break; + } + + } while (1); + + Com_UngetToken(); + Com_MatchToken( text, "}" ); +} + +void idCameraEvent::write(fileHandle_t file, const char *name) { + idStr s = va("\t%s {\n", name); + FS_Write(s.c_str(), s.length(), file); + s = va("\t\ttype %d\n", static_cast(type)); + FS_Write(s.c_str(), s.length(), file); + s = va("\t\tparam \"%s\"\n", paramStr.c_str()); + FS_Write(s.c_str(), s.length(), file); + s = va("\t\ttime %d\n", time); + FS_Write(s.c_str(), s.length(), file); + s = "\t}\n"; + FS_Write(s.c_str(), s.length(), file); +} + + +const char *idCameraPosition::positionStr[] = { + "Fixed", + "Interpolated", + "Spline", +}; + + + +const idVec3 *idInterpolatedPosition::getPosition(long t) { + static idVec3 interpolatedPos; + + float velocity = getVelocity(t); + float timePassed = t - lastTime; + lastTime = t; + + // convert to seconds + timePassed /= 1000; + + float distToTravel = timePassed * velocity; + + idVec3 temp = startPos; + temp -= endPos; + float distance = temp.Length(); + + distSoFar += distToTravel; + float percent = (float)(distSoFar) / distance; + + if (percent > 1.0) { + percent = 1.0; + } else if (percent < 0.0) { + percent = 0.0; + } + + // the following line does a straigt calc on percentage of time + // float percent = (float)(startTime + time - t) / time; + + idVec3 v1 = startPos; + idVec3 v2 = endPos; + v1 *= (1.0 - percent); + v2 *= percent; + v1 += v2; + interpolatedPos = v1; + return &interpolatedPos; +} + + +void idCameraFOV::parse(const char *(*text) ) { + const char *token; + Com_MatchToken( text, "{" ); + do { + token = Com_Parse( text ); + + if ( !token[0] ) { + break; + } + if ( !strcmp (token, "}") ) { + break; + } + + // here we may have to jump over brush epairs ( only used in editor ) + do { + // if token is not a brace, it is a key for a key/value pair + if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) { + break; + } + + Com_UngetToken(); + idStr key = Com_ParseOnLine(text); + const char *token = Com_Parse(text); + if (Q_stricmp(key.c_str(), "fov") == 0) { + fov = atof(token); + } else if (Q_stricmp(key.c_str(), "startFOV") == 0) { + startFOV = atof(token); + } else if (Q_stricmp(key.c_str(), "endFOV") == 0) { + endFOV = atof(token); + } else if (Q_stricmp(key.c_str(), "time") == 0) { + time = atoi(token); + } + token = Com_Parse(text); + + } while (1); + + if ( !strcmp (token, "}") ) { + break; + } + + } while (1); + + Com_UngetToken(); + Com_MatchToken( text, "}" ); +} + +bool idCameraPosition::parseToken(const char *key, const char *(*text)) { + const char *token = Com_Parse(text); + if (Q_stricmp(key, "time") == 0) { + time = atol(token); + return true; + } else if (Q_stricmp(key, "type") == 0) { + type = static_cast(atoi(token)); + return true; + } else if (Q_stricmp(key, "velocity") == 0) { + long t = atol(token); + token = Com_Parse(text); + long d = atol(token); + token = Com_Parse(text); + float s = atof(token); + addVelocity(t, d, s); + return true; + } else if (Q_stricmp(key, "baseVelocity") == 0) { + baseVelocity = atof(token); + return true; + } else if (Q_stricmp(key, "name") == 0) { + name = token; + return true; + } else if (Q_stricmp(key, "time") == 0) { + time = atoi(token); + return true; + } + Com_UngetToken(); + return false; +} + + + +void idFixedPosition::parse(const char *(*text) ) { + const char *token; + Com_MatchToken( text, "{" ); + do { + token = Com_Parse( text ); + + if ( !token[0] ) { + break; + } + if ( !strcmp (token, "}") ) { + break; + } + + // here we may have to jump over brush epairs ( only used in editor ) + do { + // if token is not a brace, it is a key for a key/value pair + if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) { + break; + } + + Com_UngetToken(); + idStr key = Com_ParseOnLine(text); + + const char *token = Com_Parse(text); + if (Q_stricmp(key.c_str(), "pos") == 0) { + Com_UngetToken(); + Com_Parse1DMatrix( text, 3, pos ); + } else { + Com_UngetToken(); + idCameraPosition::parseToken(key.c_str(), text); + } + token = Com_Parse(text); + + } while (1); + + if ( !strcmp (token, "}") ) { + break; + } + + } while (1); + + Com_UngetToken(); + Com_MatchToken( text, "}" ); +} + +void idInterpolatedPosition::parse(const char *(*text) ) { + const char *token; + Com_MatchToken( text, "{" ); + do { + token = Com_Parse( text ); + + if ( !token[0] ) { + break; + } + if ( !strcmp (token, "}") ) { + break; + } + + // here we may have to jump over brush epairs ( only used in editor ) + do { + // if token is not a brace, it is a key for a key/value pair + if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) { + break; + } + + Com_UngetToken(); + idStr key = Com_ParseOnLine(text); + + const char *token = Com_Parse(text); + if (Q_stricmp(key.c_str(), "startPos") == 0) { + Com_UngetToken(); + Com_Parse1DMatrix( text, 3, startPos ); + } else if (Q_stricmp(key.c_str(), "endPos") == 0) { + Com_UngetToken(); + Com_Parse1DMatrix( text, 3, endPos ); + } else { + Com_UngetToken(); + idCameraPosition::parseToken(key.c_str(), text); + } + token = Com_Parse(text); + + } while (1); + + if ( !strcmp (token, "}") ) { + break; + } + + } while (1); + + Com_UngetToken(); + Com_MatchToken( text, "}" ); +} + + +void idSplinePosition::parse(const char *(*text) ) { + const char *token; + Com_MatchToken( text, "{" ); + do { + token = Com_Parse( text ); + + if ( !token[0] ) { + break; + } + if ( !strcmp (token, "}") ) { + break; + } + + // here we may have to jump over brush epairs ( only used in editor ) + do { + // if token is not a brace, it is a key for a key/value pair + if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) { + break; + } + + Com_UngetToken(); + idStr key = Com_ParseOnLine(text); + + const char *token = Com_Parse(text); + if (Q_stricmp(key.c_str(), "target") == 0) { + target.parse(text); + } else { + Com_UngetToken(); + idCameraPosition::parseToken(key.c_str(), text); + } + token = Com_Parse(text); + + } while (1); + + if ( !strcmp (token, "}") ) { + break; + } + + } while (1); + + Com_UngetToken(); + Com_MatchToken( text, "}" ); +} + + + +void idCameraFOV::write(fileHandle_t file, const char *p) { + idStr s = va("\t%s {\n", p); + FS_Write(s.c_str(), s.length(), file); + + s = va("\t\tfov %f\n", fov); + FS_Write(s.c_str(), s.length(), file); + + s = va("\t\tstartFOV %f\n", startFOV); + FS_Write(s.c_str(), s.length(), file); + + s = va("\t\tendFOV %f\n", endFOV); + FS_Write(s.c_str(), s.length(), file); + + s = va("\t\ttime %i\n", time); + FS_Write(s.c_str(), s.length(), file); + + s = "\t}\n"; + FS_Write(s.c_str(), s.length(), file); +} + + +void idCameraPosition::write(fileHandle_t file, const char *p) { + + idStr s = va("\t\ttime %i\n", time); + FS_Write(s.c_str(), s.length(), file); + + s = va("\t\ttype %i\n", static_cast(type)); + FS_Write(s.c_str(), s.length(), file); + + s = va("\t\tname %s\n", name.c_str()); + FS_Write(s.c_str(), s.length(), file); + + s = va("\t\tbaseVelocity %f\n", baseVelocity); + FS_Write(s.c_str(), s.length(), file); + + for (int i = 0; i < velocities.Num(); i++) { + s = va("\t\tvelocity %i %i %f\n", velocities[i]->startTime, velocities[i]->time, velocities[i]->speed); + FS_Write(s.c_str(), s.length(), file); + } + +} + +void idFixedPosition::write(fileHandle_t file, const char *p) { + idStr s = va("\t%s {\n", p); + FS_Write(s.c_str(), s.length(), file); + idCameraPosition::write(file, p); + s = va("\t\tpos ( %f %f %f )\n", pos.x, pos.y, pos.z); + FS_Write(s.c_str(), s.length(), file); + s = "\t}\n"; + FS_Write(s.c_str(), s.length(), file); +} + +void idInterpolatedPosition::write(fileHandle_t file, const char *p) { + idStr s = va("\t%s {\n", p); + FS_Write(s.c_str(), s.length(), file); + idCameraPosition::write(file, p); + s = va("\t\tstartPos ( %f %f %f )\n", startPos.x, startPos.y, startPos.z); + FS_Write(s.c_str(), s.length(), file); + s = va("\t\tendPos ( %f %f %f )\n", endPos.x, endPos.y, endPos.z); + FS_Write(s.c_str(), s.length(), file); + s = "\t}\n"; + FS_Write(s.c_str(), s.length(), file); +} + +void idSplinePosition::write(fileHandle_t file, const char *p) { + idStr s = va("\t%s {\n", p); + FS_Write(s.c_str(), s.length(), file); + idCameraPosition::write(file, p); + target.write(file, "target"); + s = "\t}\n"; + FS_Write(s.c_str(), s.length(), file); +} + +void idCameraDef::addTarget(const char *name, idCameraPosition::positionType type) { + const char *text = (name == NULL) ? va("target0%d", numTargets()+1) : name; + idCameraPosition *pos = newFromType(type); + if (pos) { + pos->setName(name); + targetPositions.Append(pos); + activeTarget = numTargets()-1; + if (activeTarget == 0) { + // first one + addEvent(idCameraEvent::EVENT_TARGET, name, 0); + } + } +} + +const idVec3 *idSplinePosition::getPosition(long t) { + static idVec3 interpolatedPos; + + float velocity = getVelocity(t); + float timePassed = t - lastTime; + lastTime = t; + + // convert to seconds + timePassed /= 1000; + + float distToTravel = timePassed * velocity; + + distSoFar += distToTravel; + double tempDistance = target.totalDistance(); + + double percent = (double)(distSoFar) / tempDistance; + + double targetDistance = percent * tempDistance; + tempDistance = 0; + + double lastDistance1,lastDistance2; + lastDistance1 = lastDistance2 = 0; + idVec3 temp; + int count = target.numSegments(); + int i; + for(i = 1; i < count; i++) { + temp = *target.getSegmentPoint(i-1); + temp -= *target.getSegmentPoint(i); + tempDistance += temp.Length(); + if (i & 1) { + lastDistance1 = tempDistance; + } else { + lastDistance2 = tempDistance; + } + if (tempDistance >= targetDistance) { + break; + } + } + + if ( i >= count - 1) { + interpolatedPos = *target.getSegmentPoint(i-1); + } else { +#if 0 + double timeHi = target.getSegmentTime(i + 1); + double timeLo = target.getSegmentTime(i - 1); + double percent = (timeHi - t) / (timeHi - timeLo); + idVec3 v1 = *target.getSegmentPoint(i - 1); + idVec3 v2 = *target.getSegmentPoint(i + 1); + v2 *= (1.0 - percent); + v1 *= percent; + v2 += v1; + interpolatedPos = v2; +#else + if (lastDistance1 > lastDistance2) { + double d = lastDistance2; + lastDistance2 = lastDistance1; + lastDistance1 = d; + } + + idVec3 v1 = *target.getSegmentPoint(i - 1); + idVec3 v2 = *target.getSegmentPoint(i); + double percent = (lastDistance2 - targetDistance) / (lastDistance2 - lastDistance1); + v2 *= (1.0 - percent); + v1 *= percent; + v2 += v1; + interpolatedPos = v2; +#endif + } + return &interpolatedPos; + +} + + + diff --git a/libs/splines/util_str.cpp b/libs/splines/util_str.cpp index 436285ad..ecacc766 100644 --- a/libs/splines/util_str.cpp +++ b/libs/splines/util_str.cpp @@ -1,628 +1,628 @@ -/* -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 -*/ - -//need to rewrite this - -#include "util_str.h" -#include -#include -#include -#include - -#ifdef _WIN32 -#pragma warning(disable : 4244) // 'conversion' conversion from 'type1' to 'type2', possible loss of data -#pragma warning(disable : 4710) // function 'blah' not inlined -#endif - -static const int STR_ALLOC_GRAN = 20; - -// screwy but intentional -#ifdef __APPLE_BUG__ -char *idStr::__tolower -#else -char *idStr::tolower -#endif - ( - char *s1 - ) - - { - char *s; - - s = s1; - while( *s ) - { - *s = ::tolower( *s ); - s++; - } - - return s1; - } - -// screwy but intentional -#ifdef __APPLE_BUG__ -char *idStr::__toupper -#else -char *idStr::toupper -#endif - ( - char *s1 - ) - - { - char *s; - - s = s1; - while( *s ) - { - *s = ::toupper( *s ); - s++; - } - - return s1; - } - -int idStr::icmpn - ( - const char *s1, - const char *s2, - int n - ) - - { - int c1; - int c2; - - do - { - c1 = *s1++; - c2 = *s2++; - - if ( !n-- ) - { - // idStrings are equal until end point - return 0; - } - - if ( c1 != c2 ) - { - if ( c1 >= 'a' && c1 <= 'z' ) - { - c1 -= ( 'a' - 'A' ); - } - - if ( c2 >= 'a' && c2 <= 'z' ) - { - c2 -= ( 'a' - 'A' ); - } - - if ( c1 < c2 ) - { - // strings less than - return -1; - } - else if ( c1 > c2 ) - { - // strings greater than - return 1; - } - } - } - while( c1 ); - - // strings are equal - return 0; - } - -int idStr::icmp - ( - const char *s1, - const char *s2 - ) - - { - int c1; - int c2; - - do - { - c1 = *s1++; - c2 = *s2++; - - if ( c1 != c2 ) - { - if ( c1 >= 'a' && c1 <= 'z' ) - { - c1 -= ( 'a' - 'A' ); - } - - if ( c2 >= 'a' && c2 <= 'z' ) - { - c2 -= ( 'a' - 'A' ); - } - - if ( c1 < c2 ) - { - // strings less than - return -1; - } - else if ( c1 > c2 ) - { - // strings greater than - return 1; - } - } - } - while( c1 ); - - // strings are equal - return 0; - } - -int idStr::cmpn - ( - const char *s1, - const char *s2, - int n - ) - - { - int c1; - int c2; - - do - { - c1 = *s1++; - c2 = *s2++; - - if ( !n-- ) - { - // strings are equal until end point - return 0; - } - - if ( c1 < c2 ) - { - // strings less than - return -1; - } - else if ( c1 > c2 ) - { - // strings greater than - return 1; - } - } - while( c1 ); - - // strings are equal - return 0; - } - -int idStr::cmp - ( - const char *s1, - const char *s2 - ) - - { - int c1; - int c2; - - do - { - c1 = *s1++; - c2 = *s2++; - - if ( c1 < c2 ) - { - // strings less than - return -1; - } - else if ( c1 > c2 ) - { - // strings greater than - return 1; - } - } - while( c1 ); - - // strings are equal - return 0; - } - -/* -============ -IsNumeric - -Checks a string to see if it contains only numerical values. -============ -*/ -bool idStr::isNumeric - ( - const char *str - ) - - { - int len; - int i; - bool dot; - - if ( *str == '-' ) - { - str++; - } - - dot = false; - len = strlen( str ); - for( i = 0; i < len; i++ ) - { - if ( !isdigit( str[ i ] ) ) - { - if ( ( str[ i ] == '.' ) && !dot ) - { - dot = true; - continue; - } - return false; - } - } - - return true; - } - -idStr operator+ - ( - const idStr& a, - const float b - ) - - { - char text[ 20 ]; - - idStr result( a ); - - sprintf( text, "%f", b ); - result.append( text ); - - return result; - } - -idStr operator+ - ( - const idStr& a, - const int b - ) - - { - char text[ 20 ]; - - idStr result( a ); - - sprintf( text, "%d", b ); - result.append( text ); - - return result; - } - -idStr operator+ - ( - const idStr& a, - const unsigned b - ) - - { - char text[ 20 ]; - - idStr result( a ); - - sprintf( text, "%u", b ); - result.append( text ); - - return result; - } - -idStr& idStr::operator+= - ( - const float a - ) - - { - char text[ 20 ]; - - sprintf( text, "%f", a ); - append( text ); - - return *this; - } - -idStr& idStr::operator+= - ( - const int a - ) - - { - char text[ 20 ]; - - sprintf( text, "%d", a ); - append( text ); - - return *this; - } - -idStr& idStr::operator+= - ( - const unsigned a - ) - - { - char text[ 20 ]; - - sprintf( text, "%u", a ); - append( text ); - - return *this; - } - -void idStr::CapLength - ( - int newlen - ) - - { - assert ( m_data ); - - if ( length() <= newlen ) - return; - - EnsureDataWritable (); - - m_data->data[newlen] = 0; - m_data->len = newlen; - } - -void idStr::EnsureDataWritable - ( - void - ) - - { - assert ( m_data ); - strdata *olddata; - int len; - - if ( !m_data->refcount ) - return; - - olddata = m_data; - len = length(); - - m_data = new strdata; - - EnsureAlloced ( len + 1, false ); - strncpy ( m_data->data, olddata->data, len+1 ); - m_data->len = len; - - olddata->DelRef (); - } - -void idStr::EnsureAlloced (int amount, bool keepold) { - - if ( !m_data ) { - m_data = new strdata(); - } - - // Now, let's make sure it's writable - EnsureDataWritable (); - - char *newbuffer; - bool wasalloced = ( m_data->alloced != 0 ); - - if ( amount < m_data->alloced ) { - return; - } - - assert ( amount ); - if ( amount == 1 ) { - m_data->alloced = 1; - } else { - int newsize, mod; - mod = amount % STR_ALLOC_GRAN; - if ( !mod ) { - newsize = amount; - } else { - newsize = amount + STR_ALLOC_GRAN - mod; - } - m_data->alloced = newsize; - } - - newbuffer = new char[m_data->alloced]; - if ( wasalloced && keepold ) { - strcpy ( newbuffer, m_data->data ); - } - - if ( m_data->data ) { - delete [] m_data->data; - } - m_data->data = newbuffer; -} - -void idStr::BackSlashesToSlashes - ( - void - ) - - { - int i; - - EnsureDataWritable (); - - for ( i=0; i < m_data->len; i++ ) - { - if ( m_data->data[i] == '\\' ) - m_data->data[i] = '/'; - } - } - -void idStr::snprintf - ( - char *dst, - int size, - const char *fmt, - ... - ) - - { - char buffer[0x10000]; - int len; - va_list argptr; - - va_start (argptr,fmt); - len = vsprintf (buffer,fmt,argptr); - va_end (argptr); - - assert ( len < size ); - - strncpy (dst, buffer, size-1); - } - -#ifdef _WIN32 -#pragma warning(disable : 4189) // local variable is initialized but not referenced -#endif - -/* -================= -TestStringClass - -This is a fairly rigorous test of the idStr class's functionality. -Because of the fairly global and subtle ramifications of a bug occuring -in this class, it should be run after any changes to the class. -Add more tests as functionality is changed. Tests should include -any possible bounds violation and NULL data tests. -================= -*/ -void TestStringClass - ( - void - ) - - { - char ch; // ch == ? - idStr *t; // t == ? - idStr a; // a.len == 0, a.data == "\0" - idStr b; // b.len == 0, b.data == "\0" - idStr c( "test" ); // c.len == 4, c.data == "test\0" - idStr d( c ); // d.len == 4, d.data == "test\0" - idStr e( reinterpret_cast(NULL) ); - // e.len == 0, e.data == "\0" ASSERT! - int i; // i == ? - - i = a.length(); // i == 0 - i = c.length(); // i == 4 - - const char *s1 = a.c_str(); // s1 == "\0" - const char *s2 = c.c_str(); // s2 == "test\0" - - t = new idStr(); // t->len == 0, t->data == "\0" - delete t; // t == ? - - b = "test"; // b.len == 4, b.data == "test\0" - t = new idStr( "test" ); // t->len == 4, t->data == "test\0" - delete t; // t == ? - - a = c; // a.len == 4, a.data == "test\0" -// a = ""; - a = NULL; // a.len == 0, a.data == "\0" ASSERT! - a = c + d; // a.len == 8, a.data == "testtest\0" - a = c + "wow"; // a.len == 7, a.data == "testwow\0" - a = c + reinterpret_cast(NULL); - // a.len == 4, a.data == "test\0" ASSERT! - a = "this" + d; // a.len == 8, a.data == "thistest\0" - a = reinterpret_cast(NULL) + d; - // a.len == 4, a.data == "test\0" ASSERT! - a += c; // a.len == 8, a.data == "testtest\0" - a += "wow"; // a.len == 11, a.data == "testtestwow\0" - a += reinterpret_cast(NULL); - // a.len == 11, a.data == "testtestwow\0" ASSERT! - - a = "test"; // a.len == 4, a.data == "test\0" - ch = a[ 0 ]; // ch == 't' - ch = a[ -1 ]; // ch == 0 ASSERT! - ch = a[ 1000 ]; // ch == 0 ASSERT! - ch = a[ 0 ]; // ch == 't' - ch = a[ 1 ]; // ch == 'e' - ch = a[ 2 ]; // ch == 's' - ch = a[ 3 ]; // ch == 't' - ch = a[ 4 ]; // ch == '\0' ASSERT! - ch = a[ 5 ]; // ch == '\0' ASSERT! - - a[ 1 ] = 'b'; // a.len == 4, a.data == "tbst\0" - a[ -1 ] = 'b'; // a.len == 4, a.data == "tbst\0" ASSERT! - a[ 0 ] = '0'; // a.len == 4, a.data == "0bst\0" - a[ 1 ] = '1'; // a.len == 4, a.data == "01st\0" - a[ 2 ] = '2'; // a.len == 4, a.data == "012t\0" - a[ 3 ] = '3'; // a.len == 4, a.data == "0123\0" - a[ 4 ] = '4'; // a.len == 4, a.data == "0123\0" ASSERT! - a[ 5 ] = '5'; // a.len == 4, a.data == "0123\0" ASSERT! - a[ 7 ] = '7'; // a.len == 4, a.data == "0123\0" ASSERT! - - a = "test"; // a.len == 4, a.data == "test\0" - b = "no"; // b.len == 2, b.data == "no\0" - - i = ( a == b ); // i == 0 - i = ( a == c ); // i == 1 - - i = ( a == "blow" ); // i == 0 - i = ( a == "test" ); // i == 1 - i = ( a == NULL ); // i == 0 ASSERT! - - i = ( "test" == b ); // i == 0 - i = ( "test" == a ); // i == 1 - i = ( NULL == a ); // i == 0 ASSERT! - - i = ( a != b ); // i == 1 - i = ( a != c ); // i == 0 - - i = ( a != "blow" ); // i == 1 - i = ( a != "test" ); // i == 0 - i = ( a != NULL ); // i == 1 ASSERT! - - i = ( "test" != b ); // i == 1 - i = ( "test" != a ); // i == 0 - i = ( NULL != a ); // i == 1 ASSERT! - - a = "test"; // a.data == "test" - b = a; // b.data == "test" - - a = "not"; // a.data == "not", b.data == "test" - - a = b; // a.data == b.data == "test" - - a += b; // a.data == "testtest", b.data = "test" - - a = b; - - a[1] = '1'; // a.data = "t1st", b.data = "test" - } - -#ifdef _WIN32 -#pragma warning(default : 4189) // local variable is initialized but not referenced -#pragma warning(disable : 4514) // unreferenced inline function has been removed -#endif +/* +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 +*/ + +//need to rewrite this + +#include "util_str.h" +#include +#include +#include +#include + +#ifdef _WIN32 +#pragma warning(disable : 4244) // 'conversion' conversion from 'type1' to 'type2', possible loss of data +#pragma warning(disable : 4710) // function 'blah' not inlined +#endif + +static const int STR_ALLOC_GRAN = 20; + +// screwy but intentional +#ifdef __APPLE_BUG__ +char *idStr::__tolower +#else +char *idStr::tolower +#endif + ( + char *s1 + ) + + { + char *s; + + s = s1; + while( *s ) + { + *s = ::tolower( *s ); + s++; + } + + return s1; + } + +// screwy but intentional +#ifdef __APPLE_BUG__ +char *idStr::__toupper +#else +char *idStr::toupper +#endif + ( + char *s1 + ) + + { + char *s; + + s = s1; + while( *s ) + { + *s = ::toupper( *s ); + s++; + } + + return s1; + } + +int idStr::icmpn + ( + const char *s1, + const char *s2, + int n + ) + + { + int c1; + int c2; + + do + { + c1 = *s1++; + c2 = *s2++; + + if ( !n-- ) + { + // idStrings are equal until end point + return 0; + } + + if ( c1 != c2 ) + { + if ( c1 >= 'a' && c1 <= 'z' ) + { + c1 -= ( 'a' - 'A' ); + } + + if ( c2 >= 'a' && c2 <= 'z' ) + { + c2 -= ( 'a' - 'A' ); + } + + if ( c1 < c2 ) + { + // strings less than + return -1; + } + else if ( c1 > c2 ) + { + // strings greater than + return 1; + } + } + } + while( c1 ); + + // strings are equal + return 0; + } + +int idStr::icmp + ( + const char *s1, + const char *s2 + ) + + { + int c1; + int c2; + + do + { + c1 = *s1++; + c2 = *s2++; + + if ( c1 != c2 ) + { + if ( c1 >= 'a' && c1 <= 'z' ) + { + c1 -= ( 'a' - 'A' ); + } + + if ( c2 >= 'a' && c2 <= 'z' ) + { + c2 -= ( 'a' - 'A' ); + } + + if ( c1 < c2 ) + { + // strings less than + return -1; + } + else if ( c1 > c2 ) + { + // strings greater than + return 1; + } + } + } + while( c1 ); + + // strings are equal + return 0; + } + +int idStr::cmpn + ( + const char *s1, + const char *s2, + int n + ) + + { + int c1; + int c2; + + do + { + c1 = *s1++; + c2 = *s2++; + + if ( !n-- ) + { + // strings are equal until end point + return 0; + } + + if ( c1 < c2 ) + { + // strings less than + return -1; + } + else if ( c1 > c2 ) + { + // strings greater than + return 1; + } + } + while( c1 ); + + // strings are equal + return 0; + } + +int idStr::cmp + ( + const char *s1, + const char *s2 + ) + + { + int c1; + int c2; + + do + { + c1 = *s1++; + c2 = *s2++; + + if ( c1 < c2 ) + { + // strings less than + return -1; + } + else if ( c1 > c2 ) + { + // strings greater than + return 1; + } + } + while( c1 ); + + // strings are equal + return 0; + } + +/* +============ +IsNumeric + +Checks a string to see if it contains only numerical values. +============ +*/ +bool idStr::isNumeric + ( + const char *str + ) + + { + int len; + int i; + bool dot; + + if ( *str == '-' ) + { + str++; + } + + dot = false; + len = strlen( str ); + for( i = 0; i < len; i++ ) + { + if ( !isdigit( str[ i ] ) ) + { + if ( ( str[ i ] == '.' ) && !dot ) + { + dot = true; + continue; + } + return false; + } + } + + return true; + } + +idStr operator+ + ( + const idStr& a, + const float b + ) + + { + char text[ 20 ]; + + idStr result( a ); + + sprintf( text, "%f", b ); + result.append( text ); + + return result; + } + +idStr operator+ + ( + const idStr& a, + const int b + ) + + { + char text[ 20 ]; + + idStr result( a ); + + sprintf( text, "%d", b ); + result.append( text ); + + return result; + } + +idStr operator+ + ( + const idStr& a, + const unsigned b + ) + + { + char text[ 20 ]; + + idStr result( a ); + + sprintf( text, "%u", b ); + result.append( text ); + + return result; + } + +idStr& idStr::operator+= + ( + const float a + ) + + { + char text[ 20 ]; + + sprintf( text, "%f", a ); + append( text ); + + return *this; + } + +idStr& idStr::operator+= + ( + const int a + ) + + { + char text[ 20 ]; + + sprintf( text, "%d", a ); + append( text ); + + return *this; + } + +idStr& idStr::operator+= + ( + const unsigned a + ) + + { + char text[ 20 ]; + + sprintf( text, "%u", a ); + append( text ); + + return *this; + } + +void idStr::CapLength + ( + int newlen + ) + + { + assert ( m_data ); + + if ( length() <= newlen ) + return; + + EnsureDataWritable (); + + m_data->data[newlen] = 0; + m_data->len = newlen; + } + +void idStr::EnsureDataWritable + ( + void + ) + + { + assert ( m_data ); + strdata *olddata; + int len; + + if ( !m_data->refcount ) + return; + + olddata = m_data; + len = length(); + + m_data = new strdata; + + EnsureAlloced ( len + 1, false ); + strncpy ( m_data->data, olddata->data, len+1 ); + m_data->len = len; + + olddata->DelRef (); + } + +void idStr::EnsureAlloced (int amount, bool keepold) { + + if ( !m_data ) { + m_data = new strdata(); + } + + // Now, let's make sure it's writable + EnsureDataWritable (); + + char *newbuffer; + bool wasalloced = ( m_data->alloced != 0 ); + + if ( amount < m_data->alloced ) { + return; + } + + assert ( amount ); + if ( amount == 1 ) { + m_data->alloced = 1; + } else { + int newsize, mod; + mod = amount % STR_ALLOC_GRAN; + if ( !mod ) { + newsize = amount; + } else { + newsize = amount + STR_ALLOC_GRAN - mod; + } + m_data->alloced = newsize; + } + + newbuffer = new char[m_data->alloced]; + if ( wasalloced && keepold ) { + strcpy ( newbuffer, m_data->data ); + } + + if ( m_data->data ) { + delete [] m_data->data; + } + m_data->data = newbuffer; +} + +void idStr::BackSlashesToSlashes + ( + void + ) + + { + int i; + + EnsureDataWritable (); + + for ( i=0; i < m_data->len; i++ ) + { + if ( m_data->data[i] == '\\' ) + m_data->data[i] = '/'; + } + } + +void idStr::snprintf + ( + char *dst, + int size, + const char *fmt, + ... + ) + + { + char buffer[0x10000]; + int len; + va_list argptr; + + va_start (argptr,fmt); + len = vsprintf (buffer,fmt,argptr); + va_end (argptr); + + assert ( len < size ); + + strncpy (dst, buffer, size-1); + } + +#ifdef _WIN32 +#pragma warning(disable : 4189) // local variable is initialized but not referenced +#endif + +/* +================= +TestStringClass + +This is a fairly rigorous test of the idStr class's functionality. +Because of the fairly global and subtle ramifications of a bug occuring +in this class, it should be run after any changes to the class. +Add more tests as functionality is changed. Tests should include +any possible bounds violation and NULL data tests. +================= +*/ +void TestStringClass + ( + void + ) + + { + char ch; // ch == ? + idStr *t; // t == ? + idStr a; // a.len == 0, a.data == "\0" + idStr b; // b.len == 0, b.data == "\0" + idStr c( "test" ); // c.len == 4, c.data == "test\0" + idStr d( c ); // d.len == 4, d.data == "test\0" + idStr e( reinterpret_cast(NULL) ); + // e.len == 0, e.data == "\0" ASSERT! + int i; // i == ? + + i = a.length(); // i == 0 + i = c.length(); // i == 4 + + const char *s1 = a.c_str(); // s1 == "\0" + const char *s2 = c.c_str(); // s2 == "test\0" + + t = new idStr(); // t->len == 0, t->data == "\0" + delete t; // t == ? + + b = "test"; // b.len == 4, b.data == "test\0" + t = new idStr( "test" ); // t->len == 4, t->data == "test\0" + delete t; // t == ? + + a = c; // a.len == 4, a.data == "test\0" +// a = ""; + a = NULL; // a.len == 0, a.data == "\0" ASSERT! + a = c + d; // a.len == 8, a.data == "testtest\0" + a = c + "wow"; // a.len == 7, a.data == "testwow\0" + a = c + reinterpret_cast(NULL); + // a.len == 4, a.data == "test\0" ASSERT! + a = "this" + d; // a.len == 8, a.data == "thistest\0" + a = reinterpret_cast(NULL) + d; + // a.len == 4, a.data == "test\0" ASSERT! + a += c; // a.len == 8, a.data == "testtest\0" + a += "wow"; // a.len == 11, a.data == "testtestwow\0" + a += reinterpret_cast(NULL); + // a.len == 11, a.data == "testtestwow\0" ASSERT! + + a = "test"; // a.len == 4, a.data == "test\0" + ch = a[ 0 ]; // ch == 't' + ch = a[ -1 ]; // ch == 0 ASSERT! + ch = a[ 1000 ]; // ch == 0 ASSERT! + ch = a[ 0 ]; // ch == 't' + ch = a[ 1 ]; // ch == 'e' + ch = a[ 2 ]; // ch == 's' + ch = a[ 3 ]; // ch == 't' + ch = a[ 4 ]; // ch == '\0' ASSERT! + ch = a[ 5 ]; // ch == '\0' ASSERT! + + a[ 1 ] = 'b'; // a.len == 4, a.data == "tbst\0" + a[ -1 ] = 'b'; // a.len == 4, a.data == "tbst\0" ASSERT! + a[ 0 ] = '0'; // a.len == 4, a.data == "0bst\0" + a[ 1 ] = '1'; // a.len == 4, a.data == "01st\0" + a[ 2 ] = '2'; // a.len == 4, a.data == "012t\0" + a[ 3 ] = '3'; // a.len == 4, a.data == "0123\0" + a[ 4 ] = '4'; // a.len == 4, a.data == "0123\0" ASSERT! + a[ 5 ] = '5'; // a.len == 4, a.data == "0123\0" ASSERT! + a[ 7 ] = '7'; // a.len == 4, a.data == "0123\0" ASSERT! + + a = "test"; // a.len == 4, a.data == "test\0" + b = "no"; // b.len == 2, b.data == "no\0" + + i = ( a == b ); // i == 0 + i = ( a == c ); // i == 1 + + i = ( a == "blow" ); // i == 0 + i = ( a == "test" ); // i == 1 + i = ( a == NULL ); // i == 0 ASSERT! + + i = ( "test" == b ); // i == 0 + i = ( "test" == a ); // i == 1 + i = ( NULL == a ); // i == 0 ASSERT! + + i = ( a != b ); // i == 1 + i = ( a != c ); // i == 0 + + i = ( a != "blow" ); // i == 1 + i = ( a != "test" ); // i == 0 + i = ( a != NULL ); // i == 1 ASSERT! + + i = ( "test" != b ); // i == 1 + i = ( "test" != a ); // i == 0 + i = ( NULL != a ); // i == 1 ASSERT! + + a = "test"; // a.data == "test" + b = a; // b.data == "test" + + a = "not"; // a.data == "not", b.data == "test" + + a = b; // a.data == b.data == "test" + + a += b; // a.data == "testtest", b.data = "test" + + a = b; + + a[1] = '1'; // a.data = "t1st", b.data = "test" + } + +#ifdef _WIN32 +#pragma warning(default : 4189) // local variable is initialized but not referenced +#pragma warning(disable : 4514) // unreferenced inline function has been removed +#endif diff --git a/libs/synapse/synapse.cpp b/libs/synapse/synapse.cpp index d223d03f..432a02c6 100644 --- a/libs/synapse/synapse.cpp +++ b/libs/synapse/synapse.cpp @@ -1,1101 +1,1101 @@ -/* -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 -*/ - -#include - -// seems to be required for str.h -#include -#include - -#include "synapse.h" -#if defined (__linux__) || defined (__APPLE__) - #include -#endif - -/* -=================================================== -diagnostic stuff -=================================================== -*/ - -extern "C" -{ - -static PFN_SYN_PRINTF_VA g_pPrintf = NULL; - -void Set_Syn_Printf(PFN_SYN_PRINTF_VA pf) -{ - g_pPrintf = pf; -} - -#define BUFFER_SIZE 4096 - -void Syn_Printf (const char *text, ...) -{ - char buf[BUFFER_SIZE]; - va_list args; - - if (!text) - return; - - if (g_pPrintf) - { - va_start (args, text); - (*g_pPrintf)(text, args); - va_end (args); - } - else - { - va_start (args, text); - vsnprintf (buf, BUFFER_SIZE, text, args); - buf[BUFFER_SIZE-1] = 0; - printf(buf); - va_end (args); - } -} - -} - -/* -======================================================================= -server -======================================================================= -*/ - -// this must be kept in sync with EAPIType -static const char* APITypeName[4] = -{ - "SYN_UNKNOWN", - "SYN_PROVIDE", - "SYN_REQUIRE", - "SYN_REQUIRE_ANY" -}; - -CSynapseServer::CSynapseServer() -{ - mpDoc = NULL; - m_api_name = NULL; - m_content = NULL; - mpFocusedNode = NULL; -} - -CSynapseServer::~CSynapseServer() -{ - if (m_api_name) - xmlFree(m_api_name); - if (m_content) - g_free(m_content); - Syn_Printf("TODO: free API managers\n"); -} - -void CSynapseServer::AddSearchPath(char* path) -{ - char *pLocalPath = new char[strlen(path)+1]; - strcpy(pLocalPath, path); - mSearchPaths.push_front(pLocalPath); -} - -bool CSynapseServer::Initialize(const char* conf_file, PFN_SYN_PRINTF_VA pf) -{ - // browse the paths to locate all potential modules - - Set_Syn_Printf(pf); - - if (conf_file) - { - // if a config file is specified and we fail to load it, we fail - Syn_Printf("loading synapse XML config file '%s'\n", conf_file); - mpDoc = xmlParseFile(conf_file); - if (!mpDoc) - { - Syn_Printf("'%s' invalid/not found\n", conf_file); - return false; - } - } - - for (list::iterator iPath=mSearchPaths.begin(); iPath!=mSearchPaths.end(); iPath++) - { - const char* path = *iPath; - - Syn_Printf("Synapse Scanning modules path: %s\n", path); - - GDir* dir = g_dir_open (path, 0, NULL); - - if (dir != NULL) - { - while (1) - { - const gchar* name = g_dir_read_name(dir); - if(name == NULL) - break; - - // too small to be isolated in win32/ and linux/ directories.. -#if defined(_WIN32) - const char* ext_so = ".dll"; -#elif defined (__linux__) || defined (__APPLE__) - const char* ext_so = ".so"; -#endif - const char* ext = strrchr (name, '.'); - if ((ext == NULL) || (stricmp (ext, ext_so) != 0)) - continue; - - Str newModule; - newModule.Format("%s%s", path, name); - Syn_Printf("Found '%s'\n", newModule.GetBuffer()); - EnumerateInterfaces(newModule); - } - - g_dir_close(dir); - } - } - return true; -} - -#if defined(_WIN32) -#define FORMAT_BUFSIZE 2048 -const char* CSynapseServer::FormatGetLastError() -{ - static char buf[FORMAT_BUFSIZE]; - FormatMessage( - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - buf, - FORMAT_BUFSIZE, - NULL - ); - return buf; -} - -void CSynapseServer::EnumerateInterfaces(Str &soname) -{ - CSynapseClientSlot slot; - slot.mpDLL = LoadLibrary(soname.GetBuffer()); - if (!slot.mpDLL) - { - Syn_Printf("LoadLibrary '%s' failed\n", soname.GetBuffer()); - Syn_Printf(" GetLastError: %s", FormatGetLastError()); - return; - } - slot.mpEnumerate = (PFN_SYNAPSE_ENUMERATEINTERFACES)GetProcAddress(slot.mpDLL, NAME_SYNAPSE_ENUMERATEINTERFACES); - if (!slot.mpEnumerate) - { - Syn_Printf("GetProcAddress('%s') failed\n", NAME_SYNAPSE_ENUMERATEINTERFACES); - Syn_Printf(" GetLastError: %s", FormatGetLastError()); - return; - } - Syn_Printf("Enumerate interfaces on '%s'\n", soname.GetBuffer()); - slot.mpClient = slot.mpEnumerate(SYNAPSE_VERSION, this); - if (!slot.mpClient) - { - Syn_Printf("Enumerate interfaces on '%s' returned NULL, unloading.\n", soname.GetBuffer()); - if (!FreeLibrary(slot.mpDLL)) - { - Syn_Printf(" FreeLibrary failed: GetLastError: '%s'\n", CSynapseServer::FormatGetLastError()); - } - return; - } - slot.mFileName = soname; - mClients.push_front(slot); -} - -void CSynapseClientSlot::ReleaseSO() -{ - if (!mpDLL) - { - Syn_Printf("ERROR: no shared object handle for client '%s' in CSynapseClientSlot::ReleaseSO\n", mpClient->GetInfo()); - return; - } - Syn_Printf("FreeLibrary '%s'\n", mpClient->GetInfo()); - if (!FreeLibrary(mpDLL)) - { - Syn_Printf(" FreeLibrary failed: GetLastError: '%s'\n", CSynapseServer::FormatGetLastError()); - } - mpDLL = NULL; -} - -#elif defined(__linux__) || defined (__APPLE__) -void CSynapseServer::EnumerateInterfaces(Str &soname) -{ - CSynapseClientSlot slot; - slot.mpDLL = dlopen (soname.GetBuffer(), RTLD_NOW); - PFN_SYNAPSE_ENUMERATEINTERFACES *pEnumerate; - if (!slot.mpDLL) - { - char* error; - if ((error = (char *)dlerror()) == NULL) - error = "Unknown"; - Syn_Printf("dlopen '%s' failed\n dlerror: '%s'\n", soname.GetBuffer(), error); - return; - } - slot.mpEnumerate = (PFN_SYNAPSE_ENUMERATEINTERFACES)dlsym(slot.mpDLL, NAME_SYNAPSE_ENUMERATEINTERFACES); - if (!slot.mpEnumerate) - { - char* error; - if ((error = (char *)dlerror()) == NULL) - error = "Unknown"; - Syn_Printf("dlsym '%s' failed on shared object '%s'\n dlerror: '%s'\n", NAME_SYNAPSE_ENUMERATEINTERFACES, soname.GetBuffer(), error); - return; - } - Syn_Printf("Enumerate interfaces on '%s'\n", soname.GetBuffer()); - slot.mpClient = slot.mpEnumerate(SYNAPSE_VERSION, this); - if (!slot.mpClient) - { - Syn_Printf("Enumerate interfaces on '%s' returned NULL, unloading.\n", soname.GetBuffer()); - if (dlclose(slot.mpDLL)) - { - char* error; - if ((error = (char *)dlerror()) == NULL) - error = "Unknown"; - Syn_Printf(" dlclose failed: dlerror: '%s'\n", error); - } - return; - } - slot.mFileName = soname; - mClients.push_front(slot); -} - -void CSynapseClientSlot::ReleaseSO() -{ - if (!mpDLL) - { - Syn_Printf("ERROR: no shared object handle for client '%s' in CSynapseClientSlot::ReleaseSO\n", mpClient->GetInfo()); - return; - } - Syn_Printf("dlclose '%s'\n", mpClient->GetInfo()); - if (dlclose(mpDLL)) - { - char* error; - if ((error = (char *)dlerror()) == NULL) - error = "Unknown"; - Syn_Printf(" dlclose failed: dlerror: '%s'\n", error); - } - mpDLL = NULL; -} - -#endif - -void CSynapseServer::EnumerateBuiltinModule(CSynapseBuiltinClient *pClient) -{ - CSynapseClientSlot slot; - pClient->EnumerateInterfaces(this); - slot.mpClient = pClient; - slot.mType = SYN_BUILTIN; - mClients.push_front(slot); -} - -PFN_SYN_PRINTF_VA CSynapseServer::Get_Syn_Printf() -{ - return g_pPrintf; -} - -void CSynapseServer::TryPushStack(APIDescriptor_t *pAPI) -{ - list::iterator iAPI; - for(iAPI=mStack.begin(); iAPI!=mStack.end(); iAPI++) - { - if ((*iAPI) == pAPI) - { - return; - } - } - mStack.push_front(pAPI); - mbStackChanged = true; -} - -list::iterator CSynapseServer::ShutdownClient(list::iterator iSlot) -{ - CSynapseClientSlot *pClientSlot = &(*iSlot); - if (pClientSlot->mpClient->IsActive()) - { - // this should not happen except during core shutdown (i.e. editor is shutting down) - Syn_Printf("WARNING: ShutdownClient attempted on an active module '%s'\n", pClientSlot->mpClient->GetInfo()); - } - // cleanup mStack - int i,api_count; - api_count = pClientSlot->mpClient->GetAPICount(); - for(i=0; impClient->GetAPIDescriptor(i); - // search this API in mStack - list< APIDescriptor_t *>::iterator iStack = mStack.begin(); - while(iStack != mStack.end()) - { - if (*iStack == pAPI) - break; - iStack++; - } - if (iStack != mStack.end()) - { - if (pAPI->mType == SYN_REQUIRE) - { - if (pAPI->mbTableInitDone) - { - // even if non active, some SYN_REQUIRE may have been filled up - // look for the corresponding SYN_PROVIDE and decref - list< APIDescriptor_t *>::iterator iStackRequire = mStack.begin(); - APIDescriptor_t *pMatchAPI; - while (iStackRequire != mStack.end()) - { - pMatchAPI = *iStackRequire; - if ( pMatchAPI->mType == SYN_PROVIDE && MatchAPI( pMatchAPI, pAPI ) ) - break; - iStackRequire++; - } - if (iStackRequire != mStack.end()) - { - // we have found the corresponding SYN_PROVIDE - pMatchAPI->mRefCount--; - } - else - { - // this is not supposed to happen at all - Syn_Printf("ERROR: couldn't find the SYN_PROVIDE for an initialized SYN_REQUIRE API '%s' '%s' '%s'\n", pAPI->major_name, pAPI->minor_name, pClientSlot->mpClient->GetInfo()); - } - } - } - else if (pAPI->mType == SYN_PROVIDE) - { - // this should never happen on non active clients, it may happen during a core shutdown though - // if the mRefCount is != 0, that means there is at least a function table out there that will segfault things - Syn_Printf("WARNING: found a SYN_PROVIDE API '%s' '%s' with refcount %d in CSynapseServer::ShutdownClient for '%s'\n", pAPI->major_name, pAPI->minor_name, pAPI->mRefCount, pClientSlot->mpClient->GetInfo()); - } - // mostly safe to remove it now - mStack.erase(iStack); - } - } - // we can actually release the module now - // NOTE: do we want to have a 'final shutdown' call to the client? (not as long as we don't have a use for it) - if (pClientSlot->mType == SYN_SO) - { - pClientSlot->ReleaseSO(); - } - return mClients.erase(iSlot); -} - -void CSynapseServer::PushRequired(CSynapseClient *pClient) -{ - /* walk through the standard APIs and push them in */ - int i,max = pClient->GetAPICount(); - for(i=0; iGetAPIDescriptor(i); - if (pAPI->mType == SYN_REQUIRE && !pAPI->mbTableInitDone) - { - TryPushStack(pAPI); - } - } - - /* if this client has 'List' API Manager types, walk through them for addition too */ - max = pClient->GetManagerListCount(); - for(i=0; iGetManagerList(i); - assert(pManager->GetType() == API_LIST); - pManager->InitializeAPIList(); - int j; - for(j=0; jGetAPICount(); j++) - { - TryPushStack(pManager->GetAPI(j)); - } - } - - /* if there are loose match managers, prompt them against the current list of SYN_PROVIDE interfaces - * and let them decide which ones they might want - */ - - max = pClient->GetManagerMatchCount(); - - for(i=0; iGetManagerMatch(i); - // start matching all known SYN_PROVIDE APIs against this manager - list::iterator iClientSlot; - for(iClientSlot=mClients.begin(); iClientSlot!=mClients.end(); iClientSlot++) - { - CSynapseClient *pScanClient = (*iClientSlot). - mpClient; - int j,jmax = pScanClient->GetAPICount(); - for(j=0; jGetAPIDescriptor(j); - if (pAPI->mType == SYN_PROVIDE) - { - if (pManager->MatchAPI(pAPI->major_name, pAPI->minor_name)) - { - /*! we are going to want to load this one - * NOTE TTimo: what if this can not be resolved in the end? - * if this happens, then the whole startup will fail instead - * or we can use SYN_REQUIRE_ANY and drop it without consequences - */ - APIDescriptor_t *pPushAPI = pManager->BuildRequireAPI(pAPI); - TryPushStack(pPushAPI); - } - } - } - } - } -} - -bool CSynapseServer::MatchAPI(APIDescriptor_t *p1, APIDescriptor_t *p2) -{ - return MatchAPI( p1->major_name, p1->minor_name, p2->major_name, p2->minor_name ); -} - -bool CSynapseServer::MatchAPI(const char* major1, const char* minor1, const char* major2, const char* minor2) -{ - if ( strcmp( major1, major2 ) ) { - return false; - } - // either no minor at all for this API, or matching - if ( ( minor1 && minor2 ) && !strcmp( minor1, minor2 ) ) { - return true; - } - // or one of the minors says "*" (knowing that the majors match already) - if ( ( minor1 && !strcmp( minor1, "*" ) ) || ( minor2 && !strcmp( minor2, "*" ) ) ) { - return true; - } - return false; -} - -bool CSynapseServer::ResolveAPI(APIDescriptor_t* pAPI) -{ - //Syn_Printf("In ResolveAPI %s %p '%s' '%s'\n", APITypeName[pAPI->mType], pAPI, pAPI->major_name, pAPI->minor_name); - // loop through active clients, search for a client providing what we are looking for - list::iterator iClient; - for(iClient=mClients.begin(); iClient!=mClients.end(); iClient++) - { - // walk through interfaces on this client for a match - CSynapseClient *pScanClient = (*iClient).mpClient; - int i,max = pScanClient->GetAPICount(); - for(i=0; iGetAPIDescriptor(i); - if (pScanClientAPI->mType == SYN_PROVIDE) - { - if (MatchAPI(pAPI, pScanClientAPI)) - { - // can this client provide APIs yet - // it is possible that all of it's APIs have been filled and it's not been activated yet - pScanClient->CheckSetActive(); - if (pScanClient->IsActive()) - { - // make sure this interface has correct size (this is our version check) - if (pAPI->mSize != pScanClientAPI->mSize) - { - Syn_Printf("ERROR: version mismatch for API '%s' '%s' found in '%s' (size %d != %d)\n", pAPI->major_name, pAPI->minor_name, pScanClient->GetInfo(), pAPI->mSize, pScanClientAPI->mSize); - Syn_Printf(" the module and the server are incompatible\n"); - // keep going to other APIs - continue; - } - // this is an active client, we can request - #ifdef SYNAPSE_VERBOSE - Syn_Printf("RequestAPI '%s' '%s' from '%s' for API %p\n", pAPI->major_name, pAPI->minor_name, pScanClient->GetInfo(), pAPI); - #endif - if (!pScanClient->RequestAPI(pAPI)) - { - // this should never happen, means we think this module provides the API, but it answers that it doesn't - Syn_Printf("ERROR: RequestAPI failed\n"); - return false; - } - pScanClientAPI->mRefCount++; - pAPI->mbTableInitDone = true; - return true; // job done - } - else - { - // this client is not active yet, some of it's required interfaces are not filled in - PushRequired(pScanClient); - // we will exit the scan through the APIDescriptor of this client and look at other clients - break; - } - } - } - } - } - return false; -} - -bool CSynapseServer::DoResolve(CSynapseClient *pClient) -{ - list::iterator iSlot; - for(iSlot=mClients.begin(); iSlot != mClients.end(); iSlot++) - { - if ((*iSlot).mpClient == pClient) - break; - } - if (iSlot == mClients.end()) - { - Syn_Printf("CSynapserServer::Resolve adding new client slot '%s'\n", pClient->GetInfo()); - CSynapseClientSlot slot; - slot.mpClient = pClient; - slot.mFileName = "local client"; - // make it active so we can request the interfaces already - pClient->ForceSetActive(); - mClients.push_front(slot); - } - else - { - // make it active so we can request the interfaces already - (*iSlot).mpClient->ForceSetActive(); - } - - // push the interfaces that need to be resolved for this client - // NOTE: this doesn't take care of the SYN_REQUIRE_ANY interfaces - PushRequired(pClient); - // start resolving now - // working till the stack is emptied or till we reach a dead end situation - // we do a depth first traversal, we will grow the interface stack to be resolved till we start finding solutions - list::iterator iCurrent; - mbStackChanged = true; // init to true so we try the first elem - while (!mStack.empty()) - { - //DumpStack(); - if (!mbStackChanged) - { - // the stack didn't change last loop - iCurrent++; - if (iCurrent==mStack.end()) - { - Syn_Printf("ERROR: CSynapseServer::Resolve, failed to resolve\n"); - DumpStack(); - return false; - } - if (ResolveAPI(*iCurrent)) - { - iCurrent = mStack.erase(iCurrent); - mbStackChanged = true; - } - } - else - { - // the stack changed at last loop - mbStackChanged = false; - iCurrent = mStack.begin(); - if (ResolveAPI(*iCurrent)) - { - iCurrent = mStack.erase(iCurrent); - mbStackChanged = true; - } - } - } - return true; -} - -bool CSynapseServer::Resolve(CSynapseClient *pClient) -{ - bool ret = DoResolve(pClient); - list::iterator iClient; - iClient = mClients.begin(); - while(iClient != mClients.end()) - { - CSynapseClient *pClient = (*iClient).mpClient; - if (!pClient->IsActive()) - { - Syn_Printf("Unloading an unused module: '%s'\n", pClient->GetInfo()); - iClient = ShutdownClient(iClient); - } - else - iClient++; - } - return ret; -} - -void CSynapseServer::Shutdown() -{ - Syn_Printf("Synapse server core is shutting down\n"); - // do a first pass to shutdown the clients nicely (i.e. decref, release memory and drop everything) - // we seperate the client shutdown calls from the dlclose cause that part is a clean decref / free situation whereas dlclose will break links without advice - list::iterator iClient; - iClient = mClients.begin(); - for(iClient = mClients.begin(); iClient != mClients.end(); iClient++) - { - (*iClient).mpClient->Shutdown(); - } - // now release them from the server's point of view - iClient = mClients.begin(); - while(iClient != mClients.end()) - { - iClient = ShutdownClient(iClient); - } -} - -void CSynapseServer::DumpStack() -{ - list::iterator iCurrent; - for(iCurrent=mStack.begin(); iCurrent != mStack.end(); iCurrent++) - { - APIDescriptor_t*pAPI = *iCurrent; - Syn_Printf("interface %s %p '%s' '%s'\n", APITypeName[pAPI->mType], pAPI, pAPI->major_name, pAPI->minor_name); - } -} - -void CSynapseServer::DumpActiveClients() -{ - list::iterator iClient; - for(iClient=mClients.begin(); iClient!=mClients.end(); iClient++) - { - CSynapseClient *pClient = (*iClient).mpClient; - Syn_Printf("%s", pClient->GetInfo()); - if (pClient->IsActive()) - Syn_Printf("\n"); - else - Syn_Printf(" (not active)\n"); - } -} - -bool CSynapseServer::SelectClientConfig(const char *client_name) -{ - if (!mpDoc) - return false; - xmlNodePtr pNode = xmlDocGetRootElement(mpDoc); - if (!pNode) - return false; - // look for the client - pNode=pNode->children; - while(pNode) - { - if (pNode->type == XML_ELEMENT_NODE) - { - xmlChar *prop = xmlGetProp(pNode, (const xmlChar *)"name"); - if (!strcmp((const char *)prop, client_name)) - { - xmlFree(prop); - break; - } - xmlFree(prop); - } - pNode = pNode->next; - } - if (!pNode) - return false; // config you asked for isn't there - // focus - mpFocusedNode = pNode->children; - mpCurrentClientConfig = pNode; - return true; -} - -bool CSynapseServer::GetNextConfig(char **api_name, char **minor) -{ - while(mpFocusedNode && mpFocusedNode->name) - { - if (mpFocusedNode->type == XML_ELEMENT_NODE && !strcmp((const char *)mpFocusedNode->name, "api")) - { - if (m_api_name) - xmlFree(m_api_name); - m_api_name = xmlGetProp(mpFocusedNode, (const xmlChar *)"name"); - *api_name = (char *)m_api_name; - if (m_content) - g_free(m_content); - m_content = g_strdup((const gchar *)mpFocusedNode->children->content); - g_strstrip(m_content); - *minor = m_content; - mpFocusedNode = mpFocusedNode->next; - return true; - } - mpFocusedNode = mpFocusedNode->next; - } - return false; -} - -bool CSynapseServer::GetConfigForAPI( const char *api, char **minor ) { - xmlNodePtr pNode = mpCurrentClientConfig->children; - while ( pNode && pNode->name ) { - if ( pNode->type == XML_ELEMENT_NODE && !strcmp( (const char *)pNode->name, "api" ) ) { - if ( m_api_name ) { - xmlFree( m_api_name ); - } - m_api_name = xmlGetProp( pNode, (const xmlChar *)"name" ); - if ( !strcmp( (const char *)m_api_name, api ) ) { - if ( m_content ) { - g_free( m_content ); - } - m_content = g_strdup( (const gchar *)pNode->children->content ); - g_strstrip( m_content ); - *minor = m_content; - return true; - } - } - pNode = pNode->next; - } - return false; -} - -const char *CSynapseServer::GetModuleFilename(CSynapseClient *pClient) -{ - list::iterator iSlot; - for(iSlot=mClients.begin(); iSlot != mClients.end(); iSlot++) - { - if ((*iSlot).mpClient == pClient) - { - if ((*iSlot).mType == SYN_BUILTIN) - { - return ""; // FIXME - } - else - { - return (*iSlot).mFileName; - } - } - } - return NULL; -} - -/* -======================================================================= -client -======================================================================= -*/ - -CSynapseClient::CSynapseClient() -{ -} - -void CSynapseClient::Shutdown() -{ - vector::iterator iAPI; - for(iAPI=mAPIDescriptors.begin(); iAPI!=mAPIDescriptors.end(); iAPI++) - { - APIDescriptor_t *pAPI = *iAPI; - if (pAPI->mRefCount != 0) - Syn_Printf("WARNING: ~CSynapseClient '%s' has non-zero ref count for interface '%s' '%s'\n", GetInfo(), pAPI->major_name, pAPI->minor_name); - else - delete pAPI; - *iAPI=NULL; - } - mAPIDescriptors.clear(); - vector::iterator iManager; - for(iManager=mManagersList.begin(); iManager!=mManagersList.end(); iManager++) - { - CSynapseAPIManager *pManager = *iManager; - pManager->DecRef(); - *iManager = NULL; - } - mManagersList.clear(); - for(iManager=mManagersMatch.begin(); iManager!=mManagersMatch.end(); iManager++) - { - CSynapseAPIManager *pManager = *iManager; - pManager->DecRef(); - *iManager = NULL; - } - mManagersMatch.clear(); -} - -CSynapseClient::~CSynapseClient() -{ - // this should not be doing anything when called from here if everything went right - // otherwise it's likely to crash .. at least that's the sign we missed something - Shutdown(); -} - -int CSynapseClient::GetAPICount() -{ - return mAPIDescriptors.size(); -} - -APIDescriptor_t* CSynapseClient::GetAPIDescriptor(int i) -{ - return mAPIDescriptors[i]; -} - -int CSynapseClient::GetManagerMatchCount() -{ - return mManagersMatch.size(); -} - -CSynapseAPIManager* CSynapseClient::GetManagerMatch(int i) -{ - return mManagersMatch[i]; -} - -int CSynapseClient::GetManagerListCount() -{ - return mManagersList.size(); -} - -CSynapseAPIManager* CSynapseClient::GetManagerList(int i) -{ - return mManagersList[i]; -} - -bool CSynapseClient::AddAPI(const char *major, const char *minor, int size, EAPIType type, void *pTable) -{ - // do some safe checks before actual addition - if (type == SYN_REQUIRE && !pTable) - { - Syn_Printf("ERROR: interface '%s' '%s' from '%s' is SYN_REQUIRE and doesn't provide a function table pointer\n", major, minor, GetInfo()); - return false; - } - if (pTable) - { - int *pi = (int *)pTable; - if (pi == 0) - { - Syn_Printf("ERROR: forgot to init function table size for interface '%s' '%s' from '%s'?\n", major, minor, GetInfo()); - return false; - } - } - APIDescriptor_t *pAPI = new APIDescriptor_t; - memset(pAPI, 0, sizeof(APIDescriptor_t)); - strncpy(pAPI->major_name, major, MAX_APINAME); - if (minor) - strncpy(pAPI->minor_name, minor, MAX_APINAME); - pAPI->mType = type; - pAPI->mpTable = pTable; - // store the interface size - if (type == SYN_PROVIDE) - { - if (size == 0) - { - Syn_Printf("ERROR: size of the interface required for a SYN_PROVIDE ('%s' '%s' from '%s')\n", major, minor, GetInfo()); - delete pAPI; - return false; - } - pAPI->mSize = size; - } - else if (type == SYN_REQUIRE) - { - if (size != 0) - { - // if a non-zero value is given in function call, use this instead of the val in table - *((int *)pAPI->mpTable) = size; - pAPI->mSize = size; - } - else - { - pAPI->mSize = *((int *)pAPI->mpTable); - if (pAPI->mSize == 0) - { - Syn_Printf("ERROR: didn't get an interface size ('%s' '%s' from '%s')\n", major, minor, GetInfo()); - delete pAPI; - return false; - } - } - } - else - { - Syn_Printf("ERROR: AddAPI type '%d' not supported\n", type); - return false; - } - mAPIDescriptors.push_back(pAPI); - #ifdef SYNAPSE_VERBOSE - Syn_Printf("AddAPI: %s %p '%s' '%s' from '%s', size %d\n", APITypeName[pAPI->mType], pAPI, major, minor, GetInfo(), pAPI->mSize); - #endif - return true; -} - -#include "version.h" - -const char* CSynapseClient::GetInfo() -{ - return "CSynapseClient built " __DATE__ " " RADIANT_VERSION; -} - -bool CSynapseClient::CheckSetActive() -{ - if (mbActive) - return true; - int i,max=GetAPICount(); - for(i=0; imType == SYN_REQUIRE && !pAPI->mbTableInitDone) - return false; - } - // if we have managers with fixed list, those need to be completely filled in too - vector::iterator iManager; - for(iManager=mManagersList.begin(); iManager!=mManagersList.end(); iManager++) - { - if (!(*iManager)->CheckSetActive()) - return false; // one of the managers doesn't have all it needs yet - } - // call OnActivate to let the client perform last minute checks - // NOTE: this should be fatal instead of letting the engine try other combinations - if (!OnActivate()) { - return false; - } - // yes, all required interfaces have been initialized - Syn_Printf("'%s' activated\n", GetInfo()); - mbActive = true; - return true; -} - -bool CSynapseClient::ConfigXML( CSynapseServer *pServer, const char *client_name, const XMLConfigEntry_t entries[] ) { - - if ( !client_name ) { - client_name = GetName(); - } - - Syn_Printf("Dynamic APIs for client '%s'\n", GetInfo()); - if ( !pServer->SelectClientConfig( client_name ) ) - { - Syn_Printf( "Failed to select synapse client config '%s'\n", client_name ); - return false; - } - - int i = 0; - while ( entries[i].type != SYN_UNKNOWN ) { // don't test pTable, for a SYN_PROVIDE it will be empty - char *minor; - if ( !pServer->GetConfigForAPI( entries[i].api, &minor ) ) { - Syn_Printf( "GetConfigForAPI '%s' failed - invalid XML config file?\n", entries[i].api ); - return false; - } - AddAPI( entries[i].api, minor, entries[i].size, entries[i].type, entries[i].pTable ); - i++; - } - Syn_Printf( "%d dynamic interfaces parsed for '%s'\n", i, client_name ); - return true; -} - -void CSynapseClient::AddManager(CSynapseAPIManager *pManager) -{ - pManager->IncRef(); - if (pManager->GetType() == API_LIST) - mManagersList.push_back(pManager); - else - mManagersMatch.push_back(pManager); -} - -CSynapseAPIManager::~CSynapseAPIManager() -{ - vector::iterator iAPI; - for(iAPI=mAPIs.begin(); iAPI!=mAPIs.end(); iAPI++) - { - APIDescriptor_t *pAPI = *iAPI; - if (pAPI->mRefCount != 0) - { - Syn_Printf("WARNING: ~CSynapseAPIManager has non-zero ref count for interface '%s' '%s'\n", pAPI->major_name, pAPI->minor_name); - } - delete pAPI; - *iAPI = NULL; - } -} - -APIDescriptor_t* CSynapseAPIManager::PrepareRequireAPI(APIDescriptor_t *pAPI) -{ -#ifdef _DEBUG - if (pAPI->mType != SYN_PROVIDE) - { - Syn_Printf("ERROR: unexpected pAPI->mType != SYN_PROVIDE in CSynapseAPIManager::PrepareRequireAPI\n"); - return NULL; - } -#endif - APIDescriptor_t *pRequireAPI = new APIDescriptor_t; - memcpy(pRequireAPI, pAPI, sizeof(APIDescriptor_t)); - pRequireAPI->mType = SYN_REQUIRE_ANY; - pRequireAPI->mpTable = NULL; - pRequireAPI->mbTableInitDone = false; - pRequireAPI->mSize = 0; // this will have to be set correctly by the child for version checking - pRequireAPI->mRefCount = 0; - return pRequireAPI; -} - -void CSynapseAPIManager::SetMatchAPI(const char *major, const char *minor) -{ - if (strlen(minor)>MAX_PATTERN_STRING) - { - Syn_Printf("ERROR: MAX_TOKEN_STRING exceeded in CSynapseAPIManager::SetMatchAPI: '%s'\n", minor); - return; - } - strcpy(major_pattern, major); - strcpy(minor_pattern, minor); - if (strcmp(minor, "*")) - { - mType = API_LIST; - } -} - -bool CSynapseAPIManager::MatchAPI(const char *major, const char *minor) -{ - assert(mType == API_MATCH); - - /*! - if this interface has been allocated already, avoid requesting it again.. - */ - vector::iterator iAPI; - for(iAPI=mAPIs.begin(); iAPI!=mAPIs.end(); iAPI++) - { - if (CSynapseServer::MatchAPI((*iAPI)->major_name, (*iAPI)->minor_name, major, minor)) - return false; - } - - if (!strcmp(major, major_pattern)) - return true; - return false; -} - -bool CSynapseAPIManager::CheckSetActive() -{ - if (mType == API_MATCH) - return false; - // mType == API_LIST - int i,max = GetAPICount(); - for(i=0; imbTableInitDone) - return false; - } - return true; -} - -void CSynapseAPIManager::InitializeAPIList() -{ - char minor_tok[MAX_PATTERN_STRING]; - char *token; - - if (mAPIs.size()) - { - Syn_Printf("WARNING: CSynapseAPIManager::InitializeAPIList on an already initialized APIManager\n"); - return; - } - - strncpy(minor_tok, minor_pattern, MAX_PATTERN_STRING); - token = strtok(minor_tok, " "); - while (token) - { - /* ask the child to build from scratch */ - APIDescriptor_t *pAPI = new APIDescriptor_t; - memset(pAPI, 0, sizeof(APIDescriptor_t)); - strncpy(pAPI->major_name, major_pattern, MAX_APINAME); - strncpy(pAPI->minor_name, token, MAX_APINAME); - pAPI->mType = SYN_REQUIRE_ANY; - FillAPITable(pAPI); - mAPIs.push_back(pAPI); - token = strtok(NULL, " "); - } -} - -int CSynapseAPIManager::GetAPICount() -{ - return mAPIs.size(); -} - -APIDescriptor_t* CSynapseAPIManager::GetAPI(int i) -{ - return mAPIs[i]; -} - -// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=879 -void fini_stub() { - printf( "fini_stub\n" ); -} +/* +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 +*/ + +#include + +// seems to be required for str.h +#include +#include + +#include "synapse.h" +#if defined (__linux__) || defined (__APPLE__) + #include +#endif + +/* +=================================================== +diagnostic stuff +=================================================== +*/ + +extern "C" +{ + +static PFN_SYN_PRINTF_VA g_pPrintf = NULL; + +void Set_Syn_Printf(PFN_SYN_PRINTF_VA pf) +{ + g_pPrintf = pf; +} + +#define BUFFER_SIZE 4096 + +void Syn_Printf (const char *text, ...) +{ + char buf[BUFFER_SIZE]; + va_list args; + + if (!text) + return; + + if (g_pPrintf) + { + va_start (args, text); + (*g_pPrintf)(text, args); + va_end (args); + } + else + { + va_start (args, text); + vsnprintf (buf, BUFFER_SIZE, text, args); + buf[BUFFER_SIZE-1] = 0; + printf(buf); + va_end (args); + } +} + +} + +/* +======================================================================= +server +======================================================================= +*/ + +// this must be kept in sync with EAPIType +static const char* APITypeName[4] = +{ + "SYN_UNKNOWN", + "SYN_PROVIDE", + "SYN_REQUIRE", + "SYN_REQUIRE_ANY" +}; + +CSynapseServer::CSynapseServer() +{ + mpDoc = NULL; + m_api_name = NULL; + m_content = NULL; + mpFocusedNode = NULL; +} + +CSynapseServer::~CSynapseServer() +{ + if (m_api_name) + xmlFree(m_api_name); + if (m_content) + g_free(m_content); + Syn_Printf("TODO: free API managers\n"); +} + +void CSynapseServer::AddSearchPath(char* path) +{ + char *pLocalPath = new char[strlen(path)+1]; + strcpy(pLocalPath, path); + mSearchPaths.push_front(pLocalPath); +} + +bool CSynapseServer::Initialize(const char* conf_file, PFN_SYN_PRINTF_VA pf) +{ + // browse the paths to locate all potential modules + + Set_Syn_Printf(pf); + + if (conf_file) + { + // if a config file is specified and we fail to load it, we fail + Syn_Printf("loading synapse XML config file '%s'\n", conf_file); + mpDoc = xmlParseFile(conf_file); + if (!mpDoc) + { + Syn_Printf("'%s' invalid/not found\n", conf_file); + return false; + } + } + + for (list::iterator iPath=mSearchPaths.begin(); iPath!=mSearchPaths.end(); iPath++) + { + const char* path = *iPath; + + Syn_Printf("Synapse Scanning modules path: %s\n", path); + + GDir* dir = g_dir_open (path, 0, NULL); + + if (dir != NULL) + { + while (1) + { + const gchar* name = g_dir_read_name(dir); + if(name == NULL) + break; + + // too small to be isolated in win32/ and linux/ directories.. +#if defined(_WIN32) + const char* ext_so = ".dll"; +#elif defined (__linux__) || defined (__APPLE__) + const char* ext_so = ".so"; +#endif + const char* ext = strrchr (name, '.'); + if ((ext == NULL) || (stricmp (ext, ext_so) != 0)) + continue; + + Str newModule; + newModule.Format("%s%s", path, name); + Syn_Printf("Found '%s'\n", newModule.GetBuffer()); + EnumerateInterfaces(newModule); + } + + g_dir_close(dir); + } + } + return true; +} + +#if defined(_WIN32) +#define FORMAT_BUFSIZE 2048 +const char* CSynapseServer::FormatGetLastError() +{ + static char buf[FORMAT_BUFSIZE]; + FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + buf, + FORMAT_BUFSIZE, + NULL + ); + return buf; +} + +void CSynapseServer::EnumerateInterfaces(Str &soname) +{ + CSynapseClientSlot slot; + slot.mpDLL = LoadLibrary(soname.GetBuffer()); + if (!slot.mpDLL) + { + Syn_Printf("LoadLibrary '%s' failed\n", soname.GetBuffer()); + Syn_Printf(" GetLastError: %s", FormatGetLastError()); + return; + } + slot.mpEnumerate = (PFN_SYNAPSE_ENUMERATEINTERFACES)GetProcAddress(slot.mpDLL, NAME_SYNAPSE_ENUMERATEINTERFACES); + if (!slot.mpEnumerate) + { + Syn_Printf("GetProcAddress('%s') failed\n", NAME_SYNAPSE_ENUMERATEINTERFACES); + Syn_Printf(" GetLastError: %s", FormatGetLastError()); + return; + } + Syn_Printf("Enumerate interfaces on '%s'\n", soname.GetBuffer()); + slot.mpClient = slot.mpEnumerate(SYNAPSE_VERSION, this); + if (!slot.mpClient) + { + Syn_Printf("Enumerate interfaces on '%s' returned NULL, unloading.\n", soname.GetBuffer()); + if (!FreeLibrary(slot.mpDLL)) + { + Syn_Printf(" FreeLibrary failed: GetLastError: '%s'\n", CSynapseServer::FormatGetLastError()); + } + return; + } + slot.mFileName = soname; + mClients.push_front(slot); +} + +void CSynapseClientSlot::ReleaseSO() +{ + if (!mpDLL) + { + Syn_Printf("ERROR: no shared object handle for client '%s' in CSynapseClientSlot::ReleaseSO\n", mpClient->GetInfo()); + return; + } + Syn_Printf("FreeLibrary '%s'\n", mpClient->GetInfo()); + if (!FreeLibrary(mpDLL)) + { + Syn_Printf(" FreeLibrary failed: GetLastError: '%s'\n", CSynapseServer::FormatGetLastError()); + } + mpDLL = NULL; +} + +#elif defined(__linux__) || defined (__APPLE__) +void CSynapseServer::EnumerateInterfaces(Str &soname) +{ + CSynapseClientSlot slot; + slot.mpDLL = dlopen (soname.GetBuffer(), RTLD_NOW); + PFN_SYNAPSE_ENUMERATEINTERFACES *pEnumerate; + if (!slot.mpDLL) + { + char* error; + if ((error = (char *)dlerror()) == NULL) + error = "Unknown"; + Syn_Printf("dlopen '%s' failed\n dlerror: '%s'\n", soname.GetBuffer(), error); + return; + } + slot.mpEnumerate = (PFN_SYNAPSE_ENUMERATEINTERFACES)dlsym(slot.mpDLL, NAME_SYNAPSE_ENUMERATEINTERFACES); + if (!slot.mpEnumerate) + { + char* error; + if ((error = (char *)dlerror()) == NULL) + error = "Unknown"; + Syn_Printf("dlsym '%s' failed on shared object '%s'\n dlerror: '%s'\n", NAME_SYNAPSE_ENUMERATEINTERFACES, soname.GetBuffer(), error); + return; + } + Syn_Printf("Enumerate interfaces on '%s'\n", soname.GetBuffer()); + slot.mpClient = slot.mpEnumerate(SYNAPSE_VERSION, this); + if (!slot.mpClient) + { + Syn_Printf("Enumerate interfaces on '%s' returned NULL, unloading.\n", soname.GetBuffer()); + if (dlclose(slot.mpDLL)) + { + char* error; + if ((error = (char *)dlerror()) == NULL) + error = "Unknown"; + Syn_Printf(" dlclose failed: dlerror: '%s'\n", error); + } + return; + } + slot.mFileName = soname; + mClients.push_front(slot); +} + +void CSynapseClientSlot::ReleaseSO() +{ + if (!mpDLL) + { + Syn_Printf("ERROR: no shared object handle for client '%s' in CSynapseClientSlot::ReleaseSO\n", mpClient->GetInfo()); + return; + } + Syn_Printf("dlclose '%s'\n", mpClient->GetInfo()); + if (dlclose(mpDLL)) + { + char* error; + if ((error = (char *)dlerror()) == NULL) + error = "Unknown"; + Syn_Printf(" dlclose failed: dlerror: '%s'\n", error); + } + mpDLL = NULL; +} + +#endif + +void CSynapseServer::EnumerateBuiltinModule(CSynapseBuiltinClient *pClient) +{ + CSynapseClientSlot slot; + pClient->EnumerateInterfaces(this); + slot.mpClient = pClient; + slot.mType = SYN_BUILTIN; + mClients.push_front(slot); +} + +PFN_SYN_PRINTF_VA CSynapseServer::Get_Syn_Printf() +{ + return g_pPrintf; +} + +void CSynapseServer::TryPushStack(APIDescriptor_t *pAPI) +{ + list::iterator iAPI; + for(iAPI=mStack.begin(); iAPI!=mStack.end(); iAPI++) + { + if ((*iAPI) == pAPI) + { + return; + } + } + mStack.push_front(pAPI); + mbStackChanged = true; +} + +list::iterator CSynapseServer::ShutdownClient(list::iterator iSlot) +{ + CSynapseClientSlot *pClientSlot = &(*iSlot); + if (pClientSlot->mpClient->IsActive()) + { + // this should not happen except during core shutdown (i.e. editor is shutting down) + Syn_Printf("WARNING: ShutdownClient attempted on an active module '%s'\n", pClientSlot->mpClient->GetInfo()); + } + // cleanup mStack + int i,api_count; + api_count = pClientSlot->mpClient->GetAPICount(); + for(i=0; impClient->GetAPIDescriptor(i); + // search this API in mStack + list< APIDescriptor_t *>::iterator iStack = mStack.begin(); + while(iStack != mStack.end()) + { + if (*iStack == pAPI) + break; + iStack++; + } + if (iStack != mStack.end()) + { + if (pAPI->mType == SYN_REQUIRE) + { + if (pAPI->mbTableInitDone) + { + // even if non active, some SYN_REQUIRE may have been filled up + // look for the corresponding SYN_PROVIDE and decref + list< APIDescriptor_t *>::iterator iStackRequire = mStack.begin(); + APIDescriptor_t *pMatchAPI; + while (iStackRequire != mStack.end()) + { + pMatchAPI = *iStackRequire; + if ( pMatchAPI->mType == SYN_PROVIDE && MatchAPI( pMatchAPI, pAPI ) ) + break; + iStackRequire++; + } + if (iStackRequire != mStack.end()) + { + // we have found the corresponding SYN_PROVIDE + pMatchAPI->mRefCount--; + } + else + { + // this is not supposed to happen at all + Syn_Printf("ERROR: couldn't find the SYN_PROVIDE for an initialized SYN_REQUIRE API '%s' '%s' '%s'\n", pAPI->major_name, pAPI->minor_name, pClientSlot->mpClient->GetInfo()); + } + } + } + else if (pAPI->mType == SYN_PROVIDE) + { + // this should never happen on non active clients, it may happen during a core shutdown though + // if the mRefCount is != 0, that means there is at least a function table out there that will segfault things + Syn_Printf("WARNING: found a SYN_PROVIDE API '%s' '%s' with refcount %d in CSynapseServer::ShutdownClient for '%s'\n", pAPI->major_name, pAPI->minor_name, pAPI->mRefCount, pClientSlot->mpClient->GetInfo()); + } + // mostly safe to remove it now + mStack.erase(iStack); + } + } + // we can actually release the module now + // NOTE: do we want to have a 'final shutdown' call to the client? (not as long as we don't have a use for it) + if (pClientSlot->mType == SYN_SO) + { + pClientSlot->ReleaseSO(); + } + return mClients.erase(iSlot); +} + +void CSynapseServer::PushRequired(CSynapseClient *pClient) +{ + /* walk through the standard APIs and push them in */ + int i,max = pClient->GetAPICount(); + for(i=0; iGetAPIDescriptor(i); + if (pAPI->mType == SYN_REQUIRE && !pAPI->mbTableInitDone) + { + TryPushStack(pAPI); + } + } + + /* if this client has 'List' API Manager types, walk through them for addition too */ + max = pClient->GetManagerListCount(); + for(i=0; iGetManagerList(i); + assert(pManager->GetType() == API_LIST); + pManager->InitializeAPIList(); + int j; + for(j=0; jGetAPICount(); j++) + { + TryPushStack(pManager->GetAPI(j)); + } + } + + /* if there are loose match managers, prompt them against the current list of SYN_PROVIDE interfaces + * and let them decide which ones they might want + */ + + max = pClient->GetManagerMatchCount(); + + for(i=0; iGetManagerMatch(i); + // start matching all known SYN_PROVIDE APIs against this manager + list::iterator iClientSlot; + for(iClientSlot=mClients.begin(); iClientSlot!=mClients.end(); iClientSlot++) + { + CSynapseClient *pScanClient = (*iClientSlot). + mpClient; + int j,jmax = pScanClient->GetAPICount(); + for(j=0; jGetAPIDescriptor(j); + if (pAPI->mType == SYN_PROVIDE) + { + if (pManager->MatchAPI(pAPI->major_name, pAPI->minor_name)) + { + /*! we are going to want to load this one + * NOTE TTimo: what if this can not be resolved in the end? + * if this happens, then the whole startup will fail instead + * or we can use SYN_REQUIRE_ANY and drop it without consequences + */ + APIDescriptor_t *pPushAPI = pManager->BuildRequireAPI(pAPI); + TryPushStack(pPushAPI); + } + } + } + } + } +} + +bool CSynapseServer::MatchAPI(APIDescriptor_t *p1, APIDescriptor_t *p2) +{ + return MatchAPI( p1->major_name, p1->minor_name, p2->major_name, p2->minor_name ); +} + +bool CSynapseServer::MatchAPI(const char* major1, const char* minor1, const char* major2, const char* minor2) +{ + if ( strcmp( major1, major2 ) ) { + return false; + } + // either no minor at all for this API, or matching + if ( ( minor1 && minor2 ) && !strcmp( minor1, minor2 ) ) { + return true; + } + // or one of the minors says "*" (knowing that the majors match already) + if ( ( minor1 && !strcmp( minor1, "*" ) ) || ( minor2 && !strcmp( minor2, "*" ) ) ) { + return true; + } + return false; +} + +bool CSynapseServer::ResolveAPI(APIDescriptor_t* pAPI) +{ + //Syn_Printf("In ResolveAPI %s %p '%s' '%s'\n", APITypeName[pAPI->mType], pAPI, pAPI->major_name, pAPI->minor_name); + // loop through active clients, search for a client providing what we are looking for + list::iterator iClient; + for(iClient=mClients.begin(); iClient!=mClients.end(); iClient++) + { + // walk through interfaces on this client for a match + CSynapseClient *pScanClient = (*iClient).mpClient; + int i,max = pScanClient->GetAPICount(); + for(i=0; iGetAPIDescriptor(i); + if (pScanClientAPI->mType == SYN_PROVIDE) + { + if (MatchAPI(pAPI, pScanClientAPI)) + { + // can this client provide APIs yet + // it is possible that all of it's APIs have been filled and it's not been activated yet + pScanClient->CheckSetActive(); + if (pScanClient->IsActive()) + { + // make sure this interface has correct size (this is our version check) + if (pAPI->mSize != pScanClientAPI->mSize) + { + Syn_Printf("ERROR: version mismatch for API '%s' '%s' found in '%s' (size %d != %d)\n", pAPI->major_name, pAPI->minor_name, pScanClient->GetInfo(), pAPI->mSize, pScanClientAPI->mSize); + Syn_Printf(" the module and the server are incompatible\n"); + // keep going to other APIs + continue; + } + // this is an active client, we can request + #ifdef SYNAPSE_VERBOSE + Syn_Printf("RequestAPI '%s' '%s' from '%s' for API %p\n", pAPI->major_name, pAPI->minor_name, pScanClient->GetInfo(), pAPI); + #endif + if (!pScanClient->RequestAPI(pAPI)) + { + // this should never happen, means we think this module provides the API, but it answers that it doesn't + Syn_Printf("ERROR: RequestAPI failed\n"); + return false; + } + pScanClientAPI->mRefCount++; + pAPI->mbTableInitDone = true; + return true; // job done + } + else + { + // this client is not active yet, some of it's required interfaces are not filled in + PushRequired(pScanClient); + // we will exit the scan through the APIDescriptor of this client and look at other clients + break; + } + } + } + } + } + return false; +} + +bool CSynapseServer::DoResolve(CSynapseClient *pClient) +{ + list::iterator iSlot; + for(iSlot=mClients.begin(); iSlot != mClients.end(); iSlot++) + { + if ((*iSlot).mpClient == pClient) + break; + } + if (iSlot == mClients.end()) + { + Syn_Printf("CSynapserServer::Resolve adding new client slot '%s'\n", pClient->GetInfo()); + CSynapseClientSlot slot; + slot.mpClient = pClient; + slot.mFileName = "local client"; + // make it active so we can request the interfaces already + pClient->ForceSetActive(); + mClients.push_front(slot); + } + else + { + // make it active so we can request the interfaces already + (*iSlot).mpClient->ForceSetActive(); + } + + // push the interfaces that need to be resolved for this client + // NOTE: this doesn't take care of the SYN_REQUIRE_ANY interfaces + PushRequired(pClient); + // start resolving now + // working till the stack is emptied or till we reach a dead end situation + // we do a depth first traversal, we will grow the interface stack to be resolved till we start finding solutions + list::iterator iCurrent; + mbStackChanged = true; // init to true so we try the first elem + while (!mStack.empty()) + { + //DumpStack(); + if (!mbStackChanged) + { + // the stack didn't change last loop + iCurrent++; + if (iCurrent==mStack.end()) + { + Syn_Printf("ERROR: CSynapseServer::Resolve, failed to resolve\n"); + DumpStack(); + return false; + } + if (ResolveAPI(*iCurrent)) + { + iCurrent = mStack.erase(iCurrent); + mbStackChanged = true; + } + } + else + { + // the stack changed at last loop + mbStackChanged = false; + iCurrent = mStack.begin(); + if (ResolveAPI(*iCurrent)) + { + iCurrent = mStack.erase(iCurrent); + mbStackChanged = true; + } + } + } + return true; +} + +bool CSynapseServer::Resolve(CSynapseClient *pClient) +{ + bool ret = DoResolve(pClient); + list::iterator iClient; + iClient = mClients.begin(); + while(iClient != mClients.end()) + { + CSynapseClient *pClient = (*iClient).mpClient; + if (!pClient->IsActive()) + { + Syn_Printf("Unloading an unused module: '%s'\n", pClient->GetInfo()); + iClient = ShutdownClient(iClient); + } + else + iClient++; + } + return ret; +} + +void CSynapseServer::Shutdown() +{ + Syn_Printf("Synapse server core is shutting down\n"); + // do a first pass to shutdown the clients nicely (i.e. decref, release memory and drop everything) + // we seperate the client shutdown calls from the dlclose cause that part is a clean decref / free situation whereas dlclose will break links without advice + list::iterator iClient; + iClient = mClients.begin(); + for(iClient = mClients.begin(); iClient != mClients.end(); iClient++) + { + (*iClient).mpClient->Shutdown(); + } + // now release them from the server's point of view + iClient = mClients.begin(); + while(iClient != mClients.end()) + { + iClient = ShutdownClient(iClient); + } +} + +void CSynapseServer::DumpStack() +{ + list::iterator iCurrent; + for(iCurrent=mStack.begin(); iCurrent != mStack.end(); iCurrent++) + { + APIDescriptor_t*pAPI = *iCurrent; + Syn_Printf("interface %s %p '%s' '%s'\n", APITypeName[pAPI->mType], pAPI, pAPI->major_name, pAPI->minor_name); + } +} + +void CSynapseServer::DumpActiveClients() +{ + list::iterator iClient; + for(iClient=mClients.begin(); iClient!=mClients.end(); iClient++) + { + CSynapseClient *pClient = (*iClient).mpClient; + Syn_Printf("%s", pClient->GetInfo()); + if (pClient->IsActive()) + Syn_Printf("\n"); + else + Syn_Printf(" (not active)\n"); + } +} + +bool CSynapseServer::SelectClientConfig(const char *client_name) +{ + if (!mpDoc) + return false; + xmlNodePtr pNode = xmlDocGetRootElement(mpDoc); + if (!pNode) + return false; + // look for the client + pNode=pNode->children; + while(pNode) + { + if (pNode->type == XML_ELEMENT_NODE) + { + xmlChar *prop = xmlGetProp(pNode, (const xmlChar *)"name"); + if (!strcmp((const char *)prop, client_name)) + { + xmlFree(prop); + break; + } + xmlFree(prop); + } + pNode = pNode->next; + } + if (!pNode) + return false; // config you asked for isn't there + // focus + mpFocusedNode = pNode->children; + mpCurrentClientConfig = pNode; + return true; +} + +bool CSynapseServer::GetNextConfig(char **api_name, char **minor) +{ + while(mpFocusedNode && mpFocusedNode->name) + { + if (mpFocusedNode->type == XML_ELEMENT_NODE && !strcmp((const char *)mpFocusedNode->name, "api")) + { + if (m_api_name) + xmlFree(m_api_name); + m_api_name = xmlGetProp(mpFocusedNode, (const xmlChar *)"name"); + *api_name = (char *)m_api_name; + if (m_content) + g_free(m_content); + m_content = g_strdup((const gchar *)mpFocusedNode->children->content); + g_strstrip(m_content); + *minor = m_content; + mpFocusedNode = mpFocusedNode->next; + return true; + } + mpFocusedNode = mpFocusedNode->next; + } + return false; +} + +bool CSynapseServer::GetConfigForAPI( const char *api, char **minor ) { + xmlNodePtr pNode = mpCurrentClientConfig->children; + while ( pNode && pNode->name ) { + if ( pNode->type == XML_ELEMENT_NODE && !strcmp( (const char *)pNode->name, "api" ) ) { + if ( m_api_name ) { + xmlFree( m_api_name ); + } + m_api_name = xmlGetProp( pNode, (const xmlChar *)"name" ); + if ( !strcmp( (const char *)m_api_name, api ) ) { + if ( m_content ) { + g_free( m_content ); + } + m_content = g_strdup( (const gchar *)pNode->children->content ); + g_strstrip( m_content ); + *minor = m_content; + return true; + } + } + pNode = pNode->next; + } + return false; +} + +const char *CSynapseServer::GetModuleFilename(CSynapseClient *pClient) +{ + list::iterator iSlot; + for(iSlot=mClients.begin(); iSlot != mClients.end(); iSlot++) + { + if ((*iSlot).mpClient == pClient) + { + if ((*iSlot).mType == SYN_BUILTIN) + { + return ""; // FIXME + } + else + { + return (*iSlot).mFileName; + } + } + } + return NULL; +} + +/* +======================================================================= +client +======================================================================= +*/ + +CSynapseClient::CSynapseClient() +{ +} + +void CSynapseClient::Shutdown() +{ + vector::iterator iAPI; + for(iAPI=mAPIDescriptors.begin(); iAPI!=mAPIDescriptors.end(); iAPI++) + { + APIDescriptor_t *pAPI = *iAPI; + if (pAPI->mRefCount != 0) + Syn_Printf("WARNING: ~CSynapseClient '%s' has non-zero ref count for interface '%s' '%s'\n", GetInfo(), pAPI->major_name, pAPI->minor_name); + else + delete pAPI; + *iAPI=NULL; + } + mAPIDescriptors.clear(); + vector::iterator iManager; + for(iManager=mManagersList.begin(); iManager!=mManagersList.end(); iManager++) + { + CSynapseAPIManager *pManager = *iManager; + pManager->DecRef(); + *iManager = NULL; + } + mManagersList.clear(); + for(iManager=mManagersMatch.begin(); iManager!=mManagersMatch.end(); iManager++) + { + CSynapseAPIManager *pManager = *iManager; + pManager->DecRef(); + *iManager = NULL; + } + mManagersMatch.clear(); +} + +CSynapseClient::~CSynapseClient() +{ + // this should not be doing anything when called from here if everything went right + // otherwise it's likely to crash .. at least that's the sign we missed something + Shutdown(); +} + +int CSynapseClient::GetAPICount() +{ + return mAPIDescriptors.size(); +} + +APIDescriptor_t* CSynapseClient::GetAPIDescriptor(int i) +{ + return mAPIDescriptors[i]; +} + +int CSynapseClient::GetManagerMatchCount() +{ + return mManagersMatch.size(); +} + +CSynapseAPIManager* CSynapseClient::GetManagerMatch(int i) +{ + return mManagersMatch[i]; +} + +int CSynapseClient::GetManagerListCount() +{ + return mManagersList.size(); +} + +CSynapseAPIManager* CSynapseClient::GetManagerList(int i) +{ + return mManagersList[i]; +} + +bool CSynapseClient::AddAPI(const char *major, const char *minor, int size, EAPIType type, void *pTable) +{ + // do some safe checks before actual addition + if (type == SYN_REQUIRE && !pTable) + { + Syn_Printf("ERROR: interface '%s' '%s' from '%s' is SYN_REQUIRE and doesn't provide a function table pointer\n", major, minor, GetInfo()); + return false; + } + if (pTable) + { + int *pi = (int *)pTable; + if (pi == 0) + { + Syn_Printf("ERROR: forgot to init function table size for interface '%s' '%s' from '%s'?\n", major, minor, GetInfo()); + return false; + } + } + APIDescriptor_t *pAPI = new APIDescriptor_t; + memset(pAPI, 0, sizeof(APIDescriptor_t)); + strncpy(pAPI->major_name, major, MAX_APINAME); + if (minor) + strncpy(pAPI->minor_name, minor, MAX_APINAME); + pAPI->mType = type; + pAPI->mpTable = pTable; + // store the interface size + if (type == SYN_PROVIDE) + { + if (size == 0) + { + Syn_Printf("ERROR: size of the interface required for a SYN_PROVIDE ('%s' '%s' from '%s')\n", major, minor, GetInfo()); + delete pAPI; + return false; + } + pAPI->mSize = size; + } + else if (type == SYN_REQUIRE) + { + if (size != 0) + { + // if a non-zero value is given in function call, use this instead of the val in table + *((int *)pAPI->mpTable) = size; + pAPI->mSize = size; + } + else + { + pAPI->mSize = *((int *)pAPI->mpTable); + if (pAPI->mSize == 0) + { + Syn_Printf("ERROR: didn't get an interface size ('%s' '%s' from '%s')\n", major, minor, GetInfo()); + delete pAPI; + return false; + } + } + } + else + { + Syn_Printf("ERROR: AddAPI type '%d' not supported\n", type); + return false; + } + mAPIDescriptors.push_back(pAPI); + #ifdef SYNAPSE_VERBOSE + Syn_Printf("AddAPI: %s %p '%s' '%s' from '%s', size %d\n", APITypeName[pAPI->mType], pAPI, major, minor, GetInfo(), pAPI->mSize); + #endif + return true; +} + +#include "version.h" + +const char* CSynapseClient::GetInfo() +{ + return "CSynapseClient built " __DATE__ " " RADIANT_VERSION; +} + +bool CSynapseClient::CheckSetActive() +{ + if (mbActive) + return true; + int i,max=GetAPICount(); + for(i=0; imType == SYN_REQUIRE && !pAPI->mbTableInitDone) + return false; + } + // if we have managers with fixed list, those need to be completely filled in too + vector::iterator iManager; + for(iManager=mManagersList.begin(); iManager!=mManagersList.end(); iManager++) + { + if (!(*iManager)->CheckSetActive()) + return false; // one of the managers doesn't have all it needs yet + } + // call OnActivate to let the client perform last minute checks + // NOTE: this should be fatal instead of letting the engine try other combinations + if (!OnActivate()) { + return false; + } + // yes, all required interfaces have been initialized + Syn_Printf("'%s' activated\n", GetInfo()); + mbActive = true; + return true; +} + +bool CSynapseClient::ConfigXML( CSynapseServer *pServer, const char *client_name, const XMLConfigEntry_t entries[] ) { + + if ( !client_name ) { + client_name = GetName(); + } + + Syn_Printf("Dynamic APIs for client '%s'\n", GetInfo()); + if ( !pServer->SelectClientConfig( client_name ) ) + { + Syn_Printf( "Failed to select synapse client config '%s'\n", client_name ); + return false; + } + + int i = 0; + while ( entries[i].type != SYN_UNKNOWN ) { // don't test pTable, for a SYN_PROVIDE it will be empty + char *minor; + if ( !pServer->GetConfigForAPI( entries[i].api, &minor ) ) { + Syn_Printf( "GetConfigForAPI '%s' failed - invalid XML config file?\n", entries[i].api ); + return false; + } + AddAPI( entries[i].api, minor, entries[i].size, entries[i].type, entries[i].pTable ); + i++; + } + Syn_Printf( "%d dynamic interfaces parsed for '%s'\n", i, client_name ); + return true; +} + +void CSynapseClient::AddManager(CSynapseAPIManager *pManager) +{ + pManager->IncRef(); + if (pManager->GetType() == API_LIST) + mManagersList.push_back(pManager); + else + mManagersMatch.push_back(pManager); +} + +CSynapseAPIManager::~CSynapseAPIManager() +{ + vector::iterator iAPI; + for(iAPI=mAPIs.begin(); iAPI!=mAPIs.end(); iAPI++) + { + APIDescriptor_t *pAPI = *iAPI; + if (pAPI->mRefCount != 0) + { + Syn_Printf("WARNING: ~CSynapseAPIManager has non-zero ref count for interface '%s' '%s'\n", pAPI->major_name, pAPI->minor_name); + } + delete pAPI; + *iAPI = NULL; + } +} + +APIDescriptor_t* CSynapseAPIManager::PrepareRequireAPI(APIDescriptor_t *pAPI) +{ +#ifdef _DEBUG + if (pAPI->mType != SYN_PROVIDE) + { + Syn_Printf("ERROR: unexpected pAPI->mType != SYN_PROVIDE in CSynapseAPIManager::PrepareRequireAPI\n"); + return NULL; + } +#endif + APIDescriptor_t *pRequireAPI = new APIDescriptor_t; + memcpy(pRequireAPI, pAPI, sizeof(APIDescriptor_t)); + pRequireAPI->mType = SYN_REQUIRE_ANY; + pRequireAPI->mpTable = NULL; + pRequireAPI->mbTableInitDone = false; + pRequireAPI->mSize = 0; // this will have to be set correctly by the child for version checking + pRequireAPI->mRefCount = 0; + return pRequireAPI; +} + +void CSynapseAPIManager::SetMatchAPI(const char *major, const char *minor) +{ + if (strlen(minor)>MAX_PATTERN_STRING) + { + Syn_Printf("ERROR: MAX_TOKEN_STRING exceeded in CSynapseAPIManager::SetMatchAPI: '%s'\n", minor); + return; + } + strcpy(major_pattern, major); + strcpy(minor_pattern, minor); + if (strcmp(minor, "*")) + { + mType = API_LIST; + } +} + +bool CSynapseAPIManager::MatchAPI(const char *major, const char *minor) +{ + assert(mType == API_MATCH); + + /*! + if this interface has been allocated already, avoid requesting it again.. + */ + vector::iterator iAPI; + for(iAPI=mAPIs.begin(); iAPI!=mAPIs.end(); iAPI++) + { + if (CSynapseServer::MatchAPI((*iAPI)->major_name, (*iAPI)->minor_name, major, minor)) + return false; + } + + if (!strcmp(major, major_pattern)) + return true; + return false; +} + +bool CSynapseAPIManager::CheckSetActive() +{ + if (mType == API_MATCH) + return false; + // mType == API_LIST + int i,max = GetAPICount(); + for(i=0; imbTableInitDone) + return false; + } + return true; +} + +void CSynapseAPIManager::InitializeAPIList() +{ + char minor_tok[MAX_PATTERN_STRING]; + char *token; + + if (mAPIs.size()) + { + Syn_Printf("WARNING: CSynapseAPIManager::InitializeAPIList on an already initialized APIManager\n"); + return; + } + + strncpy(minor_tok, minor_pattern, MAX_PATTERN_STRING); + token = strtok(minor_tok, " "); + while (token) + { + /* ask the child to build from scratch */ + APIDescriptor_t *pAPI = new APIDescriptor_t; + memset(pAPI, 0, sizeof(APIDescriptor_t)); + strncpy(pAPI->major_name, major_pattern, MAX_APINAME); + strncpy(pAPI->minor_name, token, MAX_APINAME); + pAPI->mType = SYN_REQUIRE_ANY; + FillAPITable(pAPI); + mAPIs.push_back(pAPI); + token = strtok(NULL, " "); + } +} + +int CSynapseAPIManager::GetAPICount() +{ + return mAPIs.size(); +} + +APIDescriptor_t* CSynapseAPIManager::GetAPI(int i) +{ + return mAPIs[i]; +} + +// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=879 +void fini_stub() { + printf( "fini_stub\n" ); +} diff --git a/plugins/eclassfgd/plugin.cpp b/plugins/eclassfgd/plugin.cpp index 9b662f87..fa8920af 100644 --- a/plugins/eclassfgd/plugin.cpp +++ b/plugins/eclassfgd/plugin.cpp @@ -1,1141 +1,1141 @@ -/* -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 -*/ - -//#define FGD_VERBOSE // define this for extra info in the log. - -#include "plugin.h" - -/*! \file plugin.cpp - \brief .fgd entity description format - - FGD loading code by Dominic Clifton - Hydra (Hydra@Hydras-World.com) - - Overview - ======== - - This module loads .fgd files, fgd files are split into classes: - - base classes - point classes (aka fixed size entities) - solid classes (aka brush entity) - - This program first scans each file, building up a list structures - in memory that contain the information for all the classes found - in the file. - - Then the program looks at each of the non-base classes in the list - and build the eclass_t structure from each one. - - Classes can request information in other classes. - - Solid/Base and Point/Base classes can have the same names as other - classes but there can be only one of each solid/point/base class with - the same name, - - e.g.: - - this is NOT allowed: - - @solidclass = "a" - @solidclass = "a" - - this is NOT allowed: - - @pointclass = "a" - @solidclass = "a" - - this IS allowed: - - @solidclass = "a" - @baseclass = "a" - - Version History - =============== - - v0.1 - 13/March/2002 - - Initial version. - - v0.2 - 16/March/2002 - - sets e->skinpath when it finds an iconsprite() token. - - v0.3 - 21/March/2002 - - Core now supports > 8 spawnflags, changes reflected here too. - - FIXED: mins/maxs were backwards when only w,h,d were in the FGD - (as opposed to the actual mins/maxs being in the .def file) - - Made sure all PointClass entities were fixed size entities - and gave them a default bounding box size if a size() setting - was not in the FGD file. - - Removed the string check for classes requesting another class - with the same name, adjusted Find_Class() so that it can search - for baseclasses only, this fixes the problem with PointClass "light" - requesting the BaseClass "light". - - v0.4 - 25/March/2002 - - bleh, It turns out that non-baseclasses can request non-baseclasses - so now I've changed Find_Class() so that it can ignore a specific class - (i.e. the one that's asking for others, so that classes can't request - themselves but they can request other classes of any kind with the - same name). - - made all spawnflag comments appear in one place, rather than being scattered - all over the comments if a requested class also had some spawnflags - - v0.5 - 6/April/2002 - - not using skinpath for sprites anymore, apprently we can code a model - module to display sprites and model files. - - model() tags are now supported. - - ToDo - ==== - - * add support for setting the eclass_t's modelpath. - (not useful for CS, but very useful for HL). - - * need to implement usage for e->skinpath in the core. - - * cleanup some areas now that GetTokenExtra() is available - (some parts were written prior to it's creation). - - * Import the comments between each BaseClass's main [ ] set. - (unfortunatly they're // cstyle comments, which GetToken skips over) - But still ignore comments OUTSIDE the main [ ] set. - -*/ - -_QERScripLibTable g_ScripLibTable; -_EClassManagerTable g_EClassManagerTable; -_QERFuncTable_1 g_FuncTable; -_QERFileSystemTable g_FileSystemTable; - -// forward declare -void Eclass_ScanFile (char *filename); - -const char* EClass_GetExtension() -{ - return "fgd"; -} - -CSynapseServer* g_pSynapseServer = NULL; -CSynapseClientFGD 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(ECLASS_MAJOR, "fgd", sizeof(_EClassTable)); - g_SynapseClient.AddAPI(SCRIPLIB_MAJOR, NULL, sizeof(g_ScripLibTable), SYN_REQUIRE, &g_ScripLibTable); - g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable); - g_SynapseClient.AddAPI(ECLASSMANAGER_MAJOR, NULL, sizeof(g_EClassManagerTable), SYN_REQUIRE, &g_EClassManagerTable); - - // Needs a 'default' option for this minor because we certainly don't load anything from wad files :) - g_SynapseClient.AddAPI(VFS_MAJOR, "wad", sizeof(g_FileSystemTable), SYN_REQUIRE, &g_FileSystemTable); - - return &g_SynapseClient; -} - -bool CSynapseClientFGD::RequestAPI(APIDescriptor_t *pAPI) -{ - if (!strcmp(pAPI->major_name, ECLASS_MAJOR)) - { - _EClassTable* pTable= static_cast<_EClassTable*>(pAPI->mpTable); - - pTable->m_pfnGetExtension = &EClass_GetExtension; - pTable->m_pfnScanFile = &Eclass_ScanFile; - - return true; - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -#include "version.h" - -const char* CSynapseClientFGD::GetInfo() -{ - return ".fgd eclass module built " __DATE__ " " RADIANT_VERSION; -} - -// ------------------------------------------------------------------------------------------------ - -#define CLASS_NOCLASS 0 -#define CLASS_BASECLASS 1 -#define CLASS_POINTCLASS 2 -#define CLASS_SOLIDCLASS 3 - -char *classnames[] = {"NOT DEFINED","BaseClass","PointClass","SolidClass"}; - -#define OPTION_NOOPTION 0 -#define OPTION_STRING 1 -#define OPTION_CHOICES 2 -#define OPTION_INTEGER 3 -#define OPTION_FLAGS 4 - -char *optionnames[] = {"NOT DEFINED","String","Choices","Integer","Flags"}; - -typedef struct choice_s { - int value; - char *name; -} choice_t; - -typedef struct option_s { - int optiontype; - char *optioninfo; - char *epairname; - char *optiondefault; - GSList *choices; // list of choices_t -} option_t; - -typedef struct class_s { - int classtype; // see CLASS_* above. - char *classname; - GSList *l_baselist; // when building the eclass_t, other class_s's with these names are required. - char *description; - - GSList *l_optionlist; // when building the eclass_t, other class_s's with these names are required. - - bool gotsize; // if set then boundingbox is valid. - vec3_t boundingbox[2]; // mins, maxs - - bool gotcolor; // if set then color is valid. - vec3_t color; // R,G,B, loaded as 0-255 - - char *model; // relative path + filename to a model (.spr/.mdl) file, or NULL -} class_t; - -/* -=========================================================== -utility functions - -=========================================================== -*/ -char *strlower (char *start) -{ - char *in; - in = start; - while (*in) - { - *in = tolower(*in); - in++; - } - return start; -} - -char *addstr(char *dest,char *source) -{ - if (dest) - { - char *ptr; - int len = strlen(dest); - ptr = (char *) malloc (len + strlen(source) + 1); - strcpy(ptr,dest); - strcpy(ptr+len,source); - free(dest); - dest = ptr; - } - else - { - dest = strdup(source); - } - return(dest); -} - -int getindex(unsigned int a) -{ - unsigned int count = 0; - unsigned int b = 0; - for (;b != a;count++) - { - b = (1< a) - return -1; - } - return (count); -} - -void ClearGSList (GSList* lst) -{ - GSList *p = lst; - while (p) - { - free (p->data); - p = g_slist_remove (p, p->data); - } -} - -/*! -free a choice_t structure and it's contents -*/ -void Free_Choice(choice_t *p) -{ - if (p->name) free(p->name); - free (p); - -} - -/* -=========================================================== -Main functions - -=========================================================== -*/ - -/*! -free an option_t structure and it's contents -*/ -void Free_Option(option_t *p) -{ - if (p->epairname) free(p->epairname); - if (p->optiondefault) free(p->optiondefault); - if (p->optioninfo) free(p->optioninfo); - GSList *l = p->choices; - while (l) - { - Free_Choice ((choice_t *)l->data); - l = g_slist_remove (l, l->data); - } - free (p); -} - -/*! -free a class_t structure and it's contents -*/ -void Free_Class(class_t *p) -{ - GSList *l = p->l_optionlist; - while (l) - { - Free_Option ((option_t *)l->data); - l = g_slist_remove (l, l->data); - } - - if (p->classname) free(p->classname); - free (p); -} - -/*! -find a class in the list -*/ -class_t *Find_Class(GSList *l,char *classname, class_t *ignore) -{ - for (GSList *clst = l; clst != NULL; clst = clst->next) - { - class_t *c = (class_t *)clst->data; - - if (c == ignore) - continue; - - // NOTE: to speed up we could make all the classnames lower-case when they're initialised. - if (!stricmp(c->classname,classname)) - { - return c; - } - - } - return NULL; -} - -/*! -Import as much as possible from a class_t into an eclass_t -Note: this is somewhat recursive, as a class can require a class that requires a class and so on.. -*/ -void EClass_ImportFromClass(eclass_t *e, GSList *l_classes, class_t *bc) -{ - char color[128]; - - // We allocate 16k here, but only the memory actually used is kept allocated. - // this is just used for building the final comments string. - // Note: if the FGD file contains comments that are >16k (per entity) then - // radiant will crash upon loading such a file as the eclass_t will become - // corrupted. - // FIXME: we could add some length checking when building "newcomments", but - // that'd slow it down a bit. - char newcomments[16384] = ""; - - //Note: we override the values already in e. - //and we do it in such a way that the items that appear last in the l_baselist - //represent the final values. - - if (bc->description) - { - sprintf(newcomments,"%s\n",bc->description); - e->comments = addstr(e->comments,newcomments); - newcomments[0] = 0; // so we don't add them twice. - } - - - // import from other classes if required. - - if (bc->l_baselist) - { - // this class requires other base classes. - - for (GSList *bclst = bc->l_baselist; bclst != NULL; bclst = bclst->next) - { - char *requestedclass = (char *)bclst->data; - -// class_t *rbc = Find_Class(l_classes, requestedclass, true); - class_t *rbc = Find_Class(l_classes, requestedclass, bc); - - // make sure we don't request ourself! - if (rbc == bc) - { - Sys_Printf ("WARNING: baseclass '%s' tried to request itself!\n", bclst->data); - } - else - { - if (!rbc) - { - Sys_Printf ("WARNING: could not find the requested baseclass '%s' when building '%s'\n", requestedclass,bc->classname); - } - else - { - // call ourself! - EClass_ImportFromClass(e, l_classes, rbc); - } - } - } - } - // SIZE - if (bc->gotsize) - { - e->fixedsize = true; - memcpy(e->mins,bc->boundingbox[0],sizeof( vec3_t )); - memcpy(e->maxs,bc->boundingbox[1],sizeof( vec3_t )); - } -/* - // Hydra: apparently, this would be bad. - - if (bc->sprite) - { - // Hydra - NOTE: e->skinpath is not currently used by the editor but the code - // to set it is used by both this eclass_t loader and the .DEF eclass_t loader. - // TODO: implement using e->skinpath. - if (e->skinpath) - free (e->skinpath); - - e->skinpath = strdup(bc->sprite); - } -*/ - - // MODEL - if (bc->model) - { - if (e->modelpath) - free (e->modelpath); - - e->modelpath = strdup(bc->model); - } - - // COLOR - if (bc->gotcolor) - { - memcpy(e->color,bc->color,sizeof( vec3_t )); - sprintf (color, "(%f %f %f)", e->color[0], e->color[1], e->color[2]); - e->texdef.SetName(color); - } - - // SPAWNFLAGS and COMMENTS - if (bc->l_optionlist) - { - for (GSList *optlst = bc->l_optionlist; optlst != NULL; optlst = optlst->next) - { - option_t *opt = (option_t*) optlst->data; - - if (opt->optiontype != OPTION_FLAGS) - { - // add some info to the comments. - if (opt->optioninfo) - { - sprintf(newcomments+strlen(newcomments),"%s '%s' %s%s\n", - opt->epairname, - opt->optioninfo ? opt->optioninfo : "", - opt->optiondefault ? ", Default: " : "", - opt->optiondefault ? opt->optiondefault : ""); - } - else - { - sprintf(newcomments+strlen(newcomments),"%s %s%s\n", - opt->epairname, - opt->optiondefault ? ", Default: " : "", - opt->optiondefault ? opt->optiondefault : ""); - } - } - - GSList *choicelst; - switch(opt->optiontype) - { - case OPTION_FLAGS : - // grab the flags. - for (choicelst = opt->choices; choicelst != NULL; choicelst = choicelst->next) - { - choice_t *choice = (choice_t*) choicelst->data; - - int index = getindex(choice->value); - index--; - if (index < MAX_FLAGS) - { - strcpy(e->flagnames[index],choice->name); - } - else - { - Sys_Printf ("WARNING: baseclass '%s' has a spawnflag out of range, ignored!\n", bc->classname); - } - } - break; - case OPTION_CHOICES : - strcat(newcomments," Choices:\n"); - for (choicelst = opt->choices; choicelst != NULL; choicelst = choicelst->next) - { - choice_t *choice = (choice_t*) choicelst->data; - sprintf(newcomments+strlen(newcomments)," %5d - %s\n",choice->value,choice->name); - } - break; - } - } - } - - // name - if (e->name) free(e->name); - e->name = strdup(bc->classname); - - // fixed size initialisation - if (bc->classtype == CLASS_POINTCLASS) - { - e->fixedsize = true; - // some point classes dont seem to have size()'s in the fgd, so set up a default here.. - if ((e->mins[0] == 0) && (e->mins[1] == 0) && (e->mins[2] == 0) && - (e->maxs[0] == 0) && (e->maxs[1] == 0) && (e->maxs[2] == 0)) - { - e->mins[0] = -8; - e->mins[1] = -8; - e->mins[2] = -8; - e->maxs[0] = 8; - e->maxs[1] = 8; - e->maxs[2] = 8; - } - - if (e->texdef.GetName() == NULL) - { - // no color specified for this entity in the fgd file - // set one now - // Note: if this eclass_t is not fully built, then this may be - // overridden with the correct color. - - e->color[0] = 1; - e->color[1] = 0.5; // how about a nice bright pink, mmm, nice! :) - e->color[2] = 1; - - sprintf (color, "(%f %f %f)", e->color[0], e->color[1], e->color[2]); - e->texdef.SetName(color); - } - } - - // COMMENTS - if (newcomments[0]) - { - e->comments = addstr(e->comments,newcomments); - } -} - -/*! -create the eclass_t structures and add to the global list. -*/ -void Create_EClasses(GSList *l_classes) -{ - int count = 0; - // loop through the loaded structures finding all the non BaseClasses - for (GSList *clst = l_classes; clst != NULL; clst = clst->next) - { - class_t *c = (class_t *)clst->data; - - if (c->classtype == CLASS_BASECLASS) // not looking for these. - continue; - - eclass_t *e = (eclass_t *) malloc( sizeof( eclass_s )); - memset(e,0,sizeof( eclass_s )); - - EClass_ImportFromClass(e, l_classes, c ); - - // radiant will crash if this is null, and it still could be at this point. - if (!e->comments) - { - e->comments=strdup("No description available, check documentation\n"); - } - - // dump the spawnflags to the end of the comments. - int i; - bool havespawnflags; - - havespawnflags = false; - for (i = 0 ; i < MAX_FLAGS ; i++) - { - if (*e->flagnames[i]) havespawnflags = true; - } - - if (havespawnflags) - { - char spawnline[80]; - e->comments = addstr(e->comments,"Spawnflags\n"); - for (i = 0 ; i < MAX_FLAGS ; i++) - { - if (*e->flagnames[i]) - { - sprintf(spawnline," %d - %s\n", 1<flagnames[i]); - e->comments = addstr(e->comments,spawnline); - } - } - } - - Eclass_InsertAlphabetized (e); - count ++; - // Hydra: ttimo, I don't think this code is required... - // single ? - *Get_Eclass_E() = e; - Set_Eclass_Found(true); - if ( Get_Parsing_Single() ) - break; - } - - Sys_Printf ("FGD Loaded %d entities.\n", count); -} - -void Eclass_ScanFile (char *filename) -{ - int size; - char *data; - char temp[1024]; - GSList *l_classes = NULL; - char token_debug[1024]; //++Hydra FIXME: cleanup this. - bool done = false; - int len,classtype; - - char *token = Token(); - - QE_ConvertDOSToUnixName( temp, filename ); - - size = vfsLoadFullPathFile (filename, (void**)&data); - if (size <= 0) - { - Sys_FPrintf (SYS_ERR, "Eclass_ScanFile: %s not found\n", filename); - return; - } - Sys_Printf ("ScanFile: %s\n", temp); - - // start parsing the file - StartTokenParsing(data); - - // build a list of base classes first - - while (!done) - { - // find an @ sign. - do - { - if (!GetToken(true)) - { - done = true; - break; - } - } while (token[0] != '@'); - - strcpy(temp,token+1); // skip the @ - - classtype = CLASS_NOCLASS; - if (!stricmp(temp,"BaseClass")) classtype = CLASS_BASECLASS; - if (!stricmp(temp,"PointClass")) classtype = CLASS_POINTCLASS; - if (!stricmp(temp,"SolidClass")) classtype = CLASS_SOLIDCLASS; - - if (classtype) - { - class_t *newclass = (class_t *) malloc( sizeof(class_s) ); - memset( newclass, 0, sizeof(class_s) ); - newclass->classtype = classtype; - - while (1) - { - GetTokenExtra(false,"(",false); // option or = - strcpy(token_debug,token); - - if (!strcmp(token,"=")) - { - UnGetToken(); - break; - } - else - { - strlower(token); - if (!strcmp(token,"base")) - { - GetTokenExtra(false,"(",true); // ( - - if (!strcmp(token,"(")) - { - while (GetTokenExtra(false,",)",false)) // option) or option, - { - newclass->l_baselist = g_slist_append (newclass->l_baselist, strdup(token)); - - GetTokenExtra(false,",)",true); // , or ) - if (!strcmp(token,")")) - break; - - } - } - } - else if (!strcmp(token,"size")) - { - // parse (w h d) or (x y z, x y z) - - GetTokenExtra(false,"(",true); // ( - if (!strcmp(token,"(")) - { - int sizedone = false; - float w,h,d; - GetToken(false); - w = atof(token); - GetToken(false); - h = atof(token); - GetToken(false); // number) or number , - strcpy(temp,token); - len = strlen(temp); - if (temp[len-1] == ')') sizedone = true; - temp[len-1] = 0; - d = atof(temp); - if (sizedone) - { - // only one set of cordinates supplied, change the W,H,D to mins/maxs - newclass->boundingbox[0][0] = 0 - (w / 2); - newclass->boundingbox[1][0] = w / 2; - newclass->boundingbox[0][1] = 0 - (h / 2); - newclass->boundingbox[1][1] = h / 2; - newclass->boundingbox[0][2] = 0 - (d / 2); - newclass->boundingbox[1][2] = d / 2; - newclass->gotsize = true; - } - else - { - newclass->boundingbox[0][0] = w; - newclass->boundingbox[0][1] = h; - newclass->boundingbox[0][2] = d; - GetToken(false); - newclass->boundingbox[1][0] = atof(token); - GetToken(false); - newclass->boundingbox[1][1] = atof(token); -/* - GetToken(false); // "number)" or "number )" - strcpy(temp,token); - len = strlen(temp); - if (temp[len-1] == ')') - temp[len-1] = 0; - else - GetToken(false); // ) - newclass->boundingbox[1][2] = atof(temp); -*/ - GetTokenExtra(false,")",false); // number - newclass->boundingbox[1][2] = atof(token); - newclass->gotsize = true; - GetTokenExtra(false,")",true); // ) - } - } - } - else if (!strcmp(token,"color")) - { - GetTokenExtra(false,"(",true); // ( - if (!strcmp(token,"(")) - { - // get the color values (0-255) and normalize them if required. - GetToken(false); - newclass->color[0] = atof(token); - if (newclass->color[0] > 1) - newclass->color[0]/=255; - GetToken(false); - newclass->color[1] = atof(token); - if (newclass->color[1] > 1) - newclass->color[1]/=255; - GetToken(false); - strcpy(temp,token); - len = strlen(temp); - if (temp[len-1] == ')') temp[len-1] = 0; - newclass->color[2] = atof(temp); - if (newclass->color[2] > 1) - newclass->color[2]/=255; - newclass->gotcolor = true; - } - } - else if (!strcmp(token,"iconsprite")) - { - GetTokenExtra(false,"(",true); // ( - if (!strcmp(token,"(")) - { - GetTokenExtra(false,")",false); // filename) - // the model plugins will handle sprites too. - // newclass->sprite = strdup(token); - newclass->model = strdup(token); - GetTokenExtra(false,")",true); // ) - } - } - else if (!strcmp(token,"model")) - { - GetTokenExtra(false,"(",true); // ( - if (!strcmp(token,"(")) - { - GetTokenExtra(false,")",false); // filename) - newclass->model = strdup(token); - GetTokenExtra(false,")",true); // ) - } - } - else - { - // Unsupported - GetToken(false); // skip it. - } - - } - } - - GetToken(false); // = - strcpy(token_debug,token); - if (!strcmp(token,"=")) - { - GetToken(false); - newclass->classname = strdup(token); - } - - // Get the description - if (newclass->classtype != CLASS_BASECLASS) - { - GetToken(false); - if (!strcmp(token,":")) - { - GetToken(false); - newclass->description = strdup(token); - } else UnGetToken(); // no description - } - - // now build the option list. - GetToken(true); // [ or [] - - if (strcmp(token,"[]")) // got some options ? - { - if (!strcmp(token,"[")) - { - // yup - bool optioncomplete = false; - option_t *newoption; - - while (1) - { - GetToken(true); - if (!strcmp(token,"]")) - break; // no more options - - // parse the data and build the option_t - - strcpy(temp,token); - len = strlen(temp); - char *ptr = strchr(temp,'('); - - if (!ptr) - break; - - newoption = (option_t *) malloc ( sizeof( option_s )); - memset( newoption, 0, sizeof( option_s )); - - *ptr++ = 0; - newoption->epairname = strdup(temp); - - len = strlen(ptr); - if (ptr[len-1] != ')') - break; - - ptr[len-1] = 0; - strlower(ptr); - if (!strcmp(ptr,"integer")) - { - newoption->optiontype = OPTION_INTEGER; - } - else if (!strcmp(ptr,"choices")) - { - newoption->optiontype = OPTION_CHOICES; - } - else if (!strcmp(ptr,"flags")) - { - newoption->optiontype = OPTION_FLAGS; - } - else // string - { - newoption->optiontype = OPTION_STRING; - } - - switch (newoption->optiontype) - { - case OPTION_STRING : - case OPTION_INTEGER : - if (!TokenAvailable()) - { - optioncomplete = true; - break; - } - GetToken(false); // : - strcpy(token_debug,token); - if ((token[0] == ':') && (strlen(token) > 1)) - { - newoption->optioninfo = strdup(token+1); - } - else - { - GetToken(false); - newoption->optioninfo = strdup(token); - } - if (TokenAvailable()) // default value ? - { - GetToken(false); - if (!strcmp(token,":")) - { - if (GetToken(false)) - { - newoption->optiondefault = strdup(token); - optioncomplete = true; - } - } - } - else - { - optioncomplete = true; - } - break; - - case OPTION_CHOICES : - GetTokenExtra(false,":",true); // : or :"something like this" (bah!) - strcpy(token_debug,token); - if ((token[0] == ':') && (strlen(token) > 1)) - { - if (token[1] == '\"') - { - strcpy(temp,token+2); - while (1) - { - if (!GetToken(false)) - break; - strcat(temp," "); - strcat(temp,token); - len = strlen(temp); - if (temp[len-1] == '\"') - { - temp[len-1] = 0; - break; - } - } - } - newoption->optioninfo = strdup(temp); - } - else - { - GetToken(false); - newoption->optioninfo = strdup(token); - } - GetToken(false); // : or = - strcpy(token_debug,token); - if (!strcmp(token,":")) - { - GetToken(false); - newoption->optiondefault = strdup(token); - } - else - { - UnGetToken(); - } - // And Follow on... - case OPTION_FLAGS : - GetToken(false); // : or = - strcpy(token_debug,token); - if (strcmp(token,"=")) // missing ? - break; - - GetToken(true); // [ - strcpy(token_debug,token); - if (strcmp(token,"[")) // missing ? - break; - - choice_t *newchoice; - while (1) - { - GetTokenExtra(true,":",true); // "]" or "number", or "number:" - strcpy(token_debug,token); - if (!strcmp(token,"]")) // no more ? - { - optioncomplete = true; - break; - } - strcpy(temp,token); - len = strlen(temp); - if (temp[len-1] == ':') - { - temp[len-1] = 0; - } - else - { - GetToken(false); // : - if (strcmp(token,":")) // missing ? - break; - } - if (!TokenAvailable()) - break; - GetToken(false); // the name - - newchoice = (choice_t *) malloc ( sizeof( choice_s )); - memset( newchoice, 0, sizeof( choice_s )); - - newchoice->value = atoi(temp); - newchoice->name = strdup(token); - - newoption->choices = g_slist_append(newoption->choices, newchoice); - - // ignore any remaining tokens on the line - while (TokenAvailable()) GetToken(false); - - // and it we found a "]" on the end of the line, put it back in the queue. - if (!strcmp(token,"]")) UnGetToken(); - } - break; - - } - - // add option to the newclass - - if (optioncomplete) - { - if (newoption) - { - // add it to the list. - newclass->l_optionlist = g_slist_append(newclass->l_optionlist, newoption); - } - } - else - { - Sys_Printf ("%WARNING: Parse error occured in '%s - %s'\n",classnames[newclass->classtype],newclass->classname); - Free_Option(newoption); - } - - } - } - else - { - UnGetToken(); // shouldn't get here. - } - } - - // add it to our list. - l_classes = g_slist_append (l_classes, newclass); - - } - } - - // finished with the file now. - g_free(data); - - Sys_Printf ("FGD scan complete, building entities...\n"); - - // Once we get here we should have a few (!) lists in memory that we - // can extract all the information required to build a the eclass_t structures. - - Create_EClasses(l_classes); - - // Free everything - - GSList *p = l_classes; - while (p) - { - class_t *tmpclass = (class_t *)p->data; - -#ifdef FGD_VERBOSE - // DEBUG: dump the info... - Sys_Printf ("%s: %s (", classnames[tmpclass->classtype],tmpclass->classname); - for (GSList *tmp = tmpclass->l_baselist; tmp != NULL; tmp = tmp->next) - { - if (tmp != tmpclass->l_baselist) - { - Sys_Printf (", "); - } - Sys_Printf ("%s", (char *)tmp->data); - } - if (tmpclass->gotsize) - { - sprintf(temp,"(%.0f %.0f %.0f) - (%.0f %.0f %.0f)",tmpclass->boundingbox[0][0], - tmpclass->boundingbox[0][1], - tmpclass->boundingbox[0][2], - tmpclass->boundingbox[1][0], - tmpclass->boundingbox[1][1], - tmpclass->boundingbox[1][2]); - } else strcpy(temp,"No Size"); - Sys_Printf (") '%s' Size: %s",tmpclass->description ? tmpclass->description : "No description",temp); - if (tmpclass->gotcolor) - { - sprintf(temp,"(%d %d %d)",tmpclass->color[0], - tmpclass->color[1], - tmpclass->color[2]); - } else strcpy(temp,"No Color"); - Sys_Printf (" Color: %s Options:\n",temp); - if (!tmpclass->l_optionlist) - { - Sys_Printf (" No Options\n"); - } - else - { - option_t *tmpoption; - int count; - GSList *olst; - for (olst = tmpclass->l_optionlist, count = 1; olst != NULL; olst = olst->next, count ++) - { - tmpoption = (option_t *)olst->data; - Sys_Printf (" %d, Type: %s, EPair: %s\n", count,optionnames[tmpoption->optiontype], tmpoption->epairname ); - - choice_t *tmpchoice; - GSList *clst; - int ccount; - for (clst = tmpoption->choices, ccount = 1; clst != NULL; clst = clst->next, ccount ++) - { - tmpchoice = (choice_t *)clst->data; - Sys_Printf (" %d, Value: %d, Name: %s\n", ccount, tmpchoice->value, tmpchoice->name); - } - } - } - -#endif - - // free the baselist. - ClearGSList(tmpclass->l_baselist); - Free_Class (tmpclass); - p = g_slist_remove (p, p->data); - } - -} +/* +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 +*/ + +//#define FGD_VERBOSE // define this for extra info in the log. + +#include "plugin.h" + +/*! \file plugin.cpp + \brief .fgd entity description format + + FGD loading code by Dominic Clifton - Hydra (Hydra@Hydras-World.com) + + Overview + ======== + + This module loads .fgd files, fgd files are split into classes: + + base classes + point classes (aka fixed size entities) + solid classes (aka brush entity) + + This program first scans each file, building up a list structures + in memory that contain the information for all the classes found + in the file. + + Then the program looks at each of the non-base classes in the list + and build the eclass_t structure from each one. + + Classes can request information in other classes. + + Solid/Base and Point/Base classes can have the same names as other + classes but there can be only one of each solid/point/base class with + the same name, + + e.g.: + + this is NOT allowed: + + @solidclass = "a" + @solidclass = "a" + + this is NOT allowed: + + @pointclass = "a" + @solidclass = "a" + + this IS allowed: + + @solidclass = "a" + @baseclass = "a" + + Version History + =============== + + v0.1 - 13/March/2002 + - Initial version. + + v0.2 - 16/March/2002 + - sets e->skinpath when it finds an iconsprite() token. + + v0.3 - 21/March/2002 + - Core now supports > 8 spawnflags, changes reflected here too. + - FIXED: mins/maxs were backwards when only w,h,d were in the FGD + (as opposed to the actual mins/maxs being in the .def file) + - Made sure all PointClass entities were fixed size entities + and gave them a default bounding box size if a size() setting + was not in the FGD file. + - Removed the string check for classes requesting another class + with the same name, adjusted Find_Class() so that it can search + for baseclasses only, this fixes the problem with PointClass "light" + requesting the BaseClass "light". + + v0.4 - 25/March/2002 + - bleh, It turns out that non-baseclasses can request non-baseclasses + so now I've changed Find_Class() so that it can ignore a specific class + (i.e. the one that's asking for others, so that classes can't request + themselves but they can request other classes of any kind with the + same name). + - made all spawnflag comments appear in one place, rather than being scattered + all over the comments if a requested class also had some spawnflags + + v0.5 - 6/April/2002 + - not using skinpath for sprites anymore, apprently we can code a model + module to display sprites and model files. + - model() tags are now supported. + + ToDo + ==== + + * add support for setting the eclass_t's modelpath. + (not useful for CS, but very useful for HL). + + * need to implement usage for e->skinpath in the core. + + * cleanup some areas now that GetTokenExtra() is available + (some parts were written prior to it's creation). + + * Import the comments between each BaseClass's main [ ] set. + (unfortunatly they're // cstyle comments, which GetToken skips over) + But still ignore comments OUTSIDE the main [ ] set. + +*/ + +_QERScripLibTable g_ScripLibTable; +_EClassManagerTable g_EClassManagerTable; +_QERFuncTable_1 g_FuncTable; +_QERFileSystemTable g_FileSystemTable; + +// forward declare +void Eclass_ScanFile (char *filename); + +const char* EClass_GetExtension() +{ + return "fgd"; +} + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientFGD 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(ECLASS_MAJOR, "fgd", sizeof(_EClassTable)); + g_SynapseClient.AddAPI(SCRIPLIB_MAJOR, NULL, sizeof(g_ScripLibTable), SYN_REQUIRE, &g_ScripLibTable); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(ECLASSMANAGER_MAJOR, NULL, sizeof(g_EClassManagerTable), SYN_REQUIRE, &g_EClassManagerTable); + + // Needs a 'default' option for this minor because we certainly don't load anything from wad files :) + g_SynapseClient.AddAPI(VFS_MAJOR, "wad", sizeof(g_FileSystemTable), SYN_REQUIRE, &g_FileSystemTable); + + return &g_SynapseClient; +} + +bool CSynapseClientFGD::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, ECLASS_MAJOR)) + { + _EClassTable* pTable= static_cast<_EClassTable*>(pAPI->mpTable); + + pTable->m_pfnGetExtension = &EClass_GetExtension; + pTable->m_pfnScanFile = &Eclass_ScanFile; + + return true; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientFGD::GetInfo() +{ + return ".fgd eclass module built " __DATE__ " " RADIANT_VERSION; +} + +// ------------------------------------------------------------------------------------------------ + +#define CLASS_NOCLASS 0 +#define CLASS_BASECLASS 1 +#define CLASS_POINTCLASS 2 +#define CLASS_SOLIDCLASS 3 + +char *classnames[] = {"NOT DEFINED","BaseClass","PointClass","SolidClass"}; + +#define OPTION_NOOPTION 0 +#define OPTION_STRING 1 +#define OPTION_CHOICES 2 +#define OPTION_INTEGER 3 +#define OPTION_FLAGS 4 + +char *optionnames[] = {"NOT DEFINED","String","Choices","Integer","Flags"}; + +typedef struct choice_s { + int value; + char *name; +} choice_t; + +typedef struct option_s { + int optiontype; + char *optioninfo; + char *epairname; + char *optiondefault; + GSList *choices; // list of choices_t +} option_t; + +typedef struct class_s { + int classtype; // see CLASS_* above. + char *classname; + GSList *l_baselist; // when building the eclass_t, other class_s's with these names are required. + char *description; + + GSList *l_optionlist; // when building the eclass_t, other class_s's with these names are required. + + bool gotsize; // if set then boundingbox is valid. + vec3_t boundingbox[2]; // mins, maxs + + bool gotcolor; // if set then color is valid. + vec3_t color; // R,G,B, loaded as 0-255 + + char *model; // relative path + filename to a model (.spr/.mdl) file, or NULL +} class_t; + +/* +=========================================================== +utility functions + +=========================================================== +*/ +char *strlower (char *start) +{ + char *in; + in = start; + while (*in) + { + *in = tolower(*in); + in++; + } + return start; +} + +char *addstr(char *dest,char *source) +{ + if (dest) + { + char *ptr; + int len = strlen(dest); + ptr = (char *) malloc (len + strlen(source) + 1); + strcpy(ptr,dest); + strcpy(ptr+len,source); + free(dest); + dest = ptr; + } + else + { + dest = strdup(source); + } + return(dest); +} + +int getindex(unsigned int a) +{ + unsigned int count = 0; + unsigned int b = 0; + for (;b != a;count++) + { + b = (1< a) + return -1; + } + return (count); +} + +void ClearGSList (GSList* lst) +{ + GSList *p = lst; + while (p) + { + free (p->data); + p = g_slist_remove (p, p->data); + } +} + +/*! +free a choice_t structure and it's contents +*/ +void Free_Choice(choice_t *p) +{ + if (p->name) free(p->name); + free (p); + +} + +/* +=========================================================== +Main functions + +=========================================================== +*/ + +/*! +free an option_t structure and it's contents +*/ +void Free_Option(option_t *p) +{ + if (p->epairname) free(p->epairname); + if (p->optiondefault) free(p->optiondefault); + if (p->optioninfo) free(p->optioninfo); + GSList *l = p->choices; + while (l) + { + Free_Choice ((choice_t *)l->data); + l = g_slist_remove (l, l->data); + } + free (p); +} + +/*! +free a class_t structure and it's contents +*/ +void Free_Class(class_t *p) +{ + GSList *l = p->l_optionlist; + while (l) + { + Free_Option ((option_t *)l->data); + l = g_slist_remove (l, l->data); + } + + if (p->classname) free(p->classname); + free (p); +} + +/*! +find a class in the list +*/ +class_t *Find_Class(GSList *l,char *classname, class_t *ignore) +{ + for (GSList *clst = l; clst != NULL; clst = clst->next) + { + class_t *c = (class_t *)clst->data; + + if (c == ignore) + continue; + + // NOTE: to speed up we could make all the classnames lower-case when they're initialised. + if (!stricmp(c->classname,classname)) + { + return c; + } + + } + return NULL; +} + +/*! +Import as much as possible from a class_t into an eclass_t +Note: this is somewhat recursive, as a class can require a class that requires a class and so on.. +*/ +void EClass_ImportFromClass(eclass_t *e, GSList *l_classes, class_t *bc) +{ + char color[128]; + + // We allocate 16k here, but only the memory actually used is kept allocated. + // this is just used for building the final comments string. + // Note: if the FGD file contains comments that are >16k (per entity) then + // radiant will crash upon loading such a file as the eclass_t will become + // corrupted. + // FIXME: we could add some length checking when building "newcomments", but + // that'd slow it down a bit. + char newcomments[16384] = ""; + + //Note: we override the values already in e. + //and we do it in such a way that the items that appear last in the l_baselist + //represent the final values. + + if (bc->description) + { + sprintf(newcomments,"%s\n",bc->description); + e->comments = addstr(e->comments,newcomments); + newcomments[0] = 0; // so we don't add them twice. + } + + + // import from other classes if required. + + if (bc->l_baselist) + { + // this class requires other base classes. + + for (GSList *bclst = bc->l_baselist; bclst != NULL; bclst = bclst->next) + { + char *requestedclass = (char *)bclst->data; + +// class_t *rbc = Find_Class(l_classes, requestedclass, true); + class_t *rbc = Find_Class(l_classes, requestedclass, bc); + + // make sure we don't request ourself! + if (rbc == bc) + { + Sys_Printf ("WARNING: baseclass '%s' tried to request itself!\n", bclst->data); + } + else + { + if (!rbc) + { + Sys_Printf ("WARNING: could not find the requested baseclass '%s' when building '%s'\n", requestedclass,bc->classname); + } + else + { + // call ourself! + EClass_ImportFromClass(e, l_classes, rbc); + } + } + } + } + // SIZE + if (bc->gotsize) + { + e->fixedsize = true; + memcpy(e->mins,bc->boundingbox[0],sizeof( vec3_t )); + memcpy(e->maxs,bc->boundingbox[1],sizeof( vec3_t )); + } +/* + // Hydra: apparently, this would be bad. + + if (bc->sprite) + { + // Hydra - NOTE: e->skinpath is not currently used by the editor but the code + // to set it is used by both this eclass_t loader and the .DEF eclass_t loader. + // TODO: implement using e->skinpath. + if (e->skinpath) + free (e->skinpath); + + e->skinpath = strdup(bc->sprite); + } +*/ + + // MODEL + if (bc->model) + { + if (e->modelpath) + free (e->modelpath); + + e->modelpath = strdup(bc->model); + } + + // COLOR + if (bc->gotcolor) + { + memcpy(e->color,bc->color,sizeof( vec3_t )); + sprintf (color, "(%f %f %f)", e->color[0], e->color[1], e->color[2]); + e->texdef.SetName(color); + } + + // SPAWNFLAGS and COMMENTS + if (bc->l_optionlist) + { + for (GSList *optlst = bc->l_optionlist; optlst != NULL; optlst = optlst->next) + { + option_t *opt = (option_t*) optlst->data; + + if (opt->optiontype != OPTION_FLAGS) + { + // add some info to the comments. + if (opt->optioninfo) + { + sprintf(newcomments+strlen(newcomments),"%s '%s' %s%s\n", + opt->epairname, + opt->optioninfo ? opt->optioninfo : "", + opt->optiondefault ? ", Default: " : "", + opt->optiondefault ? opt->optiondefault : ""); + } + else + { + sprintf(newcomments+strlen(newcomments),"%s %s%s\n", + opt->epairname, + opt->optiondefault ? ", Default: " : "", + opt->optiondefault ? opt->optiondefault : ""); + } + } + + GSList *choicelst; + switch(opt->optiontype) + { + case OPTION_FLAGS : + // grab the flags. + for (choicelst = opt->choices; choicelst != NULL; choicelst = choicelst->next) + { + choice_t *choice = (choice_t*) choicelst->data; + + int index = getindex(choice->value); + index--; + if (index < MAX_FLAGS) + { + strcpy(e->flagnames[index],choice->name); + } + else + { + Sys_Printf ("WARNING: baseclass '%s' has a spawnflag out of range, ignored!\n", bc->classname); + } + } + break; + case OPTION_CHOICES : + strcat(newcomments," Choices:\n"); + for (choicelst = opt->choices; choicelst != NULL; choicelst = choicelst->next) + { + choice_t *choice = (choice_t*) choicelst->data; + sprintf(newcomments+strlen(newcomments)," %5d - %s\n",choice->value,choice->name); + } + break; + } + } + } + + // name + if (e->name) free(e->name); + e->name = strdup(bc->classname); + + // fixed size initialisation + if (bc->classtype == CLASS_POINTCLASS) + { + e->fixedsize = true; + // some point classes dont seem to have size()'s in the fgd, so set up a default here.. + if ((e->mins[0] == 0) && (e->mins[1] == 0) && (e->mins[2] == 0) && + (e->maxs[0] == 0) && (e->maxs[1] == 0) && (e->maxs[2] == 0)) + { + e->mins[0] = -8; + e->mins[1] = -8; + e->mins[2] = -8; + e->maxs[0] = 8; + e->maxs[1] = 8; + e->maxs[2] = 8; + } + + if (e->texdef.GetName() == NULL) + { + // no color specified for this entity in the fgd file + // set one now + // Note: if this eclass_t is not fully built, then this may be + // overridden with the correct color. + + e->color[0] = 1; + e->color[1] = 0.5; // how about a nice bright pink, mmm, nice! :) + e->color[2] = 1; + + sprintf (color, "(%f %f %f)", e->color[0], e->color[1], e->color[2]); + e->texdef.SetName(color); + } + } + + // COMMENTS + if (newcomments[0]) + { + e->comments = addstr(e->comments,newcomments); + } +} + +/*! +create the eclass_t structures and add to the global list. +*/ +void Create_EClasses(GSList *l_classes) +{ + int count = 0; + // loop through the loaded structures finding all the non BaseClasses + for (GSList *clst = l_classes; clst != NULL; clst = clst->next) + { + class_t *c = (class_t *)clst->data; + + if (c->classtype == CLASS_BASECLASS) // not looking for these. + continue; + + eclass_t *e = (eclass_t *) malloc( sizeof( eclass_s )); + memset(e,0,sizeof( eclass_s )); + + EClass_ImportFromClass(e, l_classes, c ); + + // radiant will crash if this is null, and it still could be at this point. + if (!e->comments) + { + e->comments=strdup("No description available, check documentation\n"); + } + + // dump the spawnflags to the end of the comments. + int i; + bool havespawnflags; + + havespawnflags = false; + for (i = 0 ; i < MAX_FLAGS ; i++) + { + if (*e->flagnames[i]) havespawnflags = true; + } + + if (havespawnflags) + { + char spawnline[80]; + e->comments = addstr(e->comments,"Spawnflags\n"); + for (i = 0 ; i < MAX_FLAGS ; i++) + { + if (*e->flagnames[i]) + { + sprintf(spawnline," %d - %s\n", 1<flagnames[i]); + e->comments = addstr(e->comments,spawnline); + } + } + } + + Eclass_InsertAlphabetized (e); + count ++; + // Hydra: ttimo, I don't think this code is required... + // single ? + *Get_Eclass_E() = e; + Set_Eclass_Found(true); + if ( Get_Parsing_Single() ) + break; + } + + Sys_Printf ("FGD Loaded %d entities.\n", count); +} + +void Eclass_ScanFile (char *filename) +{ + int size; + char *data; + char temp[1024]; + GSList *l_classes = NULL; + char token_debug[1024]; //++Hydra FIXME: cleanup this. + bool done = false; + int len,classtype; + + char *token = Token(); + + QE_ConvertDOSToUnixName( temp, filename ); + + size = vfsLoadFullPathFile (filename, (void**)&data); + if (size <= 0) + { + Sys_FPrintf (SYS_ERR, "Eclass_ScanFile: %s not found\n", filename); + return; + } + Sys_Printf ("ScanFile: %s\n", temp); + + // start parsing the file + StartTokenParsing(data); + + // build a list of base classes first + + while (!done) + { + // find an @ sign. + do + { + if (!GetToken(true)) + { + done = true; + break; + } + } while (token[0] != '@'); + + strcpy(temp,token+1); // skip the @ + + classtype = CLASS_NOCLASS; + if (!stricmp(temp,"BaseClass")) classtype = CLASS_BASECLASS; + if (!stricmp(temp,"PointClass")) classtype = CLASS_POINTCLASS; + if (!stricmp(temp,"SolidClass")) classtype = CLASS_SOLIDCLASS; + + if (classtype) + { + class_t *newclass = (class_t *) malloc( sizeof(class_s) ); + memset( newclass, 0, sizeof(class_s) ); + newclass->classtype = classtype; + + while (1) + { + GetTokenExtra(false,"(",false); // option or = + strcpy(token_debug,token); + + if (!strcmp(token,"=")) + { + UnGetToken(); + break; + } + else + { + strlower(token); + if (!strcmp(token,"base")) + { + GetTokenExtra(false,"(",true); // ( + + if (!strcmp(token,"(")) + { + while (GetTokenExtra(false,",)",false)) // option) or option, + { + newclass->l_baselist = g_slist_append (newclass->l_baselist, strdup(token)); + + GetTokenExtra(false,",)",true); // , or ) + if (!strcmp(token,")")) + break; + + } + } + } + else if (!strcmp(token,"size")) + { + // parse (w h d) or (x y z, x y z) + + GetTokenExtra(false,"(",true); // ( + if (!strcmp(token,"(")) + { + int sizedone = false; + float w,h,d; + GetToken(false); + w = atof(token); + GetToken(false); + h = atof(token); + GetToken(false); // number) or number , + strcpy(temp,token); + len = strlen(temp); + if (temp[len-1] == ')') sizedone = true; + temp[len-1] = 0; + d = atof(temp); + if (sizedone) + { + // only one set of cordinates supplied, change the W,H,D to mins/maxs + newclass->boundingbox[0][0] = 0 - (w / 2); + newclass->boundingbox[1][0] = w / 2; + newclass->boundingbox[0][1] = 0 - (h / 2); + newclass->boundingbox[1][1] = h / 2; + newclass->boundingbox[0][2] = 0 - (d / 2); + newclass->boundingbox[1][2] = d / 2; + newclass->gotsize = true; + } + else + { + newclass->boundingbox[0][0] = w; + newclass->boundingbox[0][1] = h; + newclass->boundingbox[0][2] = d; + GetToken(false); + newclass->boundingbox[1][0] = atof(token); + GetToken(false); + newclass->boundingbox[1][1] = atof(token); +/* + GetToken(false); // "number)" or "number )" + strcpy(temp,token); + len = strlen(temp); + if (temp[len-1] == ')') + temp[len-1] = 0; + else + GetToken(false); // ) + newclass->boundingbox[1][2] = atof(temp); +*/ + GetTokenExtra(false,")",false); // number + newclass->boundingbox[1][2] = atof(token); + newclass->gotsize = true; + GetTokenExtra(false,")",true); // ) + } + } + } + else if (!strcmp(token,"color")) + { + GetTokenExtra(false,"(",true); // ( + if (!strcmp(token,"(")) + { + // get the color values (0-255) and normalize them if required. + GetToken(false); + newclass->color[0] = atof(token); + if (newclass->color[0] > 1) + newclass->color[0]/=255; + GetToken(false); + newclass->color[1] = atof(token); + if (newclass->color[1] > 1) + newclass->color[1]/=255; + GetToken(false); + strcpy(temp,token); + len = strlen(temp); + if (temp[len-1] == ')') temp[len-1] = 0; + newclass->color[2] = atof(temp); + if (newclass->color[2] > 1) + newclass->color[2]/=255; + newclass->gotcolor = true; + } + } + else if (!strcmp(token,"iconsprite")) + { + GetTokenExtra(false,"(",true); // ( + if (!strcmp(token,"(")) + { + GetTokenExtra(false,")",false); // filename) + // the model plugins will handle sprites too. + // newclass->sprite = strdup(token); + newclass->model = strdup(token); + GetTokenExtra(false,")",true); // ) + } + } + else if (!strcmp(token,"model")) + { + GetTokenExtra(false,"(",true); // ( + if (!strcmp(token,"(")) + { + GetTokenExtra(false,")",false); // filename) + newclass->model = strdup(token); + GetTokenExtra(false,")",true); // ) + } + } + else + { + // Unsupported + GetToken(false); // skip it. + } + + } + } + + GetToken(false); // = + strcpy(token_debug,token); + if (!strcmp(token,"=")) + { + GetToken(false); + newclass->classname = strdup(token); + } + + // Get the description + if (newclass->classtype != CLASS_BASECLASS) + { + GetToken(false); + if (!strcmp(token,":")) + { + GetToken(false); + newclass->description = strdup(token); + } else UnGetToken(); // no description + } + + // now build the option list. + GetToken(true); // [ or [] + + if (strcmp(token,"[]")) // got some options ? + { + if (!strcmp(token,"[")) + { + // yup + bool optioncomplete = false; + option_t *newoption; + + while (1) + { + GetToken(true); + if (!strcmp(token,"]")) + break; // no more options + + // parse the data and build the option_t + + strcpy(temp,token); + len = strlen(temp); + char *ptr = strchr(temp,'('); + + if (!ptr) + break; + + newoption = (option_t *) malloc ( sizeof( option_s )); + memset( newoption, 0, sizeof( option_s )); + + *ptr++ = 0; + newoption->epairname = strdup(temp); + + len = strlen(ptr); + if (ptr[len-1] != ')') + break; + + ptr[len-1] = 0; + strlower(ptr); + if (!strcmp(ptr,"integer")) + { + newoption->optiontype = OPTION_INTEGER; + } + else if (!strcmp(ptr,"choices")) + { + newoption->optiontype = OPTION_CHOICES; + } + else if (!strcmp(ptr,"flags")) + { + newoption->optiontype = OPTION_FLAGS; + } + else // string + { + newoption->optiontype = OPTION_STRING; + } + + switch (newoption->optiontype) + { + case OPTION_STRING : + case OPTION_INTEGER : + if (!TokenAvailable()) + { + optioncomplete = true; + break; + } + GetToken(false); // : + strcpy(token_debug,token); + if ((token[0] == ':') && (strlen(token) > 1)) + { + newoption->optioninfo = strdup(token+1); + } + else + { + GetToken(false); + newoption->optioninfo = strdup(token); + } + if (TokenAvailable()) // default value ? + { + GetToken(false); + if (!strcmp(token,":")) + { + if (GetToken(false)) + { + newoption->optiondefault = strdup(token); + optioncomplete = true; + } + } + } + else + { + optioncomplete = true; + } + break; + + case OPTION_CHOICES : + GetTokenExtra(false,":",true); // : or :"something like this" (bah!) + strcpy(token_debug,token); + if ((token[0] == ':') && (strlen(token) > 1)) + { + if (token[1] == '\"') + { + strcpy(temp,token+2); + while (1) + { + if (!GetToken(false)) + break; + strcat(temp," "); + strcat(temp,token); + len = strlen(temp); + if (temp[len-1] == '\"') + { + temp[len-1] = 0; + break; + } + } + } + newoption->optioninfo = strdup(temp); + } + else + { + GetToken(false); + newoption->optioninfo = strdup(token); + } + GetToken(false); // : or = + strcpy(token_debug,token); + if (!strcmp(token,":")) + { + GetToken(false); + newoption->optiondefault = strdup(token); + } + else + { + UnGetToken(); + } + // And Follow on... + case OPTION_FLAGS : + GetToken(false); // : or = + strcpy(token_debug,token); + if (strcmp(token,"=")) // missing ? + break; + + GetToken(true); // [ + strcpy(token_debug,token); + if (strcmp(token,"[")) // missing ? + break; + + choice_t *newchoice; + while (1) + { + GetTokenExtra(true,":",true); // "]" or "number", or "number:" + strcpy(token_debug,token); + if (!strcmp(token,"]")) // no more ? + { + optioncomplete = true; + break; + } + strcpy(temp,token); + len = strlen(temp); + if (temp[len-1] == ':') + { + temp[len-1] = 0; + } + else + { + GetToken(false); // : + if (strcmp(token,":")) // missing ? + break; + } + if (!TokenAvailable()) + break; + GetToken(false); // the name + + newchoice = (choice_t *) malloc ( sizeof( choice_s )); + memset( newchoice, 0, sizeof( choice_s )); + + newchoice->value = atoi(temp); + newchoice->name = strdup(token); + + newoption->choices = g_slist_append(newoption->choices, newchoice); + + // ignore any remaining tokens on the line + while (TokenAvailable()) GetToken(false); + + // and it we found a "]" on the end of the line, put it back in the queue. + if (!strcmp(token,"]")) UnGetToken(); + } + break; + + } + + // add option to the newclass + + if (optioncomplete) + { + if (newoption) + { + // add it to the list. + newclass->l_optionlist = g_slist_append(newclass->l_optionlist, newoption); + } + } + else + { + Sys_Printf ("%WARNING: Parse error occured in '%s - %s'\n",classnames[newclass->classtype],newclass->classname); + Free_Option(newoption); + } + + } + } + else + { + UnGetToken(); // shouldn't get here. + } + } + + // add it to our list. + l_classes = g_slist_append (l_classes, newclass); + + } + } + + // finished with the file now. + g_free(data); + + Sys_Printf ("FGD scan complete, building entities...\n"); + + // Once we get here we should have a few (!) lists in memory that we + // can extract all the information required to build a the eclass_t structures. + + Create_EClasses(l_classes); + + // Free everything + + GSList *p = l_classes; + while (p) + { + class_t *tmpclass = (class_t *)p->data; + +#ifdef FGD_VERBOSE + // DEBUG: dump the info... + Sys_Printf ("%s: %s (", classnames[tmpclass->classtype],tmpclass->classname); + for (GSList *tmp = tmpclass->l_baselist; tmp != NULL; tmp = tmp->next) + { + if (tmp != tmpclass->l_baselist) + { + Sys_Printf (", "); + } + Sys_Printf ("%s", (char *)tmp->data); + } + if (tmpclass->gotsize) + { + sprintf(temp,"(%.0f %.0f %.0f) - (%.0f %.0f %.0f)",tmpclass->boundingbox[0][0], + tmpclass->boundingbox[0][1], + tmpclass->boundingbox[0][2], + tmpclass->boundingbox[1][0], + tmpclass->boundingbox[1][1], + tmpclass->boundingbox[1][2]); + } else strcpy(temp,"No Size"); + Sys_Printf (") '%s' Size: %s",tmpclass->description ? tmpclass->description : "No description",temp); + if (tmpclass->gotcolor) + { + sprintf(temp,"(%d %d %d)",tmpclass->color[0], + tmpclass->color[1], + tmpclass->color[2]); + } else strcpy(temp,"No Color"); + Sys_Printf (" Color: %s Options:\n",temp); + if (!tmpclass->l_optionlist) + { + Sys_Printf (" No Options\n"); + } + else + { + option_t *tmpoption; + int count; + GSList *olst; + for (olst = tmpclass->l_optionlist, count = 1; olst != NULL; olst = olst->next, count ++) + { + tmpoption = (option_t *)olst->data; + Sys_Printf (" %d, Type: %s, EPair: %s\n", count,optionnames[tmpoption->optiontype], tmpoption->epairname ); + + choice_t *tmpchoice; + GSList *clst; + int ccount; + for (clst = tmpoption->choices, ccount = 1; clst != NULL; clst = clst->next, ccount ++) + { + tmpchoice = (choice_t *)clst->data; + Sys_Printf (" %d, Value: %d, Name: %s\n", ccount, tmpchoice->value, tmpchoice->name); + } + } + } + +#endif + + // free the baselist. + ClearGSList(tmpclass->l_baselist); + Free_Class (tmpclass); + p = g_slist_remove (p, p->data); + } + +} diff --git a/plugins/entity/eclassmodel.cpp b/plugins/entity/eclassmodel.cpp index dc5b7c6e..c4c6dde7 100644 --- a/plugins/entity/eclassmodel.cpp +++ b/plugins/entity/eclassmodel.cpp @@ -1,175 +1,175 @@ -/* -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 -*/ - -#include - -#include "entity_entitymodel.h" - -// -// CEntityEclassModel implementation -// - -CEntityEclassModel::CEntityEclassModel () -{ - refCount = 1; - m_eclass = NULL; - m_model = NULL; - VectorSet(m_translate, 0,0,0); - VectorSet(m_euler, 0,0,0); - VectorSet(m_scale, 1,1,1); - VectorSet(m_pivot, 0,0,0); - m4x4_identity(m_transform); - m4x4_identity(m_inverse_transform); -} - -CEntityEclassModel::~CEntityEclassModel () -{ - if(m_name.c_str()[0] != '\0' - && m_version.c_str()[0] != '\0') - GetModelCache()->DeleteByID(m_name.c_str(), m_version.c_str()); -} - - -// IRender - -void CEntityEclassModel::Draw(int state, int rflags) const -{ - // push the current modelview matrix - // FIXME: put in a check for stack recursion depth.. - // or avoid recursion of opengl matrix stack - g_QglTable.m_pfn_qglPushMatrix(); - // apply the parent-to-local transform - g_QglTable.m_pfn_qglMultMatrixf(m_transform); - - // draw children - if(m_model && m_model->pRender) - { - m_model->pRender->Draw(state, rflags); - } - - g_QglTable.m_pfn_qglPopMatrix(); -} - -// ISelect - -bool CEntityEclassModel::TestRay(const ray_t *ray, vec_t *dist) const -{ - vec_t dist_start = *dist; - vec_t dist_local = *dist; - ray_t ray_local = *ray; - - if (aabb_intersect_ray(&m_BBox, &ray_local, &dist_local)) - *dist = dist_local; - return *dist < dist_start; -} - - -//IEdit - -void CEntityEclassModel::Translate(const vec3_t translation) -{ - VectorIncrement(translation, m_translate); - UpdateCachedData(); -} - -void CEntityEclassModel::Rotate(const vec3_t pivot, const vec3_t rotation) -{ - m4x4_t rotation_matrix; - - m4x4_identity(rotation_matrix); - m4x4_pivoted_rotate_by_vec3(rotation_matrix, rotation, eXYZ, pivot); - m4x4_transform_point(rotation_matrix, m_translate); - - VectorIncrement(rotation, m_euler); - - UpdateCachedData(); -} - -void CEntityEclassModel::OnKeyValueChanged(entity_t *e, const char *key, const char* value) -{ - if(strcmp(key,"origin") == 0) - { - sscanf(value, "%f %f %f", &m_translate[0], &m_translate[1], &m_translate[2]); - UpdateCachedData(); - } - else if(strcmp(key,"angle") == 0) - { - VectorSet(m_euler, 0, 0, (float) atof(value)); - UpdateCachedData(); - } -} - -void CEntityEclassModel::SetEclass(const eclass_t* eclass) -{ - m_eclass = eclass; -} - -void CEntityEclassModel::SetName(const char *name) -{ - if(strcmp(m_name.c_str(), name) == 0) - return; - - if(m_name.c_str()[0] != '\0' - && m_version.c_str()[0] != '\0') - GetModelCache()->DeleteByID(m_name.c_str(), m_version.c_str()); - - m_model = NULL; - m_name = name; - - if(m_name.c_str()[0] != '\0') - { - const char* dot = strrchr(m_name.c_str(), '.'); - if(dot != NULL) - { - m_version = ++dot; - m_model = GetModelCache()->GetByID(m_name.c_str(), m_version.c_str()); - } - } - - UpdateCachedData(); -} - -// -// CEntityEclassModel -// - -// private: - -void CEntityEclassModel::UpdateCachedData() -{ - aabb_t aabb_temp; - - aabb_clear(&aabb_temp); - - m4x4_identity(m_transform); - m4x4_pivoted_transform_by_vec3(m_transform, m_translate, m_euler, eXYZ, m_scale, m_pivot); - memcpy(m_inverse_transform, m_transform, sizeof(m4x4_t)); - if(m4x4_invert(m_inverse_transform) == 1) { - Sys_Printf("ERROR: Singular Matrix, cannot invert"); - } - - if(m_eclass) - aabb_construct_for_vec3(&aabb_temp, m_eclass->mins, m_eclass->maxs); - else - VectorSet(aabb_temp.extents, 8, 8, 8); - - aabb_for_transformed_aabb(&m_BBox, &aabb_temp, m_transform); -} +/* +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 +*/ + +#include + +#include "entity_entitymodel.h" + +// +// CEntityEclassModel implementation +// + +CEntityEclassModel::CEntityEclassModel () +{ + refCount = 1; + m_eclass = NULL; + m_model = NULL; + VectorSet(m_translate, 0,0,0); + VectorSet(m_euler, 0,0,0); + VectorSet(m_scale, 1,1,1); + VectorSet(m_pivot, 0,0,0); + m4x4_identity(m_transform); + m4x4_identity(m_inverse_transform); +} + +CEntityEclassModel::~CEntityEclassModel () +{ + if(m_name.c_str()[0] != '\0' + && m_version.c_str()[0] != '\0') + GetModelCache()->DeleteByID(m_name.c_str(), m_version.c_str()); +} + + +// IRender + +void CEntityEclassModel::Draw(int state, int rflags) const +{ + // push the current modelview matrix + // FIXME: put in a check for stack recursion depth.. + // or avoid recursion of opengl matrix stack + g_QglTable.m_pfn_qglPushMatrix(); + // apply the parent-to-local transform + g_QglTable.m_pfn_qglMultMatrixf(m_transform); + + // draw children + if(m_model && m_model->pRender) + { + m_model->pRender->Draw(state, rflags); + } + + g_QglTable.m_pfn_qglPopMatrix(); +} + +// ISelect + +bool CEntityEclassModel::TestRay(const ray_t *ray, vec_t *dist) const +{ + vec_t dist_start = *dist; + vec_t dist_local = *dist; + ray_t ray_local = *ray; + + if (aabb_intersect_ray(&m_BBox, &ray_local, &dist_local)) + *dist = dist_local; + return *dist < dist_start; +} + + +//IEdit + +void CEntityEclassModel::Translate(const vec3_t translation) +{ + VectorIncrement(translation, m_translate); + UpdateCachedData(); +} + +void CEntityEclassModel::Rotate(const vec3_t pivot, const vec3_t rotation) +{ + m4x4_t rotation_matrix; + + m4x4_identity(rotation_matrix); + m4x4_pivoted_rotate_by_vec3(rotation_matrix, rotation, eXYZ, pivot); + m4x4_transform_point(rotation_matrix, m_translate); + + VectorIncrement(rotation, m_euler); + + UpdateCachedData(); +} + +void CEntityEclassModel::OnKeyValueChanged(entity_t *e, const char *key, const char* value) +{ + if(strcmp(key,"origin") == 0) + { + sscanf(value, "%f %f %f", &m_translate[0], &m_translate[1], &m_translate[2]); + UpdateCachedData(); + } + else if(strcmp(key,"angle") == 0) + { + VectorSet(m_euler, 0, 0, (float) atof(value)); + UpdateCachedData(); + } +} + +void CEntityEclassModel::SetEclass(const eclass_t* eclass) +{ + m_eclass = eclass; +} + +void CEntityEclassModel::SetName(const char *name) +{ + if(strcmp(m_name.c_str(), name) == 0) + return; + + if(m_name.c_str()[0] != '\0' + && m_version.c_str()[0] != '\0') + GetModelCache()->DeleteByID(m_name.c_str(), m_version.c_str()); + + m_model = NULL; + m_name = name; + + if(m_name.c_str()[0] != '\0') + { + const char* dot = strrchr(m_name.c_str(), '.'); + if(dot != NULL) + { + m_version = ++dot; + m_model = GetModelCache()->GetByID(m_name.c_str(), m_version.c_str()); + } + } + + UpdateCachedData(); +} + +// +// CEntityEclassModel +// + +// private: + +void CEntityEclassModel::UpdateCachedData() +{ + aabb_t aabb_temp; + + aabb_clear(&aabb_temp); + + m4x4_identity(m_transform); + m4x4_pivoted_transform_by_vec3(m_transform, m_translate, m_euler, eXYZ, m_scale, m_pivot); + memcpy(m_inverse_transform, m_transform, sizeof(m4x4_t)); + if(m4x4_invert(m_inverse_transform) == 1) { + Sys_Printf("ERROR: Singular Matrix, cannot invert"); + } + + if(m_eclass) + aabb_construct_for_vec3(&aabb_temp, m_eclass->mins, m_eclass->maxs); + else + VectorSet(aabb_temp.extents, 8, 8, 8); + + aabb_for_transformed_aabb(&m_BBox, &aabb_temp, m_transform); +} diff --git a/plugins/entity/entity.cpp b/plugins/entity/entity.cpp index 9da72ce4..28faf425 100644 --- a/plugins/entity/entity.cpp +++ b/plugins/entity/entity.cpp @@ -1,377 +1,377 @@ -/* -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 -*/ - -#include "plugin.h" -#include "entity.h" -#include "entity_entitymodel.h" -#include "light.h" - -int g_entityId = 1; - - - -// internal - -static void Entity_FreeEpairs(entity_t *e); - -static void SetKeyValue (epair_t *&e, const char *key, const char *value); -static void DeleteKey (epair_t *&e, const char *key); -static const char *ValueForKey ( epair_t *&e, const char *key); - -static void Entity_OnKeyValueChanged(entity_t *e, const char* key, const char* value); - -// constructor -entity_t *Entity_Alloc() -{ - entity_t *e; - e = (entity_t*)malloc (sizeof(*e)); - e->entityId = g_entityId++; - VectorSet(e->origin, 0, 0, 0); - VectorSet(e->color, 1, 1, 1); - e->redoId = 0; - e->undoId = 0; - e->next = e->prev = NULL; - e->brushes.onext = e->brushes.oprev = &e->brushes; - e->epairs = NULL; - e->eclass = NULL; - e->model.pRender = NULL; - e->model.pSelect = NULL; - e->model.pEdit = NULL; - return e; -} - -// destructor -void Entity_Free (entity_t *e) -{ - while (e->brushes.onext != &e->brushes) - Brush_Free( e->brushes.onext, true ); - - if (e->next) - { - e->next->prev = e->prev; - e->prev->next = e->next; - } - - Entity_FreeEpairs(e); - - if (e->model.pRender) - { - e->model.pRender->DecRef(); - e->model.pRender = NULL; - } - if (e->model.pSelect) - { - e->model.pSelect->DecRef(); - e->model.pSelect = NULL; - } - if (e->model.pEdit) - { - e->model.pEdit->DecRef(); - e->model.pEdit = NULL; - } - - free (e); -} - -// construct from entity -entity_t *Entity_Clone (entity_t *e) -{ - entity_t *n; - epair_t *ep; - - n = Entity_Alloc(); - n->eclass = e->eclass; - - for (ep = e->epairs ; ep ; ep=ep->next) - SetKeyValue(n, ep->key, ep->value); - - // copy some misc stuff as well - VectorCopy( e->origin, n->origin ); -// VectorCopy( e->vRotation, n->vRotation ); -// VectorCopy( e->vScale, n->vScale ); - -// n->bDirty = true; - - return n; -} - - - - - -const char *ValueForKey ( epair_t *&e, const char *key) -{ - epair_t *ep; - for (ep=e ; ep ; ep=ep->next) - { - if (!strcmp (ep->key, key) ) - { - return ep->value; - } - } - return ""; -} - -const char *ValueForKey (entity_t *ent, const char *key) -{ - return ValueForKey(ent->epairs, key); -} - -void SetKeyValue (epair_t *&e, const char *key, const char *value) -{ - epair_t *ep; - for (ep=e ; ep ; ep=ep->next) - { - if (!strcmp (ep->key, key) ) - { - free (ep->value); - ep->value = (char*)malloc(strlen(value)+1); - strcpy (ep->value, value); - return; - } - } - ep = (epair_t*)malloc (sizeof(*ep)); - ep->next = e; - e = ep; - ep->key = (char*)malloc(strlen(key)+1); - strcpy (ep->key, key); - ep->value = (char*)malloc(strlen(value)+1); - strcpy (ep->value, value); - -} - -void SetKeyValue (entity_t *ent, const char *key, const char *value) -{ - if (ent == NULL) - { - Sys_FPrintf(SYS_ERR, "ERROR: SetKeyValue: NULL entity \n"); - return; - } - - if (!key || !key[0]) - { - Sys_FPrintf(SYS_ERR, "ERROR: SetKeyValue: NULL or zero-length key\n"); - return; - } - - SetKeyValue(ent->epairs, key, value); - /*! - \todo TODO broadcast this through a clean messaging API ;-) - */ - Entity_OnKeyValueChanged(ent, key, value); -} - -void DeleteKey (epair_t *&e, const char *key) -{ - epair_t **ep, *next; - - ep = &e; - while (*ep) - { - next = *ep; - if ( !strcmp (next->key, key) ) - { - *ep = next->next; - free(next->key); - free(next->value); - free(next); - return; - } - ep = &next->next; - } -} - -void DeleteKey (entity_t *ent, const char *key) -{ - DeleteKey(ent->epairs, key); - Entity_OnKeyValueChanged(ent, key, ""); -} - -float FloatForKey (entity_t *ent, const char *key) -{ - const char *k; - - k = ValueForKey (ent, key); - return (float) atof(k); -} - -int IntForKey (entity_t *ent, const char *key) -{ - const char *k; - - k = ValueForKey (ent, key); - return atoi(k); -} - -void GetVectorForKey (entity_t *ent, const char *key, vec3_t vec) -{ - const char *k; - - k = ValueForKey (ent, key); - sscanf (k, "%f %f %f", &vec[0], &vec[1], &vec[2]); -} - -/* -=============== -Entity_FreeEpairs - -Frees the entity epairs. -=============== -*/ -void Entity_FreeEpairs(entity_t *e) -{ - epair_t *ep, *next; - - for (ep = e->epairs; ep; ep = next) - { - next = ep->next; - free (ep->key); - free (ep->value); - free (ep); - } - e->epairs = NULL; -} - -void Entity_AddToList(entity_t *e, entity_t *elist) -{ - if (e->next || e->prev) - Error ("Entity_AddToList: already linked"); - //e->next = elist->next; - //elist->next->prev = e; - //elist->next = e; - //e->prev = elist; - e->next = elist; - e->prev = elist->prev; - elist->prev->next = e; - elist->prev = e; -} - -void Entity_RemoveFromList (entity_t *e) -{ - if (!e->next || !e->prev) - Error ("Entity_RemoveFromList: not linked"); - e->next->prev = e->prev; - e->prev->next = e->next; - e->next = e->prev = NULL; -} - -void Entity_LinkBrush (entity_t *e, brush_t *b) -{ - if (b->oprev || b->onext) - Error ("Entity_LinkBrush: Already linked"); - b->owner = e; - -// b->onext = e->brushes.onext; -// b->oprev = &e->brushes; -// e->brushes.onext->oprev = b; -// e->brushes.onext = b; - /* - SPoG - changed to add brushes to end of list instead of start - so this can be used by map loader. - This could concievably cause a problem if someone is traversing e->brushes while calling this function. - So don't. - */ - b->onext = &e->brushes; - b->oprev = e->brushes.oprev; - e->brushes.oprev->onext = b; - e->brushes.oprev = b; -} - -void Entity_UnlinkBrush (brush_t *b) -{ - if (!b->onext || !b->oprev) - Error ("Entity_UnlinkBrush: Not currently linked"); - b->onext->oprev = b->oprev; - b->oprev->onext = b->onext; - b->onext = b->oprev = NULL; - b->owner = NULL; -} - -// for undo -int Entity_MemorySize(entity_t *e) -{ - epair_t *ep; - int size = 0; - - for (ep = e->epairs; ep; ep = ep->next) - { - size += strlen(ep->key); - size += strlen(ep->value); - size += sizeof(epair_t); - } - size += sizeof(entity_t); - return size; -} - -epair_t* Entity_AllocateEpair(const char *key, const char *value) -{ - epair_t *ep = (epair_t*)malloc (sizeof(*ep)); - ep->key = (char*)malloc(strlen(key)+1); - strcpy (ep->key, key); - ep->value = (char*)malloc(strlen(value)+1); - strcpy (ep->value, value); - ep->next = NULL; - return ep; -} - -epair_t** Entity_GetKeyValList(entity_t *e) -{ - return &e->epairs; -} - -void Entity_SetKeyValList(entity_t *e, epair_t* ep) -{ - if( e->epairs ) - Sys_Printf( "Warning : pe->epairs != NULL in Entity_SetKeyValList, will not set\n" ); - else { - e->epairs = ep; - - for (epair_t *pe_ep = e->epairs; pe_ep; pe_ep = pe_ep->next) - Entity_OnKeyValueChanged(e, pe_ep->key, pe_ep->value); - } -} - - -/*! -\todo FIXME TTimo -this is meant to raise messages instead of calling the IEdit directly -*/ -static void Entity_OnKeyValueChanged(entity_t *e, const char *key, const char* value) -{ - if(strcmp(key,"classname") == 0) - { - e->eclass = Eclass_ForName(value, false); - Entity_UpdateClass(e, value); - if(strcmp(value,"light") == 0) - for(epair_t* ep = e->epairs; ep != NULL; ep=ep->next) - Light_OnKeyValueChanged(e, ep->key, ep->value); - if(e->model.pEdit) - for(epair_t* ep = e->epairs; ep != NULL; ep=ep->next) - e->model.pEdit->OnKeyValueChanged(e, ep->key, ep->value); - } - else if(Entity_IsLight(e)) - Light_OnKeyValueChanged(e, key, value); - else if(e->model.pEdit) - e->model.pEdit->OnKeyValueChanged(e, key, value); - - // update brush mins/maxs for legacy culling system - if(e->model.pRender && e->brushes.onext != &e->brushes) - Brush_Build( e->brushes.onext, true, true, false, true ); -} +/* +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 +*/ + +#include "plugin.h" +#include "entity.h" +#include "entity_entitymodel.h" +#include "light.h" + +int g_entityId = 1; + + + +// internal + +static void Entity_FreeEpairs(entity_t *e); + +static void SetKeyValue (epair_t *&e, const char *key, const char *value); +static void DeleteKey (epair_t *&e, const char *key); +static const char *ValueForKey ( epair_t *&e, const char *key); + +static void Entity_OnKeyValueChanged(entity_t *e, const char* key, const char* value); + +// constructor +entity_t *Entity_Alloc() +{ + entity_t *e; + e = (entity_t*)malloc (sizeof(*e)); + e->entityId = g_entityId++; + VectorSet(e->origin, 0, 0, 0); + VectorSet(e->color, 1, 1, 1); + e->redoId = 0; + e->undoId = 0; + e->next = e->prev = NULL; + e->brushes.onext = e->brushes.oprev = &e->brushes; + e->epairs = NULL; + e->eclass = NULL; + e->model.pRender = NULL; + e->model.pSelect = NULL; + e->model.pEdit = NULL; + return e; +} + +// destructor +void Entity_Free (entity_t *e) +{ + while (e->brushes.onext != &e->brushes) + Brush_Free( e->brushes.onext, true ); + + if (e->next) + { + e->next->prev = e->prev; + e->prev->next = e->next; + } + + Entity_FreeEpairs(e); + + if (e->model.pRender) + { + e->model.pRender->DecRef(); + e->model.pRender = NULL; + } + if (e->model.pSelect) + { + e->model.pSelect->DecRef(); + e->model.pSelect = NULL; + } + if (e->model.pEdit) + { + e->model.pEdit->DecRef(); + e->model.pEdit = NULL; + } + + free (e); +} + +// construct from entity +entity_t *Entity_Clone (entity_t *e) +{ + entity_t *n; + epair_t *ep; + + n = Entity_Alloc(); + n->eclass = e->eclass; + + for (ep = e->epairs ; ep ; ep=ep->next) + SetKeyValue(n, ep->key, ep->value); + + // copy some misc stuff as well + VectorCopy( e->origin, n->origin ); +// VectorCopy( e->vRotation, n->vRotation ); +// VectorCopy( e->vScale, n->vScale ); + +// n->bDirty = true; + + return n; +} + + + + + +const char *ValueForKey ( epair_t *&e, const char *key) +{ + epair_t *ep; + for (ep=e ; ep ; ep=ep->next) + { + if (!strcmp (ep->key, key) ) + { + return ep->value; + } + } + return ""; +} + +const char *ValueForKey (entity_t *ent, const char *key) +{ + return ValueForKey(ent->epairs, key); +} + +void SetKeyValue (epair_t *&e, const char *key, const char *value) +{ + epair_t *ep; + for (ep=e ; ep ; ep=ep->next) + { + if (!strcmp (ep->key, key) ) + { + free (ep->value); + ep->value = (char*)malloc(strlen(value)+1); + strcpy (ep->value, value); + return; + } + } + ep = (epair_t*)malloc (sizeof(*ep)); + ep->next = e; + e = ep; + ep->key = (char*)malloc(strlen(key)+1); + strcpy (ep->key, key); + ep->value = (char*)malloc(strlen(value)+1); + strcpy (ep->value, value); + +} + +void SetKeyValue (entity_t *ent, const char *key, const char *value) +{ + if (ent == NULL) + { + Sys_FPrintf(SYS_ERR, "ERROR: SetKeyValue: NULL entity \n"); + return; + } + + if (!key || !key[0]) + { + Sys_FPrintf(SYS_ERR, "ERROR: SetKeyValue: NULL or zero-length key\n"); + return; + } + + SetKeyValue(ent->epairs, key, value); + /*! + \todo TODO broadcast this through a clean messaging API ;-) + */ + Entity_OnKeyValueChanged(ent, key, value); +} + +void DeleteKey (epair_t *&e, const char *key) +{ + epair_t **ep, *next; + + ep = &e; + while (*ep) + { + next = *ep; + if ( !strcmp (next->key, key) ) + { + *ep = next->next; + free(next->key); + free(next->value); + free(next); + return; + } + ep = &next->next; + } +} + +void DeleteKey (entity_t *ent, const char *key) +{ + DeleteKey(ent->epairs, key); + Entity_OnKeyValueChanged(ent, key, ""); +} + +float FloatForKey (entity_t *ent, const char *key) +{ + const char *k; + + k = ValueForKey (ent, key); + return (float) atof(k); +} + +int IntForKey (entity_t *ent, const char *key) +{ + const char *k; + + k = ValueForKey (ent, key); + return atoi(k); +} + +void GetVectorForKey (entity_t *ent, const char *key, vec3_t vec) +{ + const char *k; + + k = ValueForKey (ent, key); + sscanf (k, "%f %f %f", &vec[0], &vec[1], &vec[2]); +} + +/* +=============== +Entity_FreeEpairs + +Frees the entity epairs. +=============== +*/ +void Entity_FreeEpairs(entity_t *e) +{ + epair_t *ep, *next; + + for (ep = e->epairs; ep; ep = next) + { + next = ep->next; + free (ep->key); + free (ep->value); + free (ep); + } + e->epairs = NULL; +} + +void Entity_AddToList(entity_t *e, entity_t *elist) +{ + if (e->next || e->prev) + Error ("Entity_AddToList: already linked"); + //e->next = elist->next; + //elist->next->prev = e; + //elist->next = e; + //e->prev = elist; + e->next = elist; + e->prev = elist->prev; + elist->prev->next = e; + elist->prev = e; +} + +void Entity_RemoveFromList (entity_t *e) +{ + if (!e->next || !e->prev) + Error ("Entity_RemoveFromList: not linked"); + e->next->prev = e->prev; + e->prev->next = e->next; + e->next = e->prev = NULL; +} + +void Entity_LinkBrush (entity_t *e, brush_t *b) +{ + if (b->oprev || b->onext) + Error ("Entity_LinkBrush: Already linked"); + b->owner = e; + +// b->onext = e->brushes.onext; +// b->oprev = &e->brushes; +// e->brushes.onext->oprev = b; +// e->brushes.onext = b; + /* + SPoG - changed to add brushes to end of list instead of start - so this can be used by map loader. + This could concievably cause a problem if someone is traversing e->brushes while calling this function. + So don't. + */ + b->onext = &e->brushes; + b->oprev = e->brushes.oprev; + e->brushes.oprev->onext = b; + e->brushes.oprev = b; +} + +void Entity_UnlinkBrush (brush_t *b) +{ + if (!b->onext || !b->oprev) + Error ("Entity_UnlinkBrush: Not currently linked"); + b->onext->oprev = b->oprev; + b->oprev->onext = b->onext; + b->onext = b->oprev = NULL; + b->owner = NULL; +} + +// for undo +int Entity_MemorySize(entity_t *e) +{ + epair_t *ep; + int size = 0; + + for (ep = e->epairs; ep; ep = ep->next) + { + size += strlen(ep->key); + size += strlen(ep->value); + size += sizeof(epair_t); + } + size += sizeof(entity_t); + return size; +} + +epair_t* Entity_AllocateEpair(const char *key, const char *value) +{ + epair_t *ep = (epair_t*)malloc (sizeof(*ep)); + ep->key = (char*)malloc(strlen(key)+1); + strcpy (ep->key, key); + ep->value = (char*)malloc(strlen(value)+1); + strcpy (ep->value, value); + ep->next = NULL; + return ep; +} + +epair_t** Entity_GetKeyValList(entity_t *e) +{ + return &e->epairs; +} + +void Entity_SetKeyValList(entity_t *e, epair_t* ep) +{ + if( e->epairs ) + Sys_Printf( "Warning : pe->epairs != NULL in Entity_SetKeyValList, will not set\n" ); + else { + e->epairs = ep; + + for (epair_t *pe_ep = e->epairs; pe_ep; pe_ep = pe_ep->next) + Entity_OnKeyValueChanged(e, pe_ep->key, pe_ep->value); + } +} + + +/*! +\todo FIXME TTimo +this is meant to raise messages instead of calling the IEdit directly +*/ +static void Entity_OnKeyValueChanged(entity_t *e, const char *key, const char* value) +{ + if(strcmp(key,"classname") == 0) + { + e->eclass = Eclass_ForName(value, false); + Entity_UpdateClass(e, value); + if(strcmp(value,"light") == 0) + for(epair_t* ep = e->epairs; ep != NULL; ep=ep->next) + Light_OnKeyValueChanged(e, ep->key, ep->value); + if(e->model.pEdit) + for(epair_t* ep = e->epairs; ep != NULL; ep=ep->next) + e->model.pEdit->OnKeyValueChanged(e, ep->key, ep->value); + } + else if(Entity_IsLight(e)) + Light_OnKeyValueChanged(e, key, value); + else if(e->model.pEdit) + e->model.pEdit->OnKeyValueChanged(e, key, value); + + // update brush mins/maxs for legacy culling system + if(e->model.pRender && e->brushes.onext != &e->brushes) + Brush_Build( e->brushes.onext, true, true, false, true ); +} diff --git a/plugins/entity/entity_entitymodel.cpp b/plugins/entity/entity_entitymodel.cpp index 037ec6d4..53d7a1b1 100644 --- a/plugins/entity/entity_entitymodel.cpp +++ b/plugins/entity/entity_entitymodel.cpp @@ -1,138 +1,138 @@ -/* -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 -*/ - -#include - -#include "entity_entitymodel.h" - -void Entity_UpdateClass(entity_t *e, const char* value) -{ - if(strcmp(value, "misc_model") == 0 - || (strcmp(value, "misc_gamemodel") == 0) - || (strcmp(value, "model_static") == 0)) - { - if (e->model.pRender) e->model.pRender->DecRef(); - if (e->model.pSelect) e->model.pSelect->DecRef(); - if (e->model.pEdit) e->model.pEdit->DecRef(); - e->model.pRender = NULL; - e->model.pSelect = NULL; - e->model.pEdit = NULL; - - CEntityMiscModel *model = new CEntityMiscModel(e); - - e->model.pRender = (IRender*)model; - e->model.pRender->IncRef(); - e->model.pSelect = (ISelect*)model; - e->model.pSelect->IncRef(); - e->model.pEdit = (IEdit*)model; - e->model.pEdit->IncRef(); - - model->DecRef(); - } - else if(e->eclass && e->eclass->modelpath) - { - if (e->model.pRender) e->model.pRender->DecRef(); - if (e->model.pSelect) e->model.pSelect->DecRef(); - if (e->model.pEdit) e->model.pEdit->DecRef(); - e->model.pRender = NULL; - e->model.pSelect = NULL; - e->model.pEdit = NULL; - - CEntityEclassModel *model = new CEntityEclassModel; - - model->SetEclass(e->eclass); - model->SetName(e->eclass->modelpath); - - e->model.pRender = (IRender*)model; - e->model.pRender->IncRef(); - e->model.pSelect = (ISelect*)model; - e->model.pSelect->IncRef(); - e->model.pEdit = (IEdit*)model; - e->model.pEdit->IncRef(); - - model->DecRef(); - } -} - -void pivot_draw(const vec3_t pivot) -{ - vec3_t vCenter, vMin, vMax; - VectorCopy(pivot, vCenter); - - g_QglTable.m_pfn_qglPointSize(4); - - g_QglTable.m_pfn_qglBegin(GL_POINTS); - g_QglTable.m_pfn_qglVertex3fv(vCenter); - g_QglTable.m_pfn_qglEnd(); - - g_QglTable.m_pfn_qglBegin(GL_LINES); - vCenter[0] -= 8; - g_QglTable.m_pfn_qglVertex3fv(vCenter); - vCenter[0] += 16; - g_QglTable.m_pfn_qglVertex3fv(vCenter); - vCenter[0] -= 8; - vCenter[1] -= 8; - g_QglTable.m_pfn_qglVertex3fv(vCenter); - vCenter[1] += 16; - g_QglTable.m_pfn_qglVertex3fv(vCenter); - vCenter[1] -= 8; - vCenter[2] -= 8; - g_QglTable.m_pfn_qglVertex3fv(vCenter); - vCenter[2] += 16; - g_QglTable.m_pfn_qglVertex3fv(vCenter); - vCenter[2] -= 8; - g_QglTable.m_pfn_qglEnd(); - - VectorCopy(vCenter, vMin); - VectorCopy(vCenter, vMax); - vMin[0] -= 4; - vMin[1] -= 4; - vMin[2] -= 4; - vMax[0] += 4; - vMax[1] += 4; - vMax[2] += 4; - - g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP); - g_QglTable.m_pfn_qglVertex3f(vMin[0],vMin[1],vMin[2]); - g_QglTable.m_pfn_qglVertex3f(vMax[0],vMin[1],vMin[2]); - g_QglTable.m_pfn_qglVertex3f(vMax[0],vMax[1],vMin[2]); - g_QglTable.m_pfn_qglVertex3f(vMin[0],vMax[1],vMin[2]); - g_QglTable.m_pfn_qglEnd(); - - g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP); - g_QglTable.m_pfn_qglVertex3f(vMin[0],vMin[1],vMax[2]); - g_QglTable.m_pfn_qglVertex3f(vMax[0],vMin[1],vMax[2]); - g_QglTable.m_pfn_qglVertex3f(vMax[0],vMax[1],vMax[2]); - g_QglTable.m_pfn_qglVertex3f(vMin[0],vMax[1],vMax[2]); - g_QglTable.m_pfn_qglEnd(); - - g_QglTable.m_pfn_qglBegin(GL_LINES); - g_QglTable.m_pfn_qglVertex3f(vMin[0],vMin[1],vMin[2]); - g_QglTable.m_pfn_qglVertex3f(vMin[0],vMin[1],vMax[2]); - g_QglTable.m_pfn_qglVertex3f(vMin[0],vMax[1],vMax[2]); - g_QglTable.m_pfn_qglVertex3f(vMin[0],vMax[1],vMin[2]); - g_QglTable.m_pfn_qglVertex3f(vMax[0],vMin[1],vMin[2]); - g_QglTable.m_pfn_qglVertex3f(vMax[0],vMin[1],vMax[2]); - g_QglTable.m_pfn_qglVertex3f(vMax[0],vMax[1],vMax[2]); - g_QglTable.m_pfn_qglVertex3f(vMax[0],vMax[1],vMin[2]); - g_QglTable.m_pfn_qglEnd(); -} - +/* +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 +*/ + +#include + +#include "entity_entitymodel.h" + +void Entity_UpdateClass(entity_t *e, const char* value) +{ + if(strcmp(value, "misc_model") == 0 + || (strcmp(value, "misc_gamemodel") == 0) + || (strcmp(value, "model_static") == 0)) + { + if (e->model.pRender) e->model.pRender->DecRef(); + if (e->model.pSelect) e->model.pSelect->DecRef(); + if (e->model.pEdit) e->model.pEdit->DecRef(); + e->model.pRender = NULL; + e->model.pSelect = NULL; + e->model.pEdit = NULL; + + CEntityMiscModel *model = new CEntityMiscModel(e); + + e->model.pRender = (IRender*)model; + e->model.pRender->IncRef(); + e->model.pSelect = (ISelect*)model; + e->model.pSelect->IncRef(); + e->model.pEdit = (IEdit*)model; + e->model.pEdit->IncRef(); + + model->DecRef(); + } + else if(e->eclass && e->eclass->modelpath) + { + if (e->model.pRender) e->model.pRender->DecRef(); + if (e->model.pSelect) e->model.pSelect->DecRef(); + if (e->model.pEdit) e->model.pEdit->DecRef(); + e->model.pRender = NULL; + e->model.pSelect = NULL; + e->model.pEdit = NULL; + + CEntityEclassModel *model = new CEntityEclassModel; + + model->SetEclass(e->eclass); + model->SetName(e->eclass->modelpath); + + e->model.pRender = (IRender*)model; + e->model.pRender->IncRef(); + e->model.pSelect = (ISelect*)model; + e->model.pSelect->IncRef(); + e->model.pEdit = (IEdit*)model; + e->model.pEdit->IncRef(); + + model->DecRef(); + } +} + +void pivot_draw(const vec3_t pivot) +{ + vec3_t vCenter, vMin, vMax; + VectorCopy(pivot, vCenter); + + g_QglTable.m_pfn_qglPointSize(4); + + g_QglTable.m_pfn_qglBegin(GL_POINTS); + g_QglTable.m_pfn_qglVertex3fv(vCenter); + g_QglTable.m_pfn_qglEnd(); + + g_QglTable.m_pfn_qglBegin(GL_LINES); + vCenter[0] -= 8; + g_QglTable.m_pfn_qglVertex3fv(vCenter); + vCenter[0] += 16; + g_QglTable.m_pfn_qglVertex3fv(vCenter); + vCenter[0] -= 8; + vCenter[1] -= 8; + g_QglTable.m_pfn_qglVertex3fv(vCenter); + vCenter[1] += 16; + g_QglTable.m_pfn_qglVertex3fv(vCenter); + vCenter[1] -= 8; + vCenter[2] -= 8; + g_QglTable.m_pfn_qglVertex3fv(vCenter); + vCenter[2] += 16; + g_QglTable.m_pfn_qglVertex3fv(vCenter); + vCenter[2] -= 8; + g_QglTable.m_pfn_qglEnd(); + + VectorCopy(vCenter, vMin); + VectorCopy(vCenter, vMax); + vMin[0] -= 4; + vMin[1] -= 4; + vMin[2] -= 4; + vMax[0] += 4; + vMax[1] += 4; + vMax[2] += 4; + + g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMin[1],vMin[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMin[1],vMin[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMax[1],vMin[2]); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMax[1],vMin[2]); + g_QglTable.m_pfn_qglEnd(); + + g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMin[1],vMax[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMin[1],vMax[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMax[1],vMax[2]); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMax[1],vMax[2]); + g_QglTable.m_pfn_qglEnd(); + + g_QglTable.m_pfn_qglBegin(GL_LINES); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMin[1],vMin[2]); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMin[1],vMax[2]); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMax[1],vMax[2]); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMax[1],vMin[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMin[1],vMin[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMin[1],vMax[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMax[1],vMax[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMax[1],vMin[2]); + g_QglTable.m_pfn_qglEnd(); +} + diff --git a/plugins/entity/light.cpp b/plugins/entity/light.cpp index 1650c075..477fc72d 100644 --- a/plugins/entity/light.cpp +++ b/plugins/entity/light.cpp @@ -1,536 +1,536 @@ - -#include "plugin.h" -#include "entity.h" -#include "light.h" - -void DrawSphere(vec3_t center, float radius, int sides, int nGLState) -{ - int i, j; - float dt = (float) (2 * Q_PI / (float) sides); - float dp = (float) (Q_PI / (float) sides); - float t, p; - vec3_t v; - - if (radius <= 0) - return; - - g_QglTable.m_pfn_qglBegin(GL_TRIANGLES); - for (i = 0; i <= sides - 1; i++) { - for (j = 0; j <= sides - 2; j++) { - t = i * dt; - p = (float) ((j * dp) - (Q_PI / 2)); - - VectorPolar(v, radius, t, p); - VectorAdd(v, center, v); - g_QglTable.m_pfn_qglVertex3fv(v); - - VectorPolar(v, radius, t, p + dp); - VectorAdd(v, center, v); - g_QglTable.m_pfn_qglVertex3fv(v); - - VectorPolar(v, radius, t + dt, p + dp); - VectorAdd(v, center, v); - g_QglTable.m_pfn_qglVertex3fv(v); - - VectorPolar(v, radius, t, p); - VectorAdd(v, center, v); - g_QglTable.m_pfn_qglVertex3fv(v); - - VectorPolar(v, radius, t + dt, p + dp); - VectorAdd(v, center, v); - g_QglTable.m_pfn_qglVertex3fv(v); - - VectorPolar(v, radius, t + dt, p); - VectorAdd(v, center, v); - g_QglTable.m_pfn_qglVertex3fv(v); - } - } - - p = (float) ((sides - 1) * dp - (Q_PI / 2)); - for (i = 0; i <= sides - 1; i++) { - t = i * dt; - - VectorPolar(v, radius, t, p); - VectorAdd(v, center, v); - g_QglTable.m_pfn_qglVertex3fv(v); - - VectorPolar(v, radius, t + dt, p + dp); - VectorAdd(v, center, v); - g_QglTable.m_pfn_qglVertex3fv(v); - - VectorPolar(v, radius, t + dt, p); - VectorAdd(v, center, v); - g_QglTable.m_pfn_qglVertex3fv(v); - } - g_QglTable.m_pfn_qglEnd(); -} - -#define LIGHT_ATTEN_LINEAR 1 -#define LIGHT_ATTEN_ANGLE 2 -#define LIGHT_ATTEN_DISTANCE 4 - -#define LIGHT_Q3A_DEFAULT (LIGHT_ATTEN_ANGLE | LIGHT_ATTEN_DISTANCE) -#define LIGHT_WOLF_DEFAULT (LIGHT_ATTEN_LINEAR | LIGHT_ATTEN_DISTANCE) - -float CalculateEnvelopeForLight(entity_t * e, float fFalloffTolerance) -{ - float fEnvelope = 0.f; - int iSpawnFlags = atoi(ValueForKey(e, "spawnflags")); - int iLightFlags = 0; - float fFade = 1.f; - float fIntensity, fPhotons; - float fScale; - const char *gameFile = g_FuncTable.m_pfnGetGameFile(); - - // These variables are tweakable on the q3map2 console, setting to q3map2 - // default here as there is no way to find out what the user actually uses - // right now. Maybe move them to worldspawn? - float fPointScale = 7500.f; - float fLinearScale = 1.f / 8000.f; - //float fFalloffTolerance = 1.f; // Need it as parameter - - // Arnout: HACK for per-game radii - really need to move this to a per-game module? - if( !strcmp( gameFile, "wolf.game" ) || !strcmp( gameFile, "et.game" ) ) { - // Spawnflags : - // 1: nonlinear - // 2: angle - - // set default flags - iLightFlags = LIGHT_WOLF_DEFAULT; - - // inverse distance squared attenuation? - if (iSpawnFlags & 1) { - iLightFlags &= ~LIGHT_ATTEN_LINEAR; - iLightFlags |= LIGHT_ATTEN_ANGLE; - } - // angle attenuate - if (iSpawnFlags & 2) - iLightFlags |= LIGHT_ATTEN_ANGLE; - } else { - // Spawnflags : - // 1: linear - // 2: no angle - - // set default flags - iLightFlags = LIGHT_Q3A_DEFAULT; - - // linear attenuation? - if (iSpawnFlags & 1) { - iLightFlags |= LIGHT_ATTEN_LINEAR; - iLightFlags &= ~LIGHT_ATTEN_ANGLE; - } - // no angle attenuate? - if (iSpawnFlags & 2) - iLightFlags &= ~LIGHT_ATTEN_ANGLE; - } - - // set fade key (from wolf) - if (iLightFlags & LIGHT_ATTEN_LINEAR) { - fFade = FloatForKey(e, "fade"); - if (fFade <= 0.f) - fFade = 1.f; - } - // set light intensity - fIntensity = FloatForKey(e, "_light"); - if (fIntensity == 0.f) - fIntensity = FloatForKey(e, "light"); - if (fIntensity == 0.f) - fIntensity = 300.f; - - // set light scale (sof2) - fScale = FloatForKey(e, "scale"); - if (fScale <= 0.f) - fScale = 1.f; - fIntensity *= fScale; - - // amount of photons - fPhotons = fIntensity * fPointScale; - - // calculate envelope - - // solve distance for non-distance lights - if (!(iLightFlags & LIGHT_ATTEN_DISTANCE)) - //!\todo (spog) can't access global objects in a module - globals are EVIL - solution: API for querying global settings. - fEnvelope = 131072/*g_MaxWorldCoord * 2.f*/; - // solve distance for linear lights - else if (iLightFlags & LIGHT_ATTEN_LINEAR) - fEnvelope = ((fPhotons * fLinearScale) - fFalloffTolerance) / fFade; - // solve for inverse square falloff - else - fEnvelope = sqrt(fPhotons / fFalloffTolerance) /* + fRadius */ ; // Arnout radius is always 0, only for area lights - - return fEnvelope; -} - -float CalculateLightRadius(entity_t * e, bool outer) -{ - float fEnvelope = 0.f; - int iSpawnFlags = atoi(ValueForKey(e, "spawnflags")); - float fIntensity; - float fScale; - const char *gameFile = g_FuncTable.m_pfnGetGameFile(); - - fIntensity = FloatForKey(e, "light"); - if (fIntensity == 0.f) - fIntensity = 300.f; - - // Arnout: HACK for per-game radii - really need to move this to a per-game module - if( !strcmp( gameFile, "sof2.game" ) || !strcmp( gameFile, "jk2.game" ) || !strcmp( gameFile, "ja.game" )) { - // Spawnflags : - // 1: linear - // 2: noincidence - - if (!outer) { - if (iSpawnFlags & 2) - fIntensity *= .9; - else - fIntensity *= .25f; - } - // set light scale (sof2) - fScale = FloatForKey(e, "scale"); - if (fScale <= 0.f) - fScale = 1.f; - fIntensity *= fScale; - - fEnvelope = fIntensity; - } else { - float fPointScale = 7500.f; - - if (outer) - fEnvelope = sqrt(fIntensity * fPointScale / 48.f); - else - fEnvelope = sqrt(fIntensity * fPointScale / 255.f); - } - - return fEnvelope; -} - -void Light_OnIntensityChanged(entity_t* e) -{ - e->fLightEnvelope1[0] = CalculateEnvelopeForLight(e, 1.f); - e->fLightEnvelope1[1] = CalculateEnvelopeForLight(e, 48.f); - e->fLightEnvelope1[2] = CalculateEnvelopeForLight(e, 255.f); - - e->fLightEnvelope2[0] = CalculateLightRadius(e, TRUE); - e->fLightEnvelope2[1] = CalculateLightRadius(e, FALSE); -} - -void Light_OnKeyValueChanged(entity_t *e, const char *key, const char* value) -{ - if(strcmp(key,"_color") == 0) - { - if (sscanf(ValueForKey(e, "_color"),"%f %f %f", - &e->color[0], &e->color[1], &e->color[2]) != 3) - VectorSet(e->color, 1, 1, 1); - } - else if(strcmp(key,"spawnflags") == 0 || - strcmp(key,"fade") == 0 || - strcmp(key,"_light") == 0 || - strcmp(key,"light") == 0 || - strcmp(key,"scale") == 0) - { - Light_OnIntensityChanged(e); - } -} - -bool Entity_IsLight(entity_t *e) -{ - return e->eclass != NULL && e->eclass->nShowFlags & ECLASS_LIGHT;//strncmp(ValueforKey(e, "classname"), "light") == 0 -} - -static void DrawLightSphere(entity_t * e, int nGLState, int pref) -{ - const char *target = ValueForKey(e, "target"); - bool bIsSpotLight = !!target[0]; - //!\todo Write an API for modules to register preference settings, and make this preference module-specific. - int nPasses = pref == 1 ? 3 : 2; - - g_QglTable.m_pfn_qglPushAttrib(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - g_QglTable.m_pfn_qglDepthMask(GL_FALSE); - g_QglTable.m_pfn_qglEnable(GL_BLEND); - g_QglTable.m_pfn_qglBlendFunc(GL_ONE, GL_ONE); - - // Arnout: TODO: spotlight rendering - if (!(bIsSpotLight)) - { - switch(pref) - { - case 1: - g_QglTable.m_pfn_qglColor3f(e->color[0] * .05f, - e->color[1] * .05f, - e->color[2] * .05f); - DrawSphere(e->origin, e->fLightEnvelope1[0], 16, nGLState); - DrawSphere(e->origin, e->fLightEnvelope1[1], 16, nGLState); - DrawSphere(e->origin, e->fLightEnvelope1[2], 16, nGLState); - break; - case 2: - g_QglTable.m_pfn_qglColor3f(e->color[0] * .15f * .95f, - e->color[1] * .15f * .95f, - e->color[2] * .15f * .95f); - DrawSphere(e->origin, e->fLightEnvelope2[0], 16, nGLState); - DrawSphere(e->origin, e->fLightEnvelope2[1], 16, nGLState); - break; - - } - } - - g_QglTable.m_pfn_qglPopAttrib(); -} - -float F = 0.70710678f; -// North, East, South, West -vec3_t normals[8] = { { 0, F, F }, { F, 0, F }, { 0,-F, F }, {-F, 0, F }, - { 0, F,-F }, { F, 0,-F }, { 0,-F,-F }, {-F, 0,-F } }; - -unsigned short indices[24] = { 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 2, - 1, 2, 5, 1, 5, 4, 1, 4, 3, 1, 3, 2 }; - -void DrawLight(entity_t* e, int nGLState, int pref, int nViewType) -{ - int i; - // top, bottom, tleft, tright, bright, bleft - vec3_t points[6]; - vec3_t vMid, vMin, vMax; - VectorAdd(e->origin, e->eclass->mins, vMin); - VectorAdd(e->origin, e->eclass->maxs, vMax); - vMid[0] = (vMin[0] + vMax[0]) * 0.5; - vMid[1] = (vMin[1] + vMax[1]) * 0.5; - vMid[2] = (vMin[2] + vMax[2]) * 0.5; - - VectorSet(points[0], vMid[0], vMid[1], vMax[2]); - VectorSet(points[1], vMid[0], vMid[1], vMin[2]); - VectorSet(points[2], vMin[0], vMax[1], vMid[2]); - VectorSet(points[3], vMax[0], vMax[1], vMid[2]); - VectorSet(points[4], vMax[0], vMin[1], vMid[2]); - VectorSet(points[5], vMin[0], vMin[1], vMid[2]); - - if (nGLState & DRAW_GL_LIGHTING)// && g_PrefsDlg.m_bGLLighting) - { - g_QglTable.m_pfn_qglBegin(GL_TRIANGLES);// NOTE: comment to use gl_triangle_fan instead - //g_QglTable.m_pfn_qglBegin(GL_TRIANGLE_FAN); - g_QglTable.m_pfn_qglVertex3fv(points[0]); - g_QglTable.m_pfn_qglVertex3fv(points[2]); - g_QglTable.m_pfn_qglNormal3fv(normals[0]); - g_QglTable.m_pfn_qglVertex3fv(points[3]); - - g_QglTable.m_pfn_qglVertex3fv(points[0]);// - g_QglTable.m_pfn_qglVertex3fv(points[3]);// - g_QglTable.m_pfn_qglNormal3fv(normals[1]); - g_QglTable.m_pfn_qglVertex3fv(points[4]); - - g_QglTable.m_pfn_qglVertex3fv(points[0]);// - g_QglTable.m_pfn_qglVertex3fv(points[4]);// - g_QglTable.m_pfn_qglNormal3fv(normals[2]); - g_QglTable.m_pfn_qglVertex3fv(points[5]); - - g_QglTable.m_pfn_qglVertex3fv(points[0]);// - g_QglTable.m_pfn_qglVertex3fv(points[5]);// - g_QglTable.m_pfn_qglNormal3fv(normals[3]); - g_QglTable.m_pfn_qglVertex3fv(points[2]); - - //g_QglTable.m_pfn_qglEnd(); - //g_QglTable.m_pfn_qglBegin(GL_TRIANGLE_FAN); - - g_QglTable.m_pfn_qglVertex3fv(points[1]); - g_QglTable.m_pfn_qglVertex3fv(points[2]); - g_QglTable.m_pfn_qglNormal3fv(normals[7]); - g_QglTable.m_pfn_qglVertex3fv(points[5]); - - g_QglTable.m_pfn_qglVertex3fv(points[1]);// - g_QglTable.m_pfn_qglVertex3fv(points[5]);// - g_QglTable.m_pfn_qglNormal3fv(normals[6]); - g_QglTable.m_pfn_qglVertex3fv(points[4]); - - g_QglTable.m_pfn_qglVertex3fv(points[1]);// - g_QglTable.m_pfn_qglVertex3fv(points[4]);// - g_QglTable.m_pfn_qglNormal3fv(normals[5]); - g_QglTable.m_pfn_qglVertex3fv(points[3]); - - g_QglTable.m_pfn_qglVertex3fv(points[1]);// - g_QglTable.m_pfn_qglVertex3fv(points[3]);// - g_QglTable.m_pfn_qglNormal3fv(normals[4]); - g_QglTable.m_pfn_qglVertex3fv(points[2]); - - g_QglTable.m_pfn_qglEnd(); - } - else if (nGLState & DRAW_GL_FILL) - { - vec3_t colors[4]; - VectorScale(e->color, 0.95, colors[0]); - VectorScale(colors[0], 0.95, colors[1]); - VectorScale(colors[1], 0.95, colors[2]); - VectorScale(colors[2], 0.95, colors[3]); - g_QglTable.m_pfn_qglBegin(GL_TRIANGLES);// NOTE: comment to use gl_triangle_fan instead - //g_QglTable.m_pfn_qglBegin(GL_TRIANGLE_FAN); - g_QglTable.m_pfn_qglColor3fv(colors[0]); - g_QglTable.m_pfn_qglVertex3fv(points[0]); - g_QglTable.m_pfn_qglVertex3fv(points[2]); - g_QglTable.m_pfn_qglVertex3fv(points[3]); - - g_QglTable.m_pfn_qglColor3fv(colors[1]); - g_QglTable.m_pfn_qglVertex3fv(points[0]);// - g_QglTable.m_pfn_qglVertex3fv(points[3]);// - g_QglTable.m_pfn_qglVertex3fv(points[4]); - - g_QglTable.m_pfn_qglColor3fv(colors[2]); - g_QglTable.m_pfn_qglVertex3fv(points[0]);// - g_QglTable.m_pfn_qglVertex3fv(points[4]);// - g_QglTable.m_pfn_qglVertex3fv(points[5]); - - g_QglTable.m_pfn_qglColor3fv(colors[3]); - g_QglTable.m_pfn_qglVertex3fv(points[0]);// - g_QglTable.m_pfn_qglVertex3fv(points[5]);// - g_QglTable.m_pfn_qglVertex3fv(points[2]); - - //g_QglTable.m_pfn_qglEnd(); - //g_QglTable.m_pfn_qglBegin(GL_TRIANGLE_FAN); - - g_QglTable.m_pfn_qglColor3fv(colors[0]); - g_QglTable.m_pfn_qglVertex3fv(points[1]); - g_QglTable.m_pfn_qglVertex3fv(points[2]); - g_QglTable.m_pfn_qglVertex3fv(points[5]); - - g_QglTable.m_pfn_qglColor3fv(colors[1]); - g_QglTable.m_pfn_qglVertex3fv(points[1]);// - g_QglTable.m_pfn_qglVertex3fv(points[5]);// - g_QglTable.m_pfn_qglVertex3fv(points[4]); - - g_QglTable.m_pfn_qglColor3fv(colors[2]); - g_QglTable.m_pfn_qglVertex3fv(points[1]);// - g_QglTable.m_pfn_qglVertex3fv(points[4]);// - g_QglTable.m_pfn_qglVertex3fv(points[3]); - - g_QglTable.m_pfn_qglColor3fv(colors[3]); - g_QglTable.m_pfn_qglVertex3fv(points[1]);// - g_QglTable.m_pfn_qglVertex3fv(points[3]);// - g_QglTable.m_pfn_qglVertex3fv(points[2]); - - g_QglTable.m_pfn_qglEnd(); - } - else - { - g_QglTable.m_pfn_qglVertexPointer(3, GL_FLOAT, 0, points); - g_QglTable.m_pfn_qglDrawElements(GL_TRIANGLES, 24, GL_UNSIGNED_SHORT, indices); - } - - - // NOTE: prolly not relevant until some time.. - // check for DOOM lights - if (strlen(ValueForKey(e, "light_right")) > 0) { - vec3_t vRight, vUp, vTarget, vTemp; - GetVectorForKey (e, "light_right", vRight); - GetVectorForKey (e, "light_up", vUp); - GetVectorForKey (e, "light_target", vTarget); - - g_QglTable.m_pfn_qglColor3f(0, 1, 0); - g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP); - VectorAdd(vTarget, e->origin, vTemp); - VectorAdd(vTemp, vRight, vTemp); - VectorAdd(vTemp, vUp, vTemp); - g_QglTable.m_pfn_qglVertex3fv(e->origin); - g_QglTable.m_pfn_qglVertex3fv(vTemp); - VectorAdd(vTarget, e->origin, vTemp); - VectorAdd(vTemp, vUp, vTemp); - VectorSubtract(vTemp, vRight, vTemp); - g_QglTable.m_pfn_qglVertex3fv(e->origin); - g_QglTable.m_pfn_qglVertex3fv(vTemp); - VectorAdd(vTarget, e->origin, vTemp); - VectorAdd(vTemp, vRight, vTemp); - VectorSubtract(vTemp, vUp, vTemp); - g_QglTable.m_pfn_qglVertex3fv(e->origin); - g_QglTable.m_pfn_qglVertex3fv(vTemp); - VectorAdd(vTarget, e->origin, vTemp); - VectorSubtract(vTemp, vUp, vTemp); - VectorSubtract(vTemp, vRight, vTemp); - g_QglTable.m_pfn_qglVertex3fv(e->origin); - g_QglTable.m_pfn_qglVertex3fv(vTemp); - g_QglTable.m_pfn_qglEnd(); - - } - - if(nGLState & DRAW_GL_FILL) - { - DrawLightSphere(e, nGLState, pref); - } - else - { - // Arnout: FIXME: clean this up a bit - // now draw lighting radius stuff... - if (pref) - { - bool bDrawSpotlightArc = false; - int nPasses = pref == 1 ? 3 : 2; - - const char *target = ValueForKey(e, "target"); - bool bIsSpotLight = !!target[0]; - - /*!\todo Spotlight.. - if (bIsSpotLight) - { - // find the origin of the target... - entity_t *e = FindEntity("targetname", target); - - if (e) - bDrawSpotlightArc = true; - } - */ - - g_QglTable.m_pfn_qglPushAttrib(GL_LINE_BIT); - g_QglTable.m_pfn_qglLineStipple(8, 0xAAAA); - g_QglTable.m_pfn_qglEnable(GL_LINE_STIPPLE); - - float* envelope = (pref == 1) ? e->fLightEnvelope1 : e->fLightEnvelope2; - for (int iPass = 0; iPass < nPasses; iPass++) - { - float fRadius = envelope[iPass]; - - g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP); - - if (bIsSpotLight) - { - if (bDrawSpotlightArc) - { - // I give up on this, it's beyond me - } - } - else - { - if (fRadius > 0) - { - int i; - float ds, dc; - - for (i = 0; i <= 24; i++) - { - ds = sin((i * 2 * Q_PI) / 24); - dc = cos((i * 2 * Q_PI) / 24); - - switch (nViewType) - { - case 2: - g_QglTable.m_pfn_qglVertex3f(e->origin[0] + fRadius * dc, - e->origin[1] + fRadius * ds, - e->origin[2]); - break; - case 1: - g_QglTable.m_pfn_qglVertex3f(e->origin[0] + fRadius * dc, - e->origin[1], - e->origin[2] + fRadius * ds); - break; - case 0: - g_QglTable.m_pfn_qglVertex3f(e->origin[0], - e->origin[1] + fRadius * dc, - e->origin[2] + fRadius * ds); - break; - } - } - } - } - g_QglTable.m_pfn_qglEnd(); - } - g_QglTable.m_pfn_qglPopAttrib(); - } - } -} - - + +#include "plugin.h" +#include "entity.h" +#include "light.h" + +void DrawSphere(vec3_t center, float radius, int sides, int nGLState) +{ + int i, j; + float dt = (float) (2 * Q_PI / (float) sides); + float dp = (float) (Q_PI / (float) sides); + float t, p; + vec3_t v; + + if (radius <= 0) + return; + + g_QglTable.m_pfn_qglBegin(GL_TRIANGLES); + for (i = 0; i <= sides - 1; i++) { + for (j = 0; j <= sides - 2; j++) { + t = i * dt; + p = (float) ((j * dp) - (Q_PI / 2)); + + VectorPolar(v, radius, t, p); + VectorAdd(v, center, v); + g_QglTable.m_pfn_qglVertex3fv(v); + + VectorPolar(v, radius, t, p + dp); + VectorAdd(v, center, v); + g_QglTable.m_pfn_qglVertex3fv(v); + + VectorPolar(v, radius, t + dt, p + dp); + VectorAdd(v, center, v); + g_QglTable.m_pfn_qglVertex3fv(v); + + VectorPolar(v, radius, t, p); + VectorAdd(v, center, v); + g_QglTable.m_pfn_qglVertex3fv(v); + + VectorPolar(v, radius, t + dt, p + dp); + VectorAdd(v, center, v); + g_QglTable.m_pfn_qglVertex3fv(v); + + VectorPolar(v, radius, t + dt, p); + VectorAdd(v, center, v); + g_QglTable.m_pfn_qglVertex3fv(v); + } + } + + p = (float) ((sides - 1) * dp - (Q_PI / 2)); + for (i = 0; i <= sides - 1; i++) { + t = i * dt; + + VectorPolar(v, radius, t, p); + VectorAdd(v, center, v); + g_QglTable.m_pfn_qglVertex3fv(v); + + VectorPolar(v, radius, t + dt, p + dp); + VectorAdd(v, center, v); + g_QglTable.m_pfn_qglVertex3fv(v); + + VectorPolar(v, radius, t + dt, p); + VectorAdd(v, center, v); + g_QglTable.m_pfn_qglVertex3fv(v); + } + g_QglTable.m_pfn_qglEnd(); +} + +#define LIGHT_ATTEN_LINEAR 1 +#define LIGHT_ATTEN_ANGLE 2 +#define LIGHT_ATTEN_DISTANCE 4 + +#define LIGHT_Q3A_DEFAULT (LIGHT_ATTEN_ANGLE | LIGHT_ATTEN_DISTANCE) +#define LIGHT_WOLF_DEFAULT (LIGHT_ATTEN_LINEAR | LIGHT_ATTEN_DISTANCE) + +float CalculateEnvelopeForLight(entity_t * e, float fFalloffTolerance) +{ + float fEnvelope = 0.f; + int iSpawnFlags = atoi(ValueForKey(e, "spawnflags")); + int iLightFlags = 0; + float fFade = 1.f; + float fIntensity, fPhotons; + float fScale; + const char *gameFile = g_FuncTable.m_pfnGetGameFile(); + + // These variables are tweakable on the q3map2 console, setting to q3map2 + // default here as there is no way to find out what the user actually uses + // right now. Maybe move them to worldspawn? + float fPointScale = 7500.f; + float fLinearScale = 1.f / 8000.f; + //float fFalloffTolerance = 1.f; // Need it as parameter + + // Arnout: HACK for per-game radii - really need to move this to a per-game module? + if( !strcmp( gameFile, "wolf.game" ) || !strcmp( gameFile, "et.game" ) ) { + // Spawnflags : + // 1: nonlinear + // 2: angle + + // set default flags + iLightFlags = LIGHT_WOLF_DEFAULT; + + // inverse distance squared attenuation? + if (iSpawnFlags & 1) { + iLightFlags &= ~LIGHT_ATTEN_LINEAR; + iLightFlags |= LIGHT_ATTEN_ANGLE; + } + // angle attenuate + if (iSpawnFlags & 2) + iLightFlags |= LIGHT_ATTEN_ANGLE; + } else { + // Spawnflags : + // 1: linear + // 2: no angle + + // set default flags + iLightFlags = LIGHT_Q3A_DEFAULT; + + // linear attenuation? + if (iSpawnFlags & 1) { + iLightFlags |= LIGHT_ATTEN_LINEAR; + iLightFlags &= ~LIGHT_ATTEN_ANGLE; + } + // no angle attenuate? + if (iSpawnFlags & 2) + iLightFlags &= ~LIGHT_ATTEN_ANGLE; + } + + // set fade key (from wolf) + if (iLightFlags & LIGHT_ATTEN_LINEAR) { + fFade = FloatForKey(e, "fade"); + if (fFade <= 0.f) + fFade = 1.f; + } + // set light intensity + fIntensity = FloatForKey(e, "_light"); + if (fIntensity == 0.f) + fIntensity = FloatForKey(e, "light"); + if (fIntensity == 0.f) + fIntensity = 300.f; + + // set light scale (sof2) + fScale = FloatForKey(e, "scale"); + if (fScale <= 0.f) + fScale = 1.f; + fIntensity *= fScale; + + // amount of photons + fPhotons = fIntensity * fPointScale; + + // calculate envelope + + // solve distance for non-distance lights + if (!(iLightFlags & LIGHT_ATTEN_DISTANCE)) + //!\todo (spog) can't access global objects in a module - globals are EVIL - solution: API for querying global settings. + fEnvelope = 131072/*g_MaxWorldCoord * 2.f*/; + // solve distance for linear lights + else if (iLightFlags & LIGHT_ATTEN_LINEAR) + fEnvelope = ((fPhotons * fLinearScale) - fFalloffTolerance) / fFade; + // solve for inverse square falloff + else + fEnvelope = sqrt(fPhotons / fFalloffTolerance) /* + fRadius */ ; // Arnout radius is always 0, only for area lights + + return fEnvelope; +} + +float CalculateLightRadius(entity_t * e, bool outer) +{ + float fEnvelope = 0.f; + int iSpawnFlags = atoi(ValueForKey(e, "spawnflags")); + float fIntensity; + float fScale; + const char *gameFile = g_FuncTable.m_pfnGetGameFile(); + + fIntensity = FloatForKey(e, "light"); + if (fIntensity == 0.f) + fIntensity = 300.f; + + // Arnout: HACK for per-game radii - really need to move this to a per-game module + if( !strcmp( gameFile, "sof2.game" ) || !strcmp( gameFile, "jk2.game" ) || !strcmp( gameFile, "ja.game" )) { + // Spawnflags : + // 1: linear + // 2: noincidence + + if (!outer) { + if (iSpawnFlags & 2) + fIntensity *= .9; + else + fIntensity *= .25f; + } + // set light scale (sof2) + fScale = FloatForKey(e, "scale"); + if (fScale <= 0.f) + fScale = 1.f; + fIntensity *= fScale; + + fEnvelope = fIntensity; + } else { + float fPointScale = 7500.f; + + if (outer) + fEnvelope = sqrt(fIntensity * fPointScale / 48.f); + else + fEnvelope = sqrt(fIntensity * fPointScale / 255.f); + } + + return fEnvelope; +} + +void Light_OnIntensityChanged(entity_t* e) +{ + e->fLightEnvelope1[0] = CalculateEnvelopeForLight(e, 1.f); + e->fLightEnvelope1[1] = CalculateEnvelopeForLight(e, 48.f); + e->fLightEnvelope1[2] = CalculateEnvelopeForLight(e, 255.f); + + e->fLightEnvelope2[0] = CalculateLightRadius(e, TRUE); + e->fLightEnvelope2[1] = CalculateLightRadius(e, FALSE); +} + +void Light_OnKeyValueChanged(entity_t *e, const char *key, const char* value) +{ + if(strcmp(key,"_color") == 0) + { + if (sscanf(ValueForKey(e, "_color"),"%f %f %f", + &e->color[0], &e->color[1], &e->color[2]) != 3) + VectorSet(e->color, 1, 1, 1); + } + else if(strcmp(key,"spawnflags") == 0 || + strcmp(key,"fade") == 0 || + strcmp(key,"_light") == 0 || + strcmp(key,"light") == 0 || + strcmp(key,"scale") == 0) + { + Light_OnIntensityChanged(e); + } +} + +bool Entity_IsLight(entity_t *e) +{ + return e->eclass != NULL && e->eclass->nShowFlags & ECLASS_LIGHT;//strncmp(ValueforKey(e, "classname"), "light") == 0 +} + +static void DrawLightSphere(entity_t * e, int nGLState, int pref) +{ + const char *target = ValueForKey(e, "target"); + bool bIsSpotLight = !!target[0]; + //!\todo Write an API for modules to register preference settings, and make this preference module-specific. + int nPasses = pref == 1 ? 3 : 2; + + g_QglTable.m_pfn_qglPushAttrib(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + g_QglTable.m_pfn_qglDepthMask(GL_FALSE); + g_QglTable.m_pfn_qglEnable(GL_BLEND); + g_QglTable.m_pfn_qglBlendFunc(GL_ONE, GL_ONE); + + // Arnout: TODO: spotlight rendering + if (!(bIsSpotLight)) + { + switch(pref) + { + case 1: + g_QglTable.m_pfn_qglColor3f(e->color[0] * .05f, + e->color[1] * .05f, + e->color[2] * .05f); + DrawSphere(e->origin, e->fLightEnvelope1[0], 16, nGLState); + DrawSphere(e->origin, e->fLightEnvelope1[1], 16, nGLState); + DrawSphere(e->origin, e->fLightEnvelope1[2], 16, nGLState); + break; + case 2: + g_QglTable.m_pfn_qglColor3f(e->color[0] * .15f * .95f, + e->color[1] * .15f * .95f, + e->color[2] * .15f * .95f); + DrawSphere(e->origin, e->fLightEnvelope2[0], 16, nGLState); + DrawSphere(e->origin, e->fLightEnvelope2[1], 16, nGLState); + break; + + } + } + + g_QglTable.m_pfn_qglPopAttrib(); +} + +float F = 0.70710678f; +// North, East, South, West +vec3_t normals[8] = { { 0, F, F }, { F, 0, F }, { 0,-F, F }, {-F, 0, F }, + { 0, F,-F }, { F, 0,-F }, { 0,-F,-F }, {-F, 0,-F } }; + +unsigned short indices[24] = { 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 2, + 1, 2, 5, 1, 5, 4, 1, 4, 3, 1, 3, 2 }; + +void DrawLight(entity_t* e, int nGLState, int pref, int nViewType) +{ + int i; + // top, bottom, tleft, tright, bright, bleft + vec3_t points[6]; + vec3_t vMid, vMin, vMax; + VectorAdd(e->origin, e->eclass->mins, vMin); + VectorAdd(e->origin, e->eclass->maxs, vMax); + vMid[0] = (vMin[0] + vMax[0]) * 0.5; + vMid[1] = (vMin[1] + vMax[1]) * 0.5; + vMid[2] = (vMin[2] + vMax[2]) * 0.5; + + VectorSet(points[0], vMid[0], vMid[1], vMax[2]); + VectorSet(points[1], vMid[0], vMid[1], vMin[2]); + VectorSet(points[2], vMin[0], vMax[1], vMid[2]); + VectorSet(points[3], vMax[0], vMax[1], vMid[2]); + VectorSet(points[4], vMax[0], vMin[1], vMid[2]); + VectorSet(points[5], vMin[0], vMin[1], vMid[2]); + + if (nGLState & DRAW_GL_LIGHTING)// && g_PrefsDlg.m_bGLLighting) + { + g_QglTable.m_pfn_qglBegin(GL_TRIANGLES);// NOTE: comment to use gl_triangle_fan instead + //g_QglTable.m_pfn_qglBegin(GL_TRIANGLE_FAN); + g_QglTable.m_pfn_qglVertex3fv(points[0]); + g_QglTable.m_pfn_qglVertex3fv(points[2]); + g_QglTable.m_pfn_qglNormal3fv(normals[0]); + g_QglTable.m_pfn_qglVertex3fv(points[3]); + + g_QglTable.m_pfn_qglVertex3fv(points[0]);// + g_QglTable.m_pfn_qglVertex3fv(points[3]);// + g_QglTable.m_pfn_qglNormal3fv(normals[1]); + g_QglTable.m_pfn_qglVertex3fv(points[4]); + + g_QglTable.m_pfn_qglVertex3fv(points[0]);// + g_QglTable.m_pfn_qglVertex3fv(points[4]);// + g_QglTable.m_pfn_qglNormal3fv(normals[2]); + g_QglTable.m_pfn_qglVertex3fv(points[5]); + + g_QglTable.m_pfn_qglVertex3fv(points[0]);// + g_QglTable.m_pfn_qglVertex3fv(points[5]);// + g_QglTable.m_pfn_qglNormal3fv(normals[3]); + g_QglTable.m_pfn_qglVertex3fv(points[2]); + + //g_QglTable.m_pfn_qglEnd(); + //g_QglTable.m_pfn_qglBegin(GL_TRIANGLE_FAN); + + g_QglTable.m_pfn_qglVertex3fv(points[1]); + g_QglTable.m_pfn_qglVertex3fv(points[2]); + g_QglTable.m_pfn_qglNormal3fv(normals[7]); + g_QglTable.m_pfn_qglVertex3fv(points[5]); + + g_QglTable.m_pfn_qglVertex3fv(points[1]);// + g_QglTable.m_pfn_qglVertex3fv(points[5]);// + g_QglTable.m_pfn_qglNormal3fv(normals[6]); + g_QglTable.m_pfn_qglVertex3fv(points[4]); + + g_QglTable.m_pfn_qglVertex3fv(points[1]);// + g_QglTable.m_pfn_qglVertex3fv(points[4]);// + g_QglTable.m_pfn_qglNormal3fv(normals[5]); + g_QglTable.m_pfn_qglVertex3fv(points[3]); + + g_QglTable.m_pfn_qglVertex3fv(points[1]);// + g_QglTable.m_pfn_qglVertex3fv(points[3]);// + g_QglTable.m_pfn_qglNormal3fv(normals[4]); + g_QglTable.m_pfn_qglVertex3fv(points[2]); + + g_QglTable.m_pfn_qglEnd(); + } + else if (nGLState & DRAW_GL_FILL) + { + vec3_t colors[4]; + VectorScale(e->color, 0.95, colors[0]); + VectorScale(colors[0], 0.95, colors[1]); + VectorScale(colors[1], 0.95, colors[2]); + VectorScale(colors[2], 0.95, colors[3]); + g_QglTable.m_pfn_qglBegin(GL_TRIANGLES);// NOTE: comment to use gl_triangle_fan instead + //g_QglTable.m_pfn_qglBegin(GL_TRIANGLE_FAN); + g_QglTable.m_pfn_qglColor3fv(colors[0]); + g_QglTable.m_pfn_qglVertex3fv(points[0]); + g_QglTable.m_pfn_qglVertex3fv(points[2]); + g_QglTable.m_pfn_qglVertex3fv(points[3]); + + g_QglTable.m_pfn_qglColor3fv(colors[1]); + g_QglTable.m_pfn_qglVertex3fv(points[0]);// + g_QglTable.m_pfn_qglVertex3fv(points[3]);// + g_QglTable.m_pfn_qglVertex3fv(points[4]); + + g_QglTable.m_pfn_qglColor3fv(colors[2]); + g_QglTable.m_pfn_qglVertex3fv(points[0]);// + g_QglTable.m_pfn_qglVertex3fv(points[4]);// + g_QglTable.m_pfn_qglVertex3fv(points[5]); + + g_QglTable.m_pfn_qglColor3fv(colors[3]); + g_QglTable.m_pfn_qglVertex3fv(points[0]);// + g_QglTable.m_pfn_qglVertex3fv(points[5]);// + g_QglTable.m_pfn_qglVertex3fv(points[2]); + + //g_QglTable.m_pfn_qglEnd(); + //g_QglTable.m_pfn_qglBegin(GL_TRIANGLE_FAN); + + g_QglTable.m_pfn_qglColor3fv(colors[0]); + g_QglTable.m_pfn_qglVertex3fv(points[1]); + g_QglTable.m_pfn_qglVertex3fv(points[2]); + g_QglTable.m_pfn_qglVertex3fv(points[5]); + + g_QglTable.m_pfn_qglColor3fv(colors[1]); + g_QglTable.m_pfn_qglVertex3fv(points[1]);// + g_QglTable.m_pfn_qglVertex3fv(points[5]);// + g_QglTable.m_pfn_qglVertex3fv(points[4]); + + g_QglTable.m_pfn_qglColor3fv(colors[2]); + g_QglTable.m_pfn_qglVertex3fv(points[1]);// + g_QglTable.m_pfn_qglVertex3fv(points[4]);// + g_QglTable.m_pfn_qglVertex3fv(points[3]); + + g_QglTable.m_pfn_qglColor3fv(colors[3]); + g_QglTable.m_pfn_qglVertex3fv(points[1]);// + g_QglTable.m_pfn_qglVertex3fv(points[3]);// + g_QglTable.m_pfn_qglVertex3fv(points[2]); + + g_QglTable.m_pfn_qglEnd(); + } + else + { + g_QglTable.m_pfn_qglVertexPointer(3, GL_FLOAT, 0, points); + g_QglTable.m_pfn_qglDrawElements(GL_TRIANGLES, 24, GL_UNSIGNED_SHORT, indices); + } + + + // NOTE: prolly not relevant until some time.. + // check for DOOM lights + if (strlen(ValueForKey(e, "light_right")) > 0) { + vec3_t vRight, vUp, vTarget, vTemp; + GetVectorForKey (e, "light_right", vRight); + GetVectorForKey (e, "light_up", vUp); + GetVectorForKey (e, "light_target", vTarget); + + g_QglTable.m_pfn_qglColor3f(0, 1, 0); + g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP); + VectorAdd(vTarget, e->origin, vTemp); + VectorAdd(vTemp, vRight, vTemp); + VectorAdd(vTemp, vUp, vTemp); + g_QglTable.m_pfn_qglVertex3fv(e->origin); + g_QglTable.m_pfn_qglVertex3fv(vTemp); + VectorAdd(vTarget, e->origin, vTemp); + VectorAdd(vTemp, vUp, vTemp); + VectorSubtract(vTemp, vRight, vTemp); + g_QglTable.m_pfn_qglVertex3fv(e->origin); + g_QglTable.m_pfn_qglVertex3fv(vTemp); + VectorAdd(vTarget, e->origin, vTemp); + VectorAdd(vTemp, vRight, vTemp); + VectorSubtract(vTemp, vUp, vTemp); + g_QglTable.m_pfn_qglVertex3fv(e->origin); + g_QglTable.m_pfn_qglVertex3fv(vTemp); + VectorAdd(vTarget, e->origin, vTemp); + VectorSubtract(vTemp, vUp, vTemp); + VectorSubtract(vTemp, vRight, vTemp); + g_QglTable.m_pfn_qglVertex3fv(e->origin); + g_QglTable.m_pfn_qglVertex3fv(vTemp); + g_QglTable.m_pfn_qglEnd(); + + } + + if(nGLState & DRAW_GL_FILL) + { + DrawLightSphere(e, nGLState, pref); + } + else + { + // Arnout: FIXME: clean this up a bit + // now draw lighting radius stuff... + if (pref) + { + bool bDrawSpotlightArc = false; + int nPasses = pref == 1 ? 3 : 2; + + const char *target = ValueForKey(e, "target"); + bool bIsSpotLight = !!target[0]; + + /*!\todo Spotlight.. + if (bIsSpotLight) + { + // find the origin of the target... + entity_t *e = FindEntity("targetname", target); + + if (e) + bDrawSpotlightArc = true; + } + */ + + g_QglTable.m_pfn_qglPushAttrib(GL_LINE_BIT); + g_QglTable.m_pfn_qglLineStipple(8, 0xAAAA); + g_QglTable.m_pfn_qglEnable(GL_LINE_STIPPLE); + + float* envelope = (pref == 1) ? e->fLightEnvelope1 : e->fLightEnvelope2; + for (int iPass = 0; iPass < nPasses; iPass++) + { + float fRadius = envelope[iPass]; + + g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP); + + if (bIsSpotLight) + { + if (bDrawSpotlightArc) + { + // I give up on this, it's beyond me + } + } + else + { + if (fRadius > 0) + { + int i; + float ds, dc; + + for (i = 0; i <= 24; i++) + { + ds = sin((i * 2 * Q_PI) / 24); + dc = cos((i * 2 * Q_PI) / 24); + + switch (nViewType) + { + case 2: + g_QglTable.m_pfn_qglVertex3f(e->origin[0] + fRadius * dc, + e->origin[1] + fRadius * ds, + e->origin[2]); + break; + case 1: + g_QglTable.m_pfn_qglVertex3f(e->origin[0] + fRadius * dc, + e->origin[1], + e->origin[2] + fRadius * ds); + break; + case 0: + g_QglTable.m_pfn_qglVertex3f(e->origin[0], + e->origin[1] + fRadius * dc, + e->origin[2] + fRadius * ds); + break; + } + } + } + } + g_QglTable.m_pfn_qglEnd(); + } + g_QglTable.m_pfn_qglPopAttrib(); + } + } +} + + diff --git a/plugins/entity/miscmodel.cpp b/plugins/entity/miscmodel.cpp index 42152070..106fa17c 100644 --- a/plugins/entity/miscmodel.cpp +++ b/plugins/entity/miscmodel.cpp @@ -1,254 +1,254 @@ -/* -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 -*/ - -#include - -#include "entity_entitymodel.h" -#include "entity.h" - -// -// CEntityMiscModel implementation -// - -CEntityMiscModel::CEntityMiscModel (entity_t *e) -{ - refCount = 1; - m_entity = e; - m_model = NULL; - VectorSet(m_translate, 0,0,0); - VectorSet(m_euler, 0,0,0); - VectorSet(m_scale, 1,1,1); - VectorSet(m_pivot, 0,0,0); - m4x4_identity(m_transform); - m4x4_identity(m_inverse_transform); -} - -CEntityMiscModel::~CEntityMiscModel () -{ - if(m_cachereq.GetBuffer()[0] != ':' - && m_version.c_str()[0] != '\0') - GetModelCache()->DeleteByID(m_cachereq.GetBuffer(), m_version.c_str()); -} - - -// IRender - -void CEntityMiscModel::Draw(int state, int rflags) const -{ - // push the current modelview matrix - // FIXME: put in a check for stack recursion depth.. - // or avoid recursion of opengl matrix stack - g_QglTable.m_pfn_qglPushMatrix(); - // apply the parent-to-local transform - g_QglTable.m_pfn_qglMultMatrixf(m_transform); - - pivot_draw(m_pivot); - - // draw children - if(m_model && m_model->pRender) - { - m_model->pRender->Draw(state, rflags); - } - - g_QglTable.m_pfn_qglPopMatrix(); -} - -// ISelect - -bool CEntityMiscModel::TestRay(const ray_t *ray, vec_t *dist) const -{ - vec_t dist_start = *dist; - vec_t dist_local = *dist; - ray_t ray_local = *ray; - - if (aabb_test_ray(&m_BBox, ray) == 0) - return false; - - ray_transform(&ray_local, m_inverse_transform); - - if(m_model && m_model->pSelect) - { - if(m_model->pSelect->TestRay(&ray_local, &dist_local)) - *dist = dist_local; - } - else *dist = dist_local; - - return *dist < dist_start; -} - - -//IEdit - -void CEntityMiscModel::Translate(const vec3_t translation) -{ - VectorIncrement(translation, m_translate); - UpdateCachedData(); -} - -void CEntityMiscModel::Rotate(const vec3_t pivot, const vec3_t rotation) -{ - m4x4_t rotation_matrix; - - m4x4_identity(rotation_matrix); - m4x4_pivoted_rotate_by_vec3(rotation_matrix, rotation, eXYZ, pivot); - m4x4_transform_point(rotation_matrix, m_translate); - - VectorIncrement(rotation, m_euler); - - UpdateCachedData(); -} - -void CEntityMiscModel::OnKeyValueChanged(entity_t *e, const char *key, const char* value) -{ - if(strcmp(key, "model") == 0) - SetName(value); - else if(strcmp(key, "_frame") == 0) - { - SetName(ValueForKey(e, "model")); - } - else if(strcmp(key, "angle") == 0) - { - VectorSet(m_euler, 0.f, 0.f, 0.f); - m_euler[2] = atof(value); - UpdateCachedData(); - } - else if(strcmp(key, "angles") == 0) - { - VectorSet(m_euler, 0.f, 0.f, 0.f); - if (value[0] != '\0') - sscanf (value, "%f %f %f", &m_euler[1], &m_euler[2], &m_euler[0]); - UpdateCachedData(); - } - else if(strcmp(key, "modelscale") == 0 || strcmp(key,"modelscale_vec") == 0) - { - const char *s; - VectorSet(m_scale, 1.f, 1.f, 1.f); - s = ValueForKey(e,"modelscale"); - if (s[0] != '\0') - { - float f = atof(s); - if( f != 0 ) - VectorSet(m_scale, f, f, f); - else - Sys_FPrintf(SYS_WRN, "WARNING: ignoring 0 modelscale key\n"); - } - s = ValueForKey(e,"modelscale_vec"); - if (s[0] != '\0') - { - sscanf (s, "%f %f %f", &m_scale[0], &m_scale[1], &m_scale[2]); - if (m_scale[0] == 0.0 && m_scale[1] == 0.0 && m_scale[2] == 0.0) - { - VectorSet(m_scale, 1,1,1); - Sys_FPrintf(SYS_WRN, "WARNING: ignoring 0 0 0 modelscale_vec key\n"); - } - } - UpdateCachedData(); - } - else if(strcmp(key, "origin") == 0) - { - sscanf(value, "%f %f %f", &m_translate[0], &m_translate[1], &m_translate[2]); - UpdateCachedData(); - } - else if(strncmp(key,"_remap",6) == 0) - { - SetName(ValueForKey(e, "model")); - } -} - -// -// CEntityMiscModel -// - -// private: - -void CEntityMiscModel::BuildCacheRequestString(const char *name) -{ - bool hasRemaps = false; - - m_cachereq.Format( "%s:%i", name, IntForKey(m_entity,"_frame") ); - - for (epair_t* ep = m_entity->epairs ; ep ; ep=ep->next) - { - if( strncmp(ep->key,"_remap",6) == 0 ) - { - if( !hasRemaps ) - { - hasRemaps = true; - m_cachereq += "?"; - } else { - m_cachereq += "&"; - } - m_cachereq += ep->value; - } - } -} - -void CEntityMiscModel::SetName(const char *name) -{ - Str m_oldcachereq = m_cachereq; - - if( name[0] == '\0' ) { - return; - } - - BuildCacheRequestString(name); - - if(strcmp(m_oldcachereq, m_cachereq) == 0) - return; - - if(m_cachereq.GetBuffer()[0] != ':' - && m_version.c_str()[0] != '\0') - GetModelCache()->DeleteByID(m_cachereq.GetBuffer(), m_version.c_str()); - - m_model = NULL; - - if(name[0] != '\0') - { - const char* dot = strrchr(name, '.'); - if(dot != NULL) - { - m_version = ++dot; - m_model = GetModelCache()->GetByID(m_cachereq.GetBuffer(), m_version.c_str()); - } - } - - UpdateCachedData(); -} - - -void CEntityMiscModel::UpdateCachedData() -{ - aabb_t aabb_temp; - - m4x4_identity(m_transform); - m4x4_pivoted_transform_by_vec3(m_transform, m_translate, m_euler, eXYZ, m_scale, m_pivot); - memcpy(m_inverse_transform, m_transform, sizeof(m4x4_t)); - m4x4_invert(m_inverse_transform); - - aabb_clear(&aabb_temp); - - if(m_model && m_model->pRender) - aabb_extend_by_aabb(&aabb_temp, m_model->pRender->GetAABB()); - else - VectorSet(aabb_temp.extents, 8, 8, 8); - - aabb_for_transformed_aabb(&m_BBox, &aabb_temp, m_transform); -} +/* +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 +*/ + +#include + +#include "entity_entitymodel.h" +#include "entity.h" + +// +// CEntityMiscModel implementation +// + +CEntityMiscModel::CEntityMiscModel (entity_t *e) +{ + refCount = 1; + m_entity = e; + m_model = NULL; + VectorSet(m_translate, 0,0,0); + VectorSet(m_euler, 0,0,0); + VectorSet(m_scale, 1,1,1); + VectorSet(m_pivot, 0,0,0); + m4x4_identity(m_transform); + m4x4_identity(m_inverse_transform); +} + +CEntityMiscModel::~CEntityMiscModel () +{ + if(m_cachereq.GetBuffer()[0] != ':' + && m_version.c_str()[0] != '\0') + GetModelCache()->DeleteByID(m_cachereq.GetBuffer(), m_version.c_str()); +} + + +// IRender + +void CEntityMiscModel::Draw(int state, int rflags) const +{ + // push the current modelview matrix + // FIXME: put in a check for stack recursion depth.. + // or avoid recursion of opengl matrix stack + g_QglTable.m_pfn_qglPushMatrix(); + // apply the parent-to-local transform + g_QglTable.m_pfn_qglMultMatrixf(m_transform); + + pivot_draw(m_pivot); + + // draw children + if(m_model && m_model->pRender) + { + m_model->pRender->Draw(state, rflags); + } + + g_QglTable.m_pfn_qglPopMatrix(); +} + +// ISelect + +bool CEntityMiscModel::TestRay(const ray_t *ray, vec_t *dist) const +{ + vec_t dist_start = *dist; + vec_t dist_local = *dist; + ray_t ray_local = *ray; + + if (aabb_test_ray(&m_BBox, ray) == 0) + return false; + + ray_transform(&ray_local, m_inverse_transform); + + if(m_model && m_model->pSelect) + { + if(m_model->pSelect->TestRay(&ray_local, &dist_local)) + *dist = dist_local; + } + else *dist = dist_local; + + return *dist < dist_start; +} + + +//IEdit + +void CEntityMiscModel::Translate(const vec3_t translation) +{ + VectorIncrement(translation, m_translate); + UpdateCachedData(); +} + +void CEntityMiscModel::Rotate(const vec3_t pivot, const vec3_t rotation) +{ + m4x4_t rotation_matrix; + + m4x4_identity(rotation_matrix); + m4x4_pivoted_rotate_by_vec3(rotation_matrix, rotation, eXYZ, pivot); + m4x4_transform_point(rotation_matrix, m_translate); + + VectorIncrement(rotation, m_euler); + + UpdateCachedData(); +} + +void CEntityMiscModel::OnKeyValueChanged(entity_t *e, const char *key, const char* value) +{ + if(strcmp(key, "model") == 0) + SetName(value); + else if(strcmp(key, "_frame") == 0) + { + SetName(ValueForKey(e, "model")); + } + else if(strcmp(key, "angle") == 0) + { + VectorSet(m_euler, 0.f, 0.f, 0.f); + m_euler[2] = atof(value); + UpdateCachedData(); + } + else if(strcmp(key, "angles") == 0) + { + VectorSet(m_euler, 0.f, 0.f, 0.f); + if (value[0] != '\0') + sscanf (value, "%f %f %f", &m_euler[1], &m_euler[2], &m_euler[0]); + UpdateCachedData(); + } + else if(strcmp(key, "modelscale") == 0 || strcmp(key,"modelscale_vec") == 0) + { + const char *s; + VectorSet(m_scale, 1.f, 1.f, 1.f); + s = ValueForKey(e,"modelscale"); + if (s[0] != '\0') + { + float f = atof(s); + if( f != 0 ) + VectorSet(m_scale, f, f, f); + else + Sys_FPrintf(SYS_WRN, "WARNING: ignoring 0 modelscale key\n"); + } + s = ValueForKey(e,"modelscale_vec"); + if (s[0] != '\0') + { + sscanf (s, "%f %f %f", &m_scale[0], &m_scale[1], &m_scale[2]); + if (m_scale[0] == 0.0 && m_scale[1] == 0.0 && m_scale[2] == 0.0) + { + VectorSet(m_scale, 1,1,1); + Sys_FPrintf(SYS_WRN, "WARNING: ignoring 0 0 0 modelscale_vec key\n"); + } + } + UpdateCachedData(); + } + else if(strcmp(key, "origin") == 0) + { + sscanf(value, "%f %f %f", &m_translate[0], &m_translate[1], &m_translate[2]); + UpdateCachedData(); + } + else if(strncmp(key,"_remap",6) == 0) + { + SetName(ValueForKey(e, "model")); + } +} + +// +// CEntityMiscModel +// + +// private: + +void CEntityMiscModel::BuildCacheRequestString(const char *name) +{ + bool hasRemaps = false; + + m_cachereq.Format( "%s:%i", name, IntForKey(m_entity,"_frame") ); + + for (epair_t* ep = m_entity->epairs ; ep ; ep=ep->next) + { + if( strncmp(ep->key,"_remap",6) == 0 ) + { + if( !hasRemaps ) + { + hasRemaps = true; + m_cachereq += "?"; + } else { + m_cachereq += "&"; + } + m_cachereq += ep->value; + } + } +} + +void CEntityMiscModel::SetName(const char *name) +{ + Str m_oldcachereq = m_cachereq; + + if( name[0] == '\0' ) { + return; + } + + BuildCacheRequestString(name); + + if(strcmp(m_oldcachereq, m_cachereq) == 0) + return; + + if(m_cachereq.GetBuffer()[0] != ':' + && m_version.c_str()[0] != '\0') + GetModelCache()->DeleteByID(m_cachereq.GetBuffer(), m_version.c_str()); + + m_model = NULL; + + if(name[0] != '\0') + { + const char* dot = strrchr(name, '.'); + if(dot != NULL) + { + m_version = ++dot; + m_model = GetModelCache()->GetByID(m_cachereq.GetBuffer(), m_version.c_str()); + } + } + + UpdateCachedData(); +} + + +void CEntityMiscModel::UpdateCachedData() +{ + aabb_t aabb_temp; + + m4x4_identity(m_transform); + m4x4_pivoted_transform_by_vec3(m_transform, m_translate, m_euler, eXYZ, m_scale, m_pivot); + memcpy(m_inverse_transform, m_transform, sizeof(m4x4_t)); + m4x4_invert(m_inverse_transform); + + aabb_clear(&aabb_temp); + + if(m_model && m_model->pRender) + aabb_extend_by_aabb(&aabb_temp, m_model->pRender->GetAABB()); + else + VectorSet(aabb_temp.extents, 8, 8, 8); + + aabb_for_transformed_aabb(&m_BBox, &aabb_temp, m_transform); +} diff --git a/plugins/entity/plugin.cpp b/plugins/entity/plugin.cpp index 5ff1c8a2..ede5b91c 100644 --- a/plugins/entity/plugin.cpp +++ b/plugins/entity/plugin.cpp @@ -1,121 +1,121 @@ -/* -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 -*/ - -// -// Model Plugin -// - -#include "plugin.h" -#include "entity.h" -#include "entity_entitymodel.h" -#include "light.h" - -// ============================================================================= -// Globals - -// function tables -_QERFuncTable_1 g_FuncTable; -_QERQglTable g_QglTable; -_QERBrushTable __BRUSHTABLENAME; -_QERUndoTable __UNDOTABLENAME; -_EClassManagerTable __ECLASSMANAGERTABLENAME; - -// ============================================================================= -// SYNAPSE - -class CSynapseClientEntity : public CSynapseClient -{ -public: - // CSynapseClient API - bool RequestAPI(APIDescriptor_t *pAPI); - const char* GetInfo(); - - CSynapseClientEntity() { } - virtual ~CSynapseClientEntity() { } -}; - - -CSynapseServer* g_pSynapseServer = NULL; -CSynapseClientEntity 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(ENTITY_MAJOR, NULL, sizeof(_QEREntityTable)); - 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); - g_SynapseClient.AddAPI(BRUSH_MAJOR, NULL, sizeof(__BRUSHTABLENAME), SYN_REQUIRE, &__BRUSHTABLENAME); - g_SynapseClient.AddAPI(UNDO_MAJOR, NULL, sizeof(__UNDOTABLENAME), SYN_REQUIRE, &__UNDOTABLENAME); - g_SynapseClient.AddAPI(ECLASSMANAGER_MAJOR, NULL, sizeof(__ECLASSMANAGERTABLENAME), SYN_REQUIRE, &__ECLASSMANAGERTABLENAME); - - return &g_SynapseClient; -} - -bool CSynapseClientEntity::RequestAPI(APIDescriptor_t *pAPI) -{ - if (!strcmp(pAPI->major_name, ENTITY_MAJOR)) - { - _QEREntityTable* pTable= static_cast<_QEREntityTable*>(pAPI->mpTable); - pTable->m_pfnEntity_Alloc = &Entity_Alloc; - pTable->m_pfnEntity_Free = &Entity_Free; - pTable->m_pfnEntity_Clone = &Entity_Clone; - pTable->m_pfnSetKeyValue = &SetKeyValue; - pTable->m_pfnDeleteKey = &DeleteKey; - pTable->m_pfnValueForKey = &ValueForKey; - pTable->m_pfnFloatForKey = &FloatForKey; - pTable->m_pfnIntForKey = &IntForKey; - pTable->m_pfnGetVectorForKey = &GetVectorForKey; - pTable->m_pfnEntity_AddToList = &Entity_AddToList; - pTable->m_pfnEntity_RemoveFromList = &Entity_RemoveFromList; - pTable->m_pfnEntity_LinkBrush = &Entity_LinkBrush; - pTable->m_pfnEntity_UnlinkBrush = &Entity_UnlinkBrush; - pTable->m_pfnDrawLight = &DrawLight; - pTable->m_pfnEntity_MemorySize = &Entity_MemorySize; - pTable->m_pfnAllocateEpair = &Entity_AllocateEpair; - pTable->m_pfnGetEntityKeyValList = &Entity_GetKeyValList; - pTable->m_pfnSetEntityKeyValList = &Entity_SetKeyValList; - - return true; - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -#include "version.h" - -const char* CSynapseClientEntity::GetInfo() -{ - return "Entity module built " __DATE__ " " RADIANT_VERSION; -} +/* +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 +*/ + +// +// Model Plugin +// + +#include "plugin.h" +#include "entity.h" +#include "entity_entitymodel.h" +#include "light.h" + +// ============================================================================= +// Globals + +// function tables +_QERFuncTable_1 g_FuncTable; +_QERQglTable g_QglTable; +_QERBrushTable __BRUSHTABLENAME; +_QERUndoTable __UNDOTABLENAME; +_EClassManagerTable __ECLASSMANAGERTABLENAME; + +// ============================================================================= +// SYNAPSE + +class CSynapseClientEntity : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + + CSynapseClientEntity() { } + virtual ~CSynapseClientEntity() { } +}; + + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientEntity 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(ENTITY_MAJOR, NULL, sizeof(_QEREntityTable)); + 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); + g_SynapseClient.AddAPI(BRUSH_MAJOR, NULL, sizeof(__BRUSHTABLENAME), SYN_REQUIRE, &__BRUSHTABLENAME); + g_SynapseClient.AddAPI(UNDO_MAJOR, NULL, sizeof(__UNDOTABLENAME), SYN_REQUIRE, &__UNDOTABLENAME); + g_SynapseClient.AddAPI(ECLASSMANAGER_MAJOR, NULL, sizeof(__ECLASSMANAGERTABLENAME), SYN_REQUIRE, &__ECLASSMANAGERTABLENAME); + + return &g_SynapseClient; +} + +bool CSynapseClientEntity::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, ENTITY_MAJOR)) + { + _QEREntityTable* pTable= static_cast<_QEREntityTable*>(pAPI->mpTable); + pTable->m_pfnEntity_Alloc = &Entity_Alloc; + pTable->m_pfnEntity_Free = &Entity_Free; + pTable->m_pfnEntity_Clone = &Entity_Clone; + pTable->m_pfnSetKeyValue = &SetKeyValue; + pTable->m_pfnDeleteKey = &DeleteKey; + pTable->m_pfnValueForKey = &ValueForKey; + pTable->m_pfnFloatForKey = &FloatForKey; + pTable->m_pfnIntForKey = &IntForKey; + pTable->m_pfnGetVectorForKey = &GetVectorForKey; + pTable->m_pfnEntity_AddToList = &Entity_AddToList; + pTable->m_pfnEntity_RemoveFromList = &Entity_RemoveFromList; + pTable->m_pfnEntity_LinkBrush = &Entity_LinkBrush; + pTable->m_pfnEntity_UnlinkBrush = &Entity_UnlinkBrush; + pTable->m_pfnDrawLight = &DrawLight; + pTable->m_pfnEntity_MemorySize = &Entity_MemorySize; + pTable->m_pfnAllocateEpair = &Entity_AllocateEpair; + pTable->m_pfnGetEntityKeyValList = &Entity_GetKeyValList; + pTable->m_pfnSetEntityKeyValList = &Entity_SetKeyValList; + + return true; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientEntity::GetInfo() +{ + return "Entity module built " __DATE__ " " RADIANT_VERSION; +} diff --git a/plugins/image/bmp.cpp b/plugins/image/bmp.cpp index 24f05dda..223f4e07 100644 --- a/plugins/image/bmp.cpp +++ b/plugins/image/bmp.cpp @@ -1,402 +1,402 @@ -/* -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 -*/ - -#include -#include -#include -#include "bmp.h" - -#include "image.h" - -static void BMPLineNone(FILE *f, char *sline, int pixbytes, int width) -{ - int nbytes, i, k, j; - - switch (pixbytes) - { - case 1 : - nbytes = (width + 3) / 4; - nbytes *= 4; - - fread(sline, width, 1, f); - nbytes -= width; - - while (nbytes-- > 0) fgetc(f); - return; - - case 3 : - nbytes = ((width * 3) + 3) / 4; - nbytes *= 4; - - fread(sline, width, 3, f); - nbytes -= width * 3; - - while (nbytes-- > 0) fgetc(f); - - // reorder bgr to rgb - for (i = 0, j = 0; i < width; i++, j += 3) - { - k = sline[j]; - sline[j] = sline[j+2]; - sline[j+2] = k; - } - - return; - } - - Error("BMPLineNone failed."); -} - - -static void BMPLineRLE8(FILE *f, char *sline, int pixbytes, int width) -{ - Error("RLE8 not yet supported."); -} - - -static void BMPLineRLE4(FILE *f, char *sline, int pixbytes, int width) -{ - Error("RLE4 not yet supported."); -} - - -static void BMPLine(FILE *f, char *scanline, int pixbytes, int width, int rle) -{ - switch (rle) - { - case xBI_NONE : BMPLineNone(f, scanline, pixbytes, width); return; - case xBI_RLE8 : BMPLineRLE8(f, scanline, pixbytes, width); return; - case xBI_RLE4 : BMPLineRLE4(f, scanline, pixbytes, width); return; - } - - Error("Unknown compression type."); -} - - -/* -static void PrintHeader(binfo_t *b) -{ - printf("biSize : %ld\n", b->biSize); - printf("biWidth : %ld\n", b->biWidth); - printf("biHeight : %ld\n", b->biHeight); - printf("biPlanes : %d\n", b->biPlanes); - printf("biBitCount : %d\n", b->biBitCount); - printf("biCompression : %ld\n", b->biCompression); - printf("biSizeImage : %ld\n", b->biSizeImage); - printf("biXPelsPerMeter: %ld\n", b->biXPelsPerMeter); - printf("biYPelsPerMeter: %ld\n", b->biYPelsPerMeter); - printf("biClrUsed : %ld\n", b->biClrUsed); - printf("biClrImportant : %ld\n", b->biClrImportant); -} -*/ - -// FIXME: calls to Error(const char *, ... ) are dependant on qe3.cpp -void LoadBMP(char *filename, bitmap_t *bit) -{ - FILE *f; - bmphd_t bhd; - binfo_t info; - // int pxlsize = 1; - int rowbytes, i, pixbytes; - char *scanline; - - // open file - if ((f = fopen(filename, "rb")) == NULL) - { - Error("Unable to open file");// %s.", filename); - } - - // read in bitmap header - if (fread(&bhd, sizeof(bhd), 1, f) != 1) - { - fclose(f); - Error("Unable to read in bitmap header."); - } - - // make sure we have a valid bitmap file - if (bhd.bfType != BMP_SIGNATURE_WORD) - { - fclose(f); - Error("Invalid BMP file");//: %s", filename); - } - - // load in info header - if (fread(&info, sizeof(info), 1, f) != 1) - { - fclose(f); - Error("Unable to read bitmap info header."); - } - - // make sure this is an info type of bitmap - if (info.biSize != sizeof(binfo_t)) - { - fclose(f); - Error("We only support the info bitmap type."); - } - - // PrintHeader(&info); - - bit->bpp = info.biBitCount; - bit->width = info.biWidth; - bit->height = info.biHeight; - bit->data = NULL; - bit->palette = NULL; - - //currently we only read in 8 and 24 bit bmp files - if (info.biBitCount == 8) pixbytes = 1; - else if (info.biBitCount == 24) pixbytes = 3; - else - { - Error("Only 8BPP and 24BPP supported"); - //Error("BPP %d not supported.", info.biBitCount); - } - - // if this is an eight bit image load palette - if (pixbytes == 1) - { - drgb_t q; - - bit->palette = reinterpret_cast(g_malloc(sizeof(rgb_t) * 256)); - - for (i = 0; i < 256; i++) - { - if (fread(&q, sizeof(drgb_t), 1, f) != 1) - { - fclose(f); g_free(bit->palette); - Error("Unable to read palette."); - } - - bit->palette[i].r = q.red; - bit->palette[i].g = q.green; - bit->palette[i].b = q.blue; - } - } - - // position to start of bitmap - fseek(f, bhd.bfOffBits, SEEK_SET); - - // create scanline to read data into - rowbytes = ((info.biWidth * pixbytes) + 3) / 4; - rowbytes *= 4; - - scanline = reinterpret_cast(g_malloc(rowbytes)); - - // alloc space for new bitmap - bit->data = reinterpret_cast(g_malloc(info.biWidth * pixbytes * info.biHeight)); - - // read in image - for (i = 0; i < info.biHeight; i++) - { - BMPLine(f, scanline, pixbytes, info.biWidth, info.biCompression); - - // store line - memcpy(&bit->data[info.biWidth * pixbytes * (info.biHeight - i - 1)], scanline, info.biWidth * pixbytes); - } - - g_free(scanline); - fclose(f); -} - - - -static void BMPEncodeLine(FILE *f, unsigned char *data, int npxls, int pixbytes) -{ - int nbytes, i, j, k; - - switch (pixbytes) - { - case 1 : - nbytes = (npxls + 3) / 4; - nbytes *= 4; - - fwrite(data, npxls, 1, f); - nbytes -= npxls; - - while (nbytes-- > 0) fputc(0, f); - return; - - case 3 : - // reorder rgb to bgr - for (i = 0, j = 0; i < npxls; i++, j+= 3) - { - k = data[j]; - data[j] = data[j + 2]; - data[j + 2] = k; - } - - nbytes = ((npxls * 3) + 3) / 4; - nbytes *= 4; - - fwrite(data, npxls, 3, f); - nbytes -= npxls * 3; - - while (nbytes-- > 0) fputc(0, f); - return; - } - - Error("BMPEncodeLine Failed."); -} - - - -void WriteBMP(char *filename, bitmap_t *bit) -{ - FILE *f; - bmphd_t header; - binfo_t info; - drgb_t q; // palette that gets written - long bmofs; - int w, h, i; - int pixbytes; - - if (bit->bpp == 8) pixbytes = 1; - else if (bit->bpp == 24) pixbytes = 3; - - else - { - Error("Only 8BPP and 24BPP supported"); - //Error("BPP %d not supported.", bit->bpp); - } - - - if ((f = fopen(filename, "wb")) == NULL) - { - Error("Unable to open file");//%s.", filename); - } - - // write out an empty header as a place holder - if (fwrite(&header, sizeof(header), 1, f) != 1) - { - Error("Unable to fwrite."); - } - - // init and write info header - info.biSize = sizeof(binfo_t); - info.biWidth = bit->width; - info.biHeight = bit->height; - info.biPlanes = 1; - info.biBitCount = bit->bpp; - info.biCompression = xBI_NONE; - info.biSizeImage = bit->width * bit->height; - info.biXPelsPerMeter = 0; - info.biYPelsPerMeter = 0; - info.biClrUsed = 256; - info.biClrImportant = 256; - - if (fwrite(&info, sizeof(binfo_t), 1, f) != 1) - { - Error("fwrite failed."); - } - - // write out palette if we need to - if (bit->bpp == 8) - { - for (i = 0; i < 256; i++) - { - q.red = bit->palette[i].r; - q.green = bit->palette[i].g; - q.blue = bit->palette[i].b; - - fwrite(&q, sizeof(q), 1, f); - } - } - - // save offset to start of bitmap - bmofs = ftell(f); - - // output bitmap - w = bit->width; - h = bit->height; - - for (i = h - 1; i >= 0; i--) - { - BMPEncodeLine(f, &bit->data[w * pixbytes * i], w, pixbytes); - } - - // update and rewrite file header - header.bfType = BMP_SIGNATURE_WORD; - header.bfSize = ftell(f); - header.bfOffBits = bmofs; - - fseek(f, 0L, SEEK_SET); - fwrite(&header, sizeof(header), 1, f); - - fclose(f); -} - - -void NewBMP(int width, int height, int bpp, bitmap_t *bit) -{ - int pixbytes; - - if (bpp == 8) pixbytes = 1; - else if (bpp == 24) pixbytes = 3; - - else - { - Error("NewBMP: 8 or 24 bit only."); - } - - bit->bpp = bpp; - bit->width = width; - bit->height = height; - - bit->data = reinterpret_cast(g_malloc(width * height * pixbytes)); - - if (bit->data == NULL) - { - Error("NewBMP: g_malloc failed."); - } - - // see if we need to create a palette - if (pixbytes == 1) - { - bit->palette = (rgb_t *) g_malloc(768); - - if (bit->palette == NULL) - { - Error("NewBMP: unable to g_malloc palette."); - } - } - else - { - bit->palette = NULL; - } -} - - - -void FreeBMP(bitmap_t *bitmap) -{ - if (bitmap->palette) - { - g_free(bitmap->palette); - bitmap->palette = NULL; - } - - if (bitmap->data) - { - g_free(bitmap->data); - bitmap->data = NULL; - } -} - - +/* +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 +*/ + +#include +#include +#include +#include "bmp.h" + +#include "image.h" + +static void BMPLineNone(FILE *f, char *sline, int pixbytes, int width) +{ + int nbytes, i, k, j; + + switch (pixbytes) + { + case 1 : + nbytes = (width + 3) / 4; + nbytes *= 4; + + fread(sline, width, 1, f); + nbytes -= width; + + while (nbytes-- > 0) fgetc(f); + return; + + case 3 : + nbytes = ((width * 3) + 3) / 4; + nbytes *= 4; + + fread(sline, width, 3, f); + nbytes -= width * 3; + + while (nbytes-- > 0) fgetc(f); + + // reorder bgr to rgb + for (i = 0, j = 0; i < width; i++, j += 3) + { + k = sline[j]; + sline[j] = sline[j+2]; + sline[j+2] = k; + } + + return; + } + + Error("BMPLineNone failed."); +} + + +static void BMPLineRLE8(FILE *f, char *sline, int pixbytes, int width) +{ + Error("RLE8 not yet supported."); +} + + +static void BMPLineRLE4(FILE *f, char *sline, int pixbytes, int width) +{ + Error("RLE4 not yet supported."); +} + + +static void BMPLine(FILE *f, char *scanline, int pixbytes, int width, int rle) +{ + switch (rle) + { + case xBI_NONE : BMPLineNone(f, scanline, pixbytes, width); return; + case xBI_RLE8 : BMPLineRLE8(f, scanline, pixbytes, width); return; + case xBI_RLE4 : BMPLineRLE4(f, scanline, pixbytes, width); return; + } + + Error("Unknown compression type."); +} + + +/* +static void PrintHeader(binfo_t *b) +{ + printf("biSize : %ld\n", b->biSize); + printf("biWidth : %ld\n", b->biWidth); + printf("biHeight : %ld\n", b->biHeight); + printf("biPlanes : %d\n", b->biPlanes); + printf("biBitCount : %d\n", b->biBitCount); + printf("biCompression : %ld\n", b->biCompression); + printf("biSizeImage : %ld\n", b->biSizeImage); + printf("biXPelsPerMeter: %ld\n", b->biXPelsPerMeter); + printf("biYPelsPerMeter: %ld\n", b->biYPelsPerMeter); + printf("biClrUsed : %ld\n", b->biClrUsed); + printf("biClrImportant : %ld\n", b->biClrImportant); +} +*/ + +// FIXME: calls to Error(const char *, ... ) are dependant on qe3.cpp +void LoadBMP(char *filename, bitmap_t *bit) +{ + FILE *f; + bmphd_t bhd; + binfo_t info; + // int pxlsize = 1; + int rowbytes, i, pixbytes; + char *scanline; + + // open file + if ((f = fopen(filename, "rb")) == NULL) + { + Error("Unable to open file");// %s.", filename); + } + + // read in bitmap header + if (fread(&bhd, sizeof(bhd), 1, f) != 1) + { + fclose(f); + Error("Unable to read in bitmap header."); + } + + // make sure we have a valid bitmap file + if (bhd.bfType != BMP_SIGNATURE_WORD) + { + fclose(f); + Error("Invalid BMP file");//: %s", filename); + } + + // load in info header + if (fread(&info, sizeof(info), 1, f) != 1) + { + fclose(f); + Error("Unable to read bitmap info header."); + } + + // make sure this is an info type of bitmap + if (info.biSize != sizeof(binfo_t)) + { + fclose(f); + Error("We only support the info bitmap type."); + } + + // PrintHeader(&info); + + bit->bpp = info.biBitCount; + bit->width = info.biWidth; + bit->height = info.biHeight; + bit->data = NULL; + bit->palette = NULL; + + //currently we only read in 8 and 24 bit bmp files + if (info.biBitCount == 8) pixbytes = 1; + else if (info.biBitCount == 24) pixbytes = 3; + else + { + Error("Only 8BPP and 24BPP supported"); + //Error("BPP %d not supported.", info.biBitCount); + } + + // if this is an eight bit image load palette + if (pixbytes == 1) + { + drgb_t q; + + bit->palette = reinterpret_cast(g_malloc(sizeof(rgb_t) * 256)); + + for (i = 0; i < 256; i++) + { + if (fread(&q, sizeof(drgb_t), 1, f) != 1) + { + fclose(f); g_free(bit->palette); + Error("Unable to read palette."); + } + + bit->palette[i].r = q.red; + bit->palette[i].g = q.green; + bit->palette[i].b = q.blue; + } + } + + // position to start of bitmap + fseek(f, bhd.bfOffBits, SEEK_SET); + + // create scanline to read data into + rowbytes = ((info.biWidth * pixbytes) + 3) / 4; + rowbytes *= 4; + + scanline = reinterpret_cast(g_malloc(rowbytes)); + + // alloc space for new bitmap + bit->data = reinterpret_cast(g_malloc(info.biWidth * pixbytes * info.biHeight)); + + // read in image + for (i = 0; i < info.biHeight; i++) + { + BMPLine(f, scanline, pixbytes, info.biWidth, info.biCompression); + + // store line + memcpy(&bit->data[info.biWidth * pixbytes * (info.biHeight - i - 1)], scanline, info.biWidth * pixbytes); + } + + g_free(scanline); + fclose(f); +} + + + +static void BMPEncodeLine(FILE *f, unsigned char *data, int npxls, int pixbytes) +{ + int nbytes, i, j, k; + + switch (pixbytes) + { + case 1 : + nbytes = (npxls + 3) / 4; + nbytes *= 4; + + fwrite(data, npxls, 1, f); + nbytes -= npxls; + + while (nbytes-- > 0) fputc(0, f); + return; + + case 3 : + // reorder rgb to bgr + for (i = 0, j = 0; i < npxls; i++, j+= 3) + { + k = data[j]; + data[j] = data[j + 2]; + data[j + 2] = k; + } + + nbytes = ((npxls * 3) + 3) / 4; + nbytes *= 4; + + fwrite(data, npxls, 3, f); + nbytes -= npxls * 3; + + while (nbytes-- > 0) fputc(0, f); + return; + } + + Error("BMPEncodeLine Failed."); +} + + + +void WriteBMP(char *filename, bitmap_t *bit) +{ + FILE *f; + bmphd_t header; + binfo_t info; + drgb_t q; // palette that gets written + long bmofs; + int w, h, i; + int pixbytes; + + if (bit->bpp == 8) pixbytes = 1; + else if (bit->bpp == 24) pixbytes = 3; + + else + { + Error("Only 8BPP and 24BPP supported"); + //Error("BPP %d not supported.", bit->bpp); + } + + + if ((f = fopen(filename, "wb")) == NULL) + { + Error("Unable to open file");//%s.", filename); + } + + // write out an empty header as a place holder + if (fwrite(&header, sizeof(header), 1, f) != 1) + { + Error("Unable to fwrite."); + } + + // init and write info header + info.biSize = sizeof(binfo_t); + info.biWidth = bit->width; + info.biHeight = bit->height; + info.biPlanes = 1; + info.biBitCount = bit->bpp; + info.biCompression = xBI_NONE; + info.biSizeImage = bit->width * bit->height; + info.biXPelsPerMeter = 0; + info.biYPelsPerMeter = 0; + info.biClrUsed = 256; + info.biClrImportant = 256; + + if (fwrite(&info, sizeof(binfo_t), 1, f) != 1) + { + Error("fwrite failed."); + } + + // write out palette if we need to + if (bit->bpp == 8) + { + for (i = 0; i < 256; i++) + { + q.red = bit->palette[i].r; + q.green = bit->palette[i].g; + q.blue = bit->palette[i].b; + + fwrite(&q, sizeof(q), 1, f); + } + } + + // save offset to start of bitmap + bmofs = ftell(f); + + // output bitmap + w = bit->width; + h = bit->height; + + for (i = h - 1; i >= 0; i--) + { + BMPEncodeLine(f, &bit->data[w * pixbytes * i], w, pixbytes); + } + + // update and rewrite file header + header.bfType = BMP_SIGNATURE_WORD; + header.bfSize = ftell(f); + header.bfOffBits = bmofs; + + fseek(f, 0L, SEEK_SET); + fwrite(&header, sizeof(header), 1, f); + + fclose(f); +} + + +void NewBMP(int width, int height, int bpp, bitmap_t *bit) +{ + int pixbytes; + + if (bpp == 8) pixbytes = 1; + else if (bpp == 24) pixbytes = 3; + + else + { + Error("NewBMP: 8 or 24 bit only."); + } + + bit->bpp = bpp; + bit->width = width; + bit->height = height; + + bit->data = reinterpret_cast(g_malloc(width * height * pixbytes)); + + if (bit->data == NULL) + { + Error("NewBMP: g_malloc failed."); + } + + // see if we need to create a palette + if (pixbytes == 1) + { + bit->palette = (rgb_t *) g_malloc(768); + + if (bit->palette == NULL) + { + Error("NewBMP: unable to g_malloc palette."); + } + } + else + { + bit->palette = NULL; + } +} + + + +void FreeBMP(bitmap_t *bitmap) +{ + if (bitmap->palette) + { + g_free(bitmap->palette); + bitmap->palette = NULL; + } + + if (bitmap->data) + { + g_free(bitmap->data); + bitmap->data = NULL; + } +} + + diff --git a/plugins/image/image.cpp b/plugins/image/image.cpp index 418d60b5..34dd6709 100644 --- a/plugins/image/image.cpp +++ b/plugins/image/image.cpp @@ -1,133 +1,133 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -// -// Image loading plugin -// -// Leonardo Zide (leo@lokigames.com) -// - -#include -#include "image.h" -#include "lbmlib.h" - -// ============================================================================= -// global tables - -_QERFuncTable_1 g_FuncTable; // Radiant function table -_QERFileSystemTable g_FileSystemTable; - -// ============================================================================= -// SYNAPSE - -CSynapseServer* g_pSynapseServer = NULL; -CSynapseClientImage g_SynapseClient; - -static const XMLConfigEntry_t entries[] = - { - { VFS_MAJOR, SYN_REQUIRE, sizeof(g_FileSystemTable), &g_FileSystemTable }, - { NULL, SYN_UNKNOWN, 0, NULL } }; - -#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(IMAGE_MAJOR, "jpg", sizeof(_QERPlugImageTable)); - g_SynapseClient.AddAPI(IMAGE_MAJOR, "tga", sizeof(_QERPlugImageTable)); - // NOTE: these two are for md2 support - // instead of requesting them systematically, we could request them per-config before enabling Q2 support - g_SynapseClient.AddAPI(IMAGE_MAJOR, "pcx", sizeof(_QERPlugImageTable)); - g_SynapseClient.AddAPI(IMAGE_MAJOR, "bmp", sizeof(_QERPlugImageTable)); - g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); - - if ( !g_SynapseClient.ConfigXML( pServer, NULL, entries ) ) { - return NULL; - } - - return &g_SynapseClient; -} - -bool CSynapseClientImage::RequestAPI(APIDescriptor_t *pAPI) -{ - if (!strcmp(pAPI->major_name, "image")) - { - _QERPlugImageTable* pTable= static_cast<_QERPlugImageTable*>(pAPI->mpTable); - if (!strcmp(pAPI->minor_name, "jpg")) - { - pTable->m_pfnLoadImage = &LoadJPG; - return true; - } - if (!strcmp(pAPI->minor_name, "tga")) - { - pTable->m_pfnLoadImage = &LoadImage; - return true; - } - if (!strcmp(pAPI->minor_name, "pcx")) - { - pTable->m_pfnLoadImage = &LoadImage; - return true; - } - if (!strcmp(pAPI->minor_name, "bmp")) - { - pTable->m_pfnLoadImage = &LoadImage; - return true; - } - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -bool CSynapseClientImage::OnActivate() { - if (!g_FileSystemTable.m_nSize) { - Syn_Printf("ERROR: VFS_MAJOR table was not initialized before OnActivate in '%s' - incomplete synapse.config?\n", GetInfo()); - return false; - } - return true; -} - -#include "version.h" - -const char* CSynapseClientImage::GetInfo() -{ - return "image formats JPG TGA PCX BMP module built " __DATE__ " " RADIANT_VERSION; -} +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// +// Image loading plugin +// +// Leonardo Zide (leo@lokigames.com) +// + +#include +#include "image.h" +#include "lbmlib.h" + +// ============================================================================= +// global tables + +_QERFuncTable_1 g_FuncTable; // Radiant function table +_QERFileSystemTable g_FileSystemTable; + +// ============================================================================= +// SYNAPSE + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientImage g_SynapseClient; + +static const XMLConfigEntry_t entries[] = + { + { VFS_MAJOR, SYN_REQUIRE, sizeof(g_FileSystemTable), &g_FileSystemTable }, + { NULL, SYN_UNKNOWN, 0, NULL } }; + +#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(IMAGE_MAJOR, "jpg", sizeof(_QERPlugImageTable)); + g_SynapseClient.AddAPI(IMAGE_MAJOR, "tga", sizeof(_QERPlugImageTable)); + // NOTE: these two are for md2 support + // instead of requesting them systematically, we could request them per-config before enabling Q2 support + g_SynapseClient.AddAPI(IMAGE_MAJOR, "pcx", sizeof(_QERPlugImageTable)); + g_SynapseClient.AddAPI(IMAGE_MAJOR, "bmp", sizeof(_QERPlugImageTable)); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + + if ( !g_SynapseClient.ConfigXML( pServer, NULL, entries ) ) { + return NULL; + } + + return &g_SynapseClient; +} + +bool CSynapseClientImage::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, "image")) + { + _QERPlugImageTable* pTable= static_cast<_QERPlugImageTable*>(pAPI->mpTable); + if (!strcmp(pAPI->minor_name, "jpg")) + { + pTable->m_pfnLoadImage = &LoadJPG; + return true; + } + if (!strcmp(pAPI->minor_name, "tga")) + { + pTable->m_pfnLoadImage = &LoadImage; + return true; + } + if (!strcmp(pAPI->minor_name, "pcx")) + { + pTable->m_pfnLoadImage = &LoadImage; + return true; + } + if (!strcmp(pAPI->minor_name, "bmp")) + { + pTable->m_pfnLoadImage = &LoadImage; + return true; + } + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +bool CSynapseClientImage::OnActivate() { + if (!g_FileSystemTable.m_nSize) { + Syn_Printf("ERROR: VFS_MAJOR table was not initialized before OnActivate in '%s' - incomplete synapse.config?\n", GetInfo()); + return false; + } + return true; +} + +#include "version.h" + +const char* CSynapseClientImage::GetInfo() +{ + return "image formats JPG TGA PCX BMP module built " __DATE__ " " RADIANT_VERSION; +} diff --git a/plugins/image/jpeg.cpp b/plugins/image/jpeg.cpp index e2e2ba79..db3d12c4 100644 --- a/plugins/image/jpeg.cpp +++ b/plugins/image/jpeg.cpp @@ -1,415 +1,415 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -// -// Functions to load JPEG files from a buffer, based on jdatasrc.c -// -// Leonardo Zide (leo@lokigames.com) -// - -#include -#include -#include -#include -#include - -#include -#include - /* -extern "C" { -#include "radiant_jpeglib.h" -#include "jpeg6/jerror.h" -} - */ - -#include "image.h" - -/* Expanded data source object for stdio input */ - -typedef struct { - struct jpeg_source_mgr pub; /* public fields */ - - int src_size; - JOCTET * src_buffer; - - JOCTET * buffer; /* start of buffer */ - boolean start_of_file; /* have we gotten any data yet? */ -} my_source_mgr; - -typedef my_source_mgr * my_src_ptr; - -#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ - - -/* - * Initialize source --- called by jpeg_read_header - * before any data is actually read. - */ - -static void my_init_source (j_decompress_ptr cinfo) -{ - my_src_ptr src = (my_src_ptr) cinfo->src; - - /* We reset the empty-input-file flag for each image, - * but we don't clear the input buffer. - * This is correct behavior for reading a series of images from one source. - */ - src->start_of_file = TRUE; -} - - -/* - * Fill the input buffer --- called whenever buffer is emptied. - * - * In typical applications, this should read fresh data into the buffer - * (ignoring the current state of next_input_byte & bytes_in_buffer), - * reset the pointer & count to the start of the buffer, and return TRUE - * indicating that the buffer has been reloaded. It is not necessary to - * fill the buffer entirely, only to obtain at least one more byte. - * - * There is no such thing as an EOF return. If the end of the file has been - * reached, the routine has a choice of ERREXIT() or inserting fake data into - * the buffer. In most cases, generating a warning message and inserting a - * fake EOI marker is the best course of action --- this will allow the - * decompressor to output however much of the image is there. However, - * the resulting error message is misleading if the real problem is an empty - * input file, so we handle that case specially. - * - * In applications that need to be able to suspend compression due to input - * not being available yet, a FALSE return indicates that no more data can be - * obtained right now, but more may be forthcoming later. In this situation, - * the decompressor will return to its caller (with an indication of the - * number of scanlines it has read, if any). The application should resume - * decompression after it has loaded more data into the input buffer. Note - * that there are substantial restrictions on the use of suspension --- see - * the documentation. - * - * When suspending, the decompressor will back up to a convenient restart point - * (typically the start of the current MCU). next_input_byte & bytes_in_buffer - * indicate where the restart point will be if the current call returns FALSE. - * Data beyond this point must be rescanned after resumption, so move it to - * the front of the buffer rather than discarding it. - */ - -static boolean my_fill_input_buffer (j_decompress_ptr cinfo) -{ - my_src_ptr src = (my_src_ptr) cinfo->src; - size_t nbytes; - - if (src->src_size > INPUT_BUF_SIZE) - nbytes = INPUT_BUF_SIZE; - else - nbytes = src->src_size; - - memcpy (src->buffer, src->src_buffer, nbytes); - src->src_buffer += nbytes; - src->src_size -= nbytes; - - if (nbytes <= 0) { - if (src->start_of_file) /* Treat empty input file as fatal error */ - ERREXIT(cinfo, JERR_INPUT_EMPTY); - WARNMS(cinfo, JWRN_JPEG_EOF); - /* Insert a fake EOI marker */ - src->buffer[0] = (JOCTET) 0xFF; - src->buffer[1] = (JOCTET) JPEG_EOI; - nbytes = 2; - } - - src->pub.next_input_byte = src->buffer; - src->pub.bytes_in_buffer = nbytes; - src->start_of_file = FALSE; - - return TRUE; -} - - -/* - * Skip data --- used to skip over a potentially large amount of - * uninteresting data (such as an APPn marker). - * - * Writers of suspendable-input applications must note that skip_input_data - * is not granted the right to give a suspension return. If the skip extends - * beyond the data currently in the buffer, the buffer can be marked empty so - * that the next read will cause a fill_input_buffer call that can suspend. - * Arranging for additional bytes to be discarded before reloading the input - * buffer is the application writer's problem. - */ - -static void my_skip_input_data (j_decompress_ptr cinfo, long num_bytes) -{ - my_src_ptr src = (my_src_ptr) cinfo->src; - - /* Just a dumb implementation for now. Could use fseek() except - * it doesn't work on pipes. Not clear that being smart is worth - * any trouble anyway --- large skips are infrequent. - */ - if (num_bytes > 0) { - while (num_bytes > (long) src->pub.bytes_in_buffer) { - num_bytes -= (long) src->pub.bytes_in_buffer; - (void) my_fill_input_buffer(cinfo); - /* note we assume that fill_input_buffer will never return FALSE, - * so suspension need not be handled. - */ - } - src->pub.next_input_byte += (size_t) num_bytes; - src->pub.bytes_in_buffer -= (size_t) num_bytes; - } -} - - -/* - * An additional method that can be provided by data source modules is the - * resync_to_restart method for error recovery in the presence of RST markers. - * For the moment, this source module just uses the default resync method - * provided by the JPEG library. That method assumes that no backtracking - * is possible. - */ - - -/* - * Terminate source --- called by jpeg_finish_decompress - * after all data has been read. Often a no-op. - * - * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding - * application must deal with any cleanup that should happen even - * for error exit. - */ - -static void my_term_source (j_decompress_ptr cinfo) -{ - /* no work necessary here */ -} - - -/* - * Prepare for input from a stdio stream. - * The caller must have already opened the stream, and is responsible - * for closing it after finishing decompression. - */ - -static void jpeg_buffer_src (j_decompress_ptr cinfo, void* buffer, int bufsize) -{ - my_src_ptr src; - - /* The source object and input buffer are made permanent so that a series - * of JPEG images can be read from the same file by calling jpeg_stdio_src - * only before the first one. (If we discarded the buffer at the end of - * one image, we'd likely lose the start of the next one.) - * This makes it unsafe to use this manager and a different source - * manager serially with the same JPEG object. Caveat programmer. - */ - if (cinfo->src == NULL) { /* first time for this JPEG object? */ - cinfo->src = (struct jpeg_source_mgr *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - sizeof (my_source_mgr)); - src = (my_src_ptr) cinfo->src; - src->buffer = (JOCTET *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - INPUT_BUF_SIZE * sizeof (JOCTET)); - } - - src = (my_src_ptr) cinfo->src; - src->pub.init_source = my_init_source; - src->pub.fill_input_buffer = my_fill_input_buffer; - src->pub.skip_input_data = my_skip_input_data; - src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ - src->pub.term_source = my_term_source; - src->src_buffer = (JOCTET *)buffer; - src->src_size = bufsize; - src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ - src->pub.next_input_byte = NULL; /* until buffer loaded */ -} - -// ============================================================================= - -static char errormsg[JMSG_LENGTH_MAX]; - -typedef struct my_jpeg_error_mgr -{ - struct jpeg_error_mgr pub; // "public" fields - jmp_buf setjmp_buffer; // for return to caller -} bt_jpeg_error_mgr; - -static void my_jpeg_error_exit (j_common_ptr cinfo) -{ - my_jpeg_error_mgr* myerr = (bt_jpeg_error_mgr*) cinfo->err; - - (*cinfo->err->format_message) (cinfo, errormsg); - - longjmp (myerr->setjmp_buffer, 1); -} - -// stash a scanline -static void j_putRGBScanline (unsigned char* jpegline, int widthPix, unsigned char* outBuf, int row) -{ - int offset = row * widthPix * 4; - int count; - - for (count = 0; count < widthPix; count++) - { - unsigned char iRed, iBlu, iGrn; - unsigned char *oRed, *oBlu, *oGrn, *oAlp; - - iRed = *(jpegline + count * 3 + 0); - iGrn = *(jpegline + count * 3 + 1); - iBlu = *(jpegline + count * 3 + 2); - - oRed = outBuf + offset + count * 4 + 0; - oGrn = outBuf + offset + count * 4 + 1; - oBlu = outBuf + offset + count * 4 + 2; - oAlp = outBuf + offset + count * 4 + 3; - - *oRed = iRed; - *oGrn = iGrn; - *oBlu = iBlu; - *oAlp = 255; - } -} - -// stash a scanline -static void j_putRGBAScanline (unsigned char* jpegline, int widthPix, unsigned char* outBuf, int row) -{ - int offset = row * widthPix * 4; - int count; - - for (count = 0; count < widthPix; count++) - { - unsigned char iRed, iBlu, iGrn, iAlp; - unsigned char *oRed, *oBlu, *oGrn, *oAlp; - - iRed = *(jpegline + count * 4 + 0); - iGrn = *(jpegline + count * 4 + 1); - iBlu = *(jpegline + count * 4 + 2); - iAlp = *(jpegline + count * 4 + 3); - - oRed = outBuf + offset + count * 4 + 0; - oGrn = outBuf + offset + count * 4 + 1; - oBlu = outBuf + offset + count * 4 + 2; - oAlp = outBuf + offset + count * 4 + 3; - - *oRed = iRed; - *oGrn = iGrn; - *oBlu = iBlu; - // ydnar: see bug 900 - *oAlp = 255; //% iAlp; - } -} - -// stash a gray scanline -static void j_putGrayScanlineToRGB (unsigned char* jpegline, int widthPix, unsigned char* outBuf, int row) -{ - int offset = row * widthPix * 4; - int count; - - for (count = 0; count < widthPix; count++) - { - unsigned char iGray; - unsigned char *oRed, *oBlu, *oGrn, *oAlp; - - // get our grayscale value - iGray = *(jpegline + count); - - oRed = outBuf + offset + count * 4; - oGrn = outBuf + offset + count * 4 + 1; - oBlu = outBuf + offset + count * 4 + 2; - oAlp = outBuf + offset + count * 4 + 3; - - *oRed = iGray; - *oGrn = iGray; - *oBlu = iGray; - *oAlp = 255; - } -} - -static int _LoadJPGBuff (void *src_buffer, int src_size, unsigned char **pic, int *width, int *height) -{ - struct jpeg_decompress_struct cinfo; - struct my_jpeg_error_mgr jerr; - JSAMPARRAY buffer; - int row_stride, size; - - cinfo.err = jpeg_std_error (&jerr.pub); - jerr.pub.error_exit = my_jpeg_error_exit; - - if (setjmp (jerr.setjmp_buffer)) - { - *pic = (unsigned char*)errormsg; - jpeg_destroy_decompress (&cinfo); - return -1; - } - - jpeg_create_decompress (&cinfo); - jpeg_buffer_src (&cinfo, src_buffer, src_size); - jpeg_read_header (&cinfo, TRUE); - jpeg_start_decompress (&cinfo); - - row_stride = cinfo.output_width * cinfo.output_components; - - size = cinfo.output_width * cinfo.output_height * 4; - *width = cinfo.output_width; - *height = cinfo.output_height; - *pic = (unsigned char*) (g_malloc (size+1)); - memset (*pic, 0, size+1); - - buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); - - while (cinfo.output_scanline < cinfo.output_height) - { - jpeg_read_scanlines (&cinfo, buffer, 1); - - if (cinfo.out_color_components == 4) - j_putRGBAScanline (buffer[0], cinfo.output_width, *pic, cinfo.output_scanline-1); - else if (cinfo.out_color_components == 3) - j_putRGBScanline (buffer[0], cinfo.output_width, *pic, cinfo.output_scanline-1); - else if (cinfo.out_color_components == 1) - j_putGrayScanlineToRGB (buffer[0], cinfo.output_width, *pic, cinfo.output_scanline-1); - } - - jpeg_finish_decompress (&cinfo); - jpeg_destroy_decompress (&cinfo); - - return 0; -} - -void LoadJPG (const char *filename, unsigned char **pic, int *width, int *height) -{ - unsigned char *fbuffer = NULL; - int nLen = vfsLoadFile ((char *)filename, (void **)&fbuffer, 0 ); - if (nLen == -1) - return; - - if (_LoadJPGBuff (fbuffer, nLen, pic, width, height) != 0) - { - g_FuncTable.m_pfnSysPrintf( "WARNING: JPEG library failed to load %s because %s\n", filename, *pic ); - *pic = NULL; - } - - vfsFreeFile (fbuffer); -} +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// +// Functions to load JPEG files from a buffer, based on jdatasrc.c +// +// Leonardo Zide (leo@lokigames.com) +// + +#include +#include +#include +#include +#include + +#include +#include + /* +extern "C" { +#include "radiant_jpeglib.h" +#include "jpeg6/jerror.h" +} + */ + +#include "image.h" + +/* Expanded data source object for stdio input */ + +typedef struct { + struct jpeg_source_mgr pub; /* public fields */ + + int src_size; + JOCTET * src_buffer; + + JOCTET * buffer; /* start of buffer */ + boolean start_of_file; /* have we gotten any data yet? */ +} my_source_mgr; + +typedef my_source_mgr * my_src_ptr; + +#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ + + +/* + * Initialize source --- called by jpeg_read_header + * before any data is actually read. + */ + +static void my_init_source (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* We reset the empty-input-file flag for each image, + * but we don't clear the input buffer. + * This is correct behavior for reading a series of images from one source. + */ + src->start_of_file = TRUE; +} + + +/* + * Fill the input buffer --- called whenever buffer is emptied. + * + * In typical applications, this should read fresh data into the buffer + * (ignoring the current state of next_input_byte & bytes_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been reloaded. It is not necessary to + * fill the buffer entirely, only to obtain at least one more byte. + * + * There is no such thing as an EOF return. If the end of the file has been + * reached, the routine has a choice of ERREXIT() or inserting fake data into + * the buffer. In most cases, generating a warning message and inserting a + * fake EOI marker is the best course of action --- this will allow the + * decompressor to output however much of the image is there. However, + * the resulting error message is misleading if the real problem is an empty + * input file, so we handle that case specially. + * + * In applications that need to be able to suspend compression due to input + * not being available yet, a FALSE return indicates that no more data can be + * obtained right now, but more may be forthcoming later. In this situation, + * the decompressor will return to its caller (with an indication of the + * number of scanlines it has read, if any). The application should resume + * decompression after it has loaded more data into the input buffer. Note + * that there are substantial restrictions on the use of suspension --- see + * the documentation. + * + * When suspending, the decompressor will back up to a convenient restart point + * (typically the start of the current MCU). next_input_byte & bytes_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point must be rescanned after resumption, so move it to + * the front of the buffer rather than discarding it. + */ + +static boolean my_fill_input_buffer (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + size_t nbytes; + + if (src->src_size > INPUT_BUF_SIZE) + nbytes = INPUT_BUF_SIZE; + else + nbytes = src->src_size; + + memcpy (src->buffer, src->src_buffer, nbytes); + src->src_buffer += nbytes; + src->src_size -= nbytes; + + if (nbytes <= 0) { + if (src->start_of_file) /* Treat empty input file as fatal error */ + ERREXIT(cinfo, JERR_INPUT_EMPTY); + WARNMS(cinfo, JWRN_JPEG_EOF); + /* Insert a fake EOI marker */ + src->buffer[0] = (JOCTET) 0xFF; + src->buffer[1] = (JOCTET) JPEG_EOI; + nbytes = 2; + } + + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = nbytes; + src->start_of_file = FALSE; + + return TRUE; +} + + +/* + * Skip data --- used to skip over a potentially large amount of + * uninteresting data (such as an APPn marker). + * + * Writers of suspendable-input applications must note that skip_input_data + * is not granted the right to give a suspension return. If the skip extends + * beyond the data currently in the buffer, the buffer can be marked empty so + * that the next read will cause a fill_input_buffer call that can suspend. + * Arranging for additional bytes to be discarded before reloading the input + * buffer is the application writer's problem. + */ + +static void my_skip_input_data (j_decompress_ptr cinfo, long num_bytes) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* Just a dumb implementation for now. Could use fseek() except + * it doesn't work on pipes. Not clear that being smart is worth + * any trouble anyway --- large skips are infrequent. + */ + if (num_bytes > 0) { + while (num_bytes > (long) src->pub.bytes_in_buffer) { + num_bytes -= (long) src->pub.bytes_in_buffer; + (void) my_fill_input_buffer(cinfo); + /* note we assume that fill_input_buffer will never return FALSE, + * so suspension need not be handled. + */ + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } +} + + +/* + * An additional method that can be provided by data source modules is the + * resync_to_restart method for error recovery in the presence of RST markers. + * For the moment, this source module just uses the default resync method + * provided by the JPEG library. That method assumes that no backtracking + * is possible. + */ + + +/* + * Terminate source --- called by jpeg_finish_decompress + * after all data has been read. Often a no-op. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +static void my_term_source (j_decompress_ptr cinfo) +{ + /* no work necessary here */ +} + + +/* + * Prepare for input from a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing decompression. + */ + +static void jpeg_buffer_src (j_decompress_ptr cinfo, void* buffer, int bufsize) +{ + my_src_ptr src; + + /* The source object and input buffer are made permanent so that a series + * of JPEG images can be read from the same file by calling jpeg_stdio_src + * only before the first one. (If we discarded the buffer at the end of + * one image, we'd likely lose the start of the next one.) + * This makes it unsafe to use this manager and a different source + * manager serially with the same JPEG object. Caveat programmer. + */ + if (cinfo->src == NULL) { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + sizeof (my_source_mgr)); + src = (my_src_ptr) cinfo->src; + src->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + INPUT_BUF_SIZE * sizeof (JOCTET)); + } + + src = (my_src_ptr) cinfo->src; + src->pub.init_source = my_init_source; + src->pub.fill_input_buffer = my_fill_input_buffer; + src->pub.skip_input_data = my_skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = my_term_source; + src->src_buffer = (JOCTET *)buffer; + src->src_size = bufsize; + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->pub.next_input_byte = NULL; /* until buffer loaded */ +} + +// ============================================================================= + +static char errormsg[JMSG_LENGTH_MAX]; + +typedef struct my_jpeg_error_mgr +{ + struct jpeg_error_mgr pub; // "public" fields + jmp_buf setjmp_buffer; // for return to caller +} bt_jpeg_error_mgr; + +static void my_jpeg_error_exit (j_common_ptr cinfo) +{ + my_jpeg_error_mgr* myerr = (bt_jpeg_error_mgr*) cinfo->err; + + (*cinfo->err->format_message) (cinfo, errormsg); + + longjmp (myerr->setjmp_buffer, 1); +} + +// stash a scanline +static void j_putRGBScanline (unsigned char* jpegline, int widthPix, unsigned char* outBuf, int row) +{ + int offset = row * widthPix * 4; + int count; + + for (count = 0; count < widthPix; count++) + { + unsigned char iRed, iBlu, iGrn; + unsigned char *oRed, *oBlu, *oGrn, *oAlp; + + iRed = *(jpegline + count * 3 + 0); + iGrn = *(jpegline + count * 3 + 1); + iBlu = *(jpegline + count * 3 + 2); + + oRed = outBuf + offset + count * 4 + 0; + oGrn = outBuf + offset + count * 4 + 1; + oBlu = outBuf + offset + count * 4 + 2; + oAlp = outBuf + offset + count * 4 + 3; + + *oRed = iRed; + *oGrn = iGrn; + *oBlu = iBlu; + *oAlp = 255; + } +} + +// stash a scanline +static void j_putRGBAScanline (unsigned char* jpegline, int widthPix, unsigned char* outBuf, int row) +{ + int offset = row * widthPix * 4; + int count; + + for (count = 0; count < widthPix; count++) + { + unsigned char iRed, iBlu, iGrn, iAlp; + unsigned char *oRed, *oBlu, *oGrn, *oAlp; + + iRed = *(jpegline + count * 4 + 0); + iGrn = *(jpegline + count * 4 + 1); + iBlu = *(jpegline + count * 4 + 2); + iAlp = *(jpegline + count * 4 + 3); + + oRed = outBuf + offset + count * 4 + 0; + oGrn = outBuf + offset + count * 4 + 1; + oBlu = outBuf + offset + count * 4 + 2; + oAlp = outBuf + offset + count * 4 + 3; + + *oRed = iRed; + *oGrn = iGrn; + *oBlu = iBlu; + // ydnar: see bug 900 + *oAlp = 255; //% iAlp; + } +} + +// stash a gray scanline +static void j_putGrayScanlineToRGB (unsigned char* jpegline, int widthPix, unsigned char* outBuf, int row) +{ + int offset = row * widthPix * 4; + int count; + + for (count = 0; count < widthPix; count++) + { + unsigned char iGray; + unsigned char *oRed, *oBlu, *oGrn, *oAlp; + + // get our grayscale value + iGray = *(jpegline + count); + + oRed = outBuf + offset + count * 4; + oGrn = outBuf + offset + count * 4 + 1; + oBlu = outBuf + offset + count * 4 + 2; + oAlp = outBuf + offset + count * 4 + 3; + + *oRed = iGray; + *oGrn = iGray; + *oBlu = iGray; + *oAlp = 255; + } +} + +static int _LoadJPGBuff (void *src_buffer, int src_size, unsigned char **pic, int *width, int *height) +{ + struct jpeg_decompress_struct cinfo; + struct my_jpeg_error_mgr jerr; + JSAMPARRAY buffer; + int row_stride, size; + + cinfo.err = jpeg_std_error (&jerr.pub); + jerr.pub.error_exit = my_jpeg_error_exit; + + if (setjmp (jerr.setjmp_buffer)) + { + *pic = (unsigned char*)errormsg; + jpeg_destroy_decompress (&cinfo); + return -1; + } + + jpeg_create_decompress (&cinfo); + jpeg_buffer_src (&cinfo, src_buffer, src_size); + jpeg_read_header (&cinfo, TRUE); + jpeg_start_decompress (&cinfo); + + row_stride = cinfo.output_width * cinfo.output_components; + + size = cinfo.output_width * cinfo.output_height * 4; + *width = cinfo.output_width; + *height = cinfo.output_height; + *pic = (unsigned char*) (g_malloc (size+1)); + memset (*pic, 0, size+1); + + buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); + + while (cinfo.output_scanline < cinfo.output_height) + { + jpeg_read_scanlines (&cinfo, buffer, 1); + + if (cinfo.out_color_components == 4) + j_putRGBAScanline (buffer[0], cinfo.output_width, *pic, cinfo.output_scanline-1); + else if (cinfo.out_color_components == 3) + j_putRGBScanline (buffer[0], cinfo.output_width, *pic, cinfo.output_scanline-1); + else if (cinfo.out_color_components == 1) + j_putGrayScanlineToRGB (buffer[0], cinfo.output_width, *pic, cinfo.output_scanline-1); + } + + jpeg_finish_decompress (&cinfo); + jpeg_destroy_decompress (&cinfo); + + return 0; +} + +void LoadJPG (const char *filename, unsigned char **pic, int *width, int *height) +{ + unsigned char *fbuffer = NULL; + int nLen = vfsLoadFile ((char *)filename, (void **)&fbuffer, 0 ); + if (nLen == -1) + return; + + if (_LoadJPGBuff (fbuffer, nLen, pic, width, height) != 0) + { + g_FuncTable.m_pfnSysPrintf( "WARNING: JPEG library failed to load %s because %s\n", filename, *pic ); + *pic = NULL; + } + + vfsFreeFile (fbuffer); +} diff --git a/plugins/image/lbmlib.cpp b/plugins/image/lbmlib.cpp index b9749893..c7a2e1ef 100644 --- a/plugins/image/lbmlib.cpp +++ b/plugins/image/lbmlib.cpp @@ -1,762 +1,762 @@ -/* -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 -*/ - -// lbmlib.c - -#include -#include -#include -#include "image.h" -#include "lbmlib.h" -#include "bmp.h" - -#define LittleLong(a) GINT32_FROM_LE(a) -#define LittleShort(a) GINT16_FROM_LE(a) - -#include - -#define Sys_Printf g_FuncTable.m_pfnSysPrintf -#define Sys_FPrintf g_FuncTable.m_pfnSysFPrintf - -/* -============================================================================ - -LOAD PCX - -============================================================================ -*/ -typedef struct -{ - char manufacturer; - char version; - char encoding; - char bits_per_pixel; - unsigned short xmin, ymin, xmax, ymax; - unsigned short hres, vres; - unsigned char palette[48]; - char reserved; - char color_planes; - unsigned short bytes_per_line; - unsigned short palette_type; - char filler[58]; - unsigned char data; // unbounded -} pcx_t; - -/* -============================================================================ - -TARGA IMAGE - -============================================================================ -*/ -typedef struct _TargaHeader -{ - unsigned char id_length, colormap_type, image_type; - unsigned short colormap_index, colormap_length; - unsigned char colormap_size; - unsigned short x_origin, y_origin, width, height; - unsigned char pixel_size, attributes; -} TargaHeader; - -/* -========================================================= - -BMP LOADING - -========================================================= -*/ -typedef struct -{ - char id[2]; - unsigned long fileSize; - unsigned long reserved0; - unsigned long bitmapDataOffset; - unsigned long bitmapHeaderSize; - unsigned long width; - unsigned long height; - unsigned short planes; - unsigned short bitsPerPixel; - unsigned long compression; - unsigned long bitmapDataSize; - unsigned long hRes; - unsigned long vRes; - unsigned long colors; - unsigned long importantColors; - unsigned char palette[256][4]; -} BMPHeader_t; - -static void LoadBMP (const char *name, byte ** pic, int *width, int *height) -{ - int columns, rows, numPixels; - byte *pixbuf; - int row, column; - byte *buf_p; - byte *buffer; - unsigned int length; - BMPHeader_t bmpHeader; - byte *bmpRGBA; - - *pic = NULL; - - // - // load the file - // - length = vfsLoadFile( (char *)name, (void **)&buffer, 0 ); - if (length == (unsigned int) -1) - return; - - buf_p = buffer; - - bmpHeader.id[0] = *buf_p++; - bmpHeader.id[1] = *buf_p++; - bmpHeader.fileSize = LittleLong (*(long *) buf_p); - buf_p += 4; - bmpHeader.reserved0 = LittleLong (*(long *) buf_p); - buf_p += 4; - bmpHeader.bitmapDataOffset = LittleLong (*(long *) buf_p); - buf_p += 4; - bmpHeader.bitmapHeaderSize = LittleLong (*(long *) buf_p); - buf_p += 4; - bmpHeader.width = LittleLong (*(long *) buf_p); - buf_p += 4; - bmpHeader.height = LittleLong (*(long *) buf_p); - buf_p += 4; - bmpHeader.planes = LittleShort (*(short *) buf_p); - buf_p += 2; - bmpHeader.bitsPerPixel = LittleShort (*(short *) buf_p); - buf_p += 2; - bmpHeader.compression = LittleLong (*(long *) buf_p); - buf_p += 4; - bmpHeader.bitmapDataSize = LittleLong (*(long *) buf_p); - buf_p += 4; - bmpHeader.hRes = LittleLong (*(long *) buf_p); - buf_p += 4; - bmpHeader.vRes = LittleLong (*(long *) buf_p); - buf_p += 4; - bmpHeader.colors = LittleLong (*(long *) buf_p); - buf_p += 4; - bmpHeader.importantColors = LittleLong (*(long *) buf_p); - buf_p += 4; - - memcpy (bmpHeader.palette, buf_p, sizeof (bmpHeader.palette)); - - if (bmpHeader.bitsPerPixel == 8) - buf_p += 1024; - - if (bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M') - { - Sys_Printf ("LoadBMP: only Windows-style BMP files supported (%s)\n", name); - return; - } - if (bmpHeader.fileSize != length) - { - Sys_Printf ("LoadBMP: header size does not match file size (%d vs. %d) (%s)\n", - bmpHeader.fileSize, length, name); - return; - } - if (bmpHeader.compression != 0) - { - Sys_Printf ("LoadBMP: only uncompressed BMP files supported (%s)\n", name); - return; - } - if (bmpHeader.bitsPerPixel < 8) - { - Sys_Printf ("LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name); - return; - } - - columns = bmpHeader.width; - rows = bmpHeader.height; - if (rows < 0) - rows = -rows; - numPixels = columns * rows; - - if (width) - *width = columns; - if (height) - *height = rows; - - bmpRGBA = reinterpret_cast < unsigned char *>(g_malloc (numPixels * 4)); - *pic = bmpRGBA; - - - for (row = rows - 1; row >= 0; row--) - { - pixbuf = bmpRGBA + row * columns * 4; - - for (column = 0; column < columns; column++) - { - unsigned char red, green, blue, alpha; - int palIndex; - unsigned short shortPixel; - - switch (bmpHeader.bitsPerPixel) - { - case 8: - palIndex = *buf_p++; - *pixbuf++ = bmpHeader.palette[palIndex][2]; - *pixbuf++ = bmpHeader.palette[palIndex][1]; - *pixbuf++ = bmpHeader.palette[palIndex][0]; - *pixbuf++ = 0xff; - break; - case 16: - shortPixel = *(unsigned short *) pixbuf; - pixbuf += 2; - *pixbuf++ = (shortPixel & (31 << 10)) >> 7; - *pixbuf++ = (shortPixel & (31 << 5)) >> 2; - *pixbuf++ = (shortPixel & (31)) << 3; - *pixbuf++ = 0xff; - break; - case 24: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = 255; - break; - case 32: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - alpha = *buf_p++; - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = alpha; - break; - default: - Sys_Printf ("LoadBMP: illegal pixel_size '%d' in file '%s'\n", bmpHeader.bitsPerPixel, - name); - g_free (*pic); - *pic = NULL; - return; - break; - } - } - } - - vfsFreeFile (buffer); - -} - - -/* -================================================================= - -PCX LOADING - -================================================================= -*/ - - -/* -============== -LoadPCX -============== -*/ - -/* RR2DO2 */ -#define DECODEPCX( b, d, r ) d=*b++;if((d&0xC0)==0xC0){r=d&0x3F;d=*b++;}else{r=1;} - -static void LoadPCX( const char *filename, byte **pic, byte **palette, int *width, int *height ) -{ - byte *raw; - pcx_t *pcx; - int x, y, lsize; - int len; - int dataByte, runLength; - byte *out, *pix; - - - /* load the file */ - len = vfsLoadFile (filename, (void **)&raw, 0); - if( len == -1 ) - Error( "LoadPCX: Couldn't read %s", filename ); - - - /* parse the PCX file */ - pcx = (pcx_t *)raw; - raw = &pcx->data; - - pcx->xmin = LittleShort(pcx->xmin); - pcx->ymin = LittleShort(pcx->ymin); - pcx->xmax = LittleShort(pcx->xmax); - pcx->ymax = LittleShort(pcx->ymax); - pcx->hres = LittleShort(pcx->hres); - pcx->vres = LittleShort(pcx->vres); - pcx->bytes_per_line = LittleShort(pcx->bytes_per_line); - pcx->palette_type = LittleShort(pcx->palette_type); - - if (pcx->manufacturer != 0x0a - || pcx->version != 5 - || pcx->encoding != 1 - || pcx->bits_per_pixel != 8 - || pcx->xmax >= 640 - || pcx->ymax >= 480) - Error ("Bad pcx file %s", filename); - - if (palette) - { - *palette = (byte *)malloc(768); - memcpy (*palette, (byte *)pcx + len - 768, 768); - } - - if (width) - *width = pcx->xmax+1; - if (height) - *height = pcx->ymax+1; - - if (!pic) - return; - - out = (byte *)malloc ( (pcx->ymax+1) * (pcx->xmax+1) ); - if (!out) - Error( "LoadPCX: couldn't allocate"); - - *pic = out; - pix = out; - - /* RR2DO2: pcx fix */ - lsize = pcx->color_planes * pcx->bytes_per_line; - - /* go scanline by scanline */ - for( y = 0; y <= pcx->ymax; y++, pix += pcx->xmax + 1 ) - { - /* do a scanline */ - for( x=0; x <= pcx->xmax; ) - { - /* RR2DO2 */ - DECODEPCX( raw, dataByte, runLength ); - while( runLength-- > 0 ) - pix[ x++ ] = dataByte; - } - - /* RR2DO2: discard any other data */ - while( x < lsize ) - { - DECODEPCX( raw, dataByte, runLength ); - x++; - } - while( runLength-- > 0 ) - x++; - } - - /* validity check */ - if( raw - (byte *) pcx > len) - Error( "PCX file %s was malformed", filename ); - free( pcx ); -} - -/* -============== -LoadPCX32 -============== -*/ -static void LoadPCX32 (const char *filename, byte ** pic, int *width, int *height) -{ - byte *palette; - byte *pic8; - int i, c, p; - byte *pic32; - - LoadPCX (filename, &pic8, &palette, width, height); - if (!pic8) - { - *pic = NULL; - return; - } - - c = (*width) * (*height); - pic32 = *pic = reinterpret_cast < unsigned char *>(g_malloc (4 * c)); - for (i = 0; i < c; i++) - { - p = pic8[i]; - pic32[0] = palette[p * 3]; - pic32[1] = palette[p * 3 + 1]; - pic32[2] = palette[p * 3 + 2]; - pic32[3] = 255; - pic32 += 4; - } - - g_free (pic8); - g_free (palette); -} - -/* -========================================================= - -TARGA LOADING - - TTimo: added code to get rid of alphachannel from prefs or ignore it if completely empty - was required since Radiant is using alpha channel when binding the textures for proper curry operation - can be fully turned off from the prefs though -========================================================= -*/ - -/* -============= -LoadTGA -============= -*/ -void LoadTGA (const char *name, byte ** pic, int *width, int *height) -{ - int columns, rows, numPixels; - byte *pixbuf; - int row, column; - byte *buf_p; - byte *buffer; - TargaHeader targa_header; - byte *targa_rgba; - - *pic = NULL; - - // - // load the file - // - int nLen = vfsLoadFile( (char *)name, (void **)&buffer, 0 ); - if (nLen == -1) - return; - - buf_p = buffer; - - targa_header.id_length = *buf_p++; - targa_header.colormap_type = *buf_p++; - targa_header.image_type = *buf_p++; - - targa_header.colormap_index = LittleShort (*(short *) buf_p); - buf_p += 2; - targa_header.colormap_length = LittleShort (*(short *) buf_p); - buf_p += 2; - targa_header.colormap_size = *buf_p++; - targa_header.x_origin = LittleShort (*(short *) buf_p); - buf_p += 2; - targa_header.y_origin = LittleShort (*(short *) buf_p); - buf_p += 2; - targa_header.width = LittleShort (*(short *) buf_p); - buf_p += 2; - targa_header.height = LittleShort (*(short *) buf_p); - buf_p += 2; - targa_header.pixel_size = *buf_p++; - targa_header.attributes = *buf_p++; - - bool bAlphaOK = false; - - if (targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3) - { - Sys_Printf ("LoadTGA: TGA type %d not supported\n", targa_header.image_type); - Sys_Printf ("LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n"); - return; - } - - if (targa_header.colormap_type != 0) - { - Sys_Printf ("LoadTGA: colormaps not supported\n"); - return; - } - - if ((targa_header.pixel_size != 32 && targa_header.pixel_size != 24) - && targa_header.image_type != 3) - { - Sys_Printf ("LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); - return; - } - - columns = targa_header.width; - rows = targa_header.height; - numPixels = columns * rows; - - if (width) - *width = columns; - if (height) - *height = rows; - - targa_rgba = reinterpret_cast < unsigned char *>(g_malloc (numPixels * 4)); - *pic = targa_rgba; - - if (targa_header.id_length != 0) - buf_p += targa_header.id_length; // skip TARGA image comment - - if (targa_header.image_type == 2 || targa_header.image_type == 3) - { - // Uncompressed RGB or gray scale image - for (row = rows - 1; row >= 0; row--) - { - pixbuf = targa_rgba + row * columns * 4; - for (column = 0; column < columns; column++) - { - unsigned char red, green, blue, alphabyte; - switch (targa_header.pixel_size) - { - case 8: - blue = *buf_p++; - green = blue; - red = blue; - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = 255; - break; - - case 24: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = 255; - break; - case 32: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - alphabyte = *buf_p++; - // detect if the whole alpha channel is 0 - if (alphabyte != 0) - bAlphaOK = true; - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = alphabyte; - break; - default: - Sys_Printf ("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, - name); - g_free (*pic); - *pic = NULL; - return; - break; - } - } - } - - if (!bAlphaOK) - { - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=444 - if (targa_header.pixel_size == 32) - Sys_FPrintf (SYS_WRN, "WARNING: %s has empty alpha channel\n", name); - // disable the alpha value - for (row = rows - 1; row >= 0; row--) - { - pixbuf = targa_rgba + row * columns * 4; - for (column = 0; column < columns; column++) - { - // 32 bit - pixbuf += 3; - *pixbuf++ = 255; - } - } - } - } - else if (targa_header.image_type == 10) - { // Runlength encoded RGB images - unsigned char red, green, blue, alphabyte, packetHeader, packetSize, j; - - red = 0; - green = 0; - blue = 0; - alphabyte = 0xff; - - for (row = rows - 1; row >= 0; row--) - { - pixbuf = targa_rgba + row * columns * 4; - for (column = 0; column < columns;) - { - packetHeader = *buf_p++; - packetSize = 1 + (packetHeader & 0x7f); - if (packetHeader & 0x80) - { // run-length packet - switch (targa_header.pixel_size) - { - case 24: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - alphabyte = 255; - break; - case 32: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - alphabyte = *buf_p++; - // detect if the whole alpha channel is 0 - if (alphabyte != 0) - bAlphaOK = true; - break; - default: - Sys_Printf ("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, - name); - g_free (*pic); - *pic = NULL; - return; - break; - } - - for (j = 0; j < packetSize; j++) - { - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = alphabyte; - column++; - if (column == columns) - { // run spans across rows - column = 0; - if (row > 0) - row--; - else - goto breakOut; - pixbuf = targa_rgba + row * columns * 4; - } - } - } - else - { // non run-length packet - for (j = 0; j < packetSize; j++) - { - switch (targa_header.pixel_size) - { - case 24: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = 255; - break; - case 32: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - alphabyte = *buf_p++; - // detect if the whole alpha channel is 0 - if (alphabyte != 0) - bAlphaOK = true; - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = alphabyte; - break; - default: - Sys_Printf ("LoadTGA: illegal pixel_size '%d' in file '%s'\n", - targa_header.pixel_size, name); - g_free (*pic); - *pic = NULL; - return; - break; - } - column++; - if (column == columns) - { // pixel packet run spans across rows - column = 0; - if (row > 0) - row--; - else - goto breakOut; - pixbuf = targa_rgba + row * columns * 4; - } - } - } - } - breakOut:; - } - - if (!bAlphaOK) - { - if (targa_header.pixel_size == 32) - Sys_FPrintf (SYS_WRN, "WARNING: %s has empty alpha channel\n", name); - // disable the alpha value - for (row = rows - 1; row >= 0; row--) - { - pixbuf = targa_rgba + row * columns * 4; - for (column = 0; column < columns; column++) - { - // 32 bit - pixbuf += 3; - *pixbuf++ = 255; - } - } - } - - } - - // vertically flipped - if ( (targa_header.attributes & (1<<5)) ) { - int flip; - for (row = 0; row < .5f * rows; row++) - { - for (column = 0; column < columns; column++) - { - flip = *( (int*)targa_rgba + row * columns + column); - *( (int*)targa_rgba + row * columns + column) = *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ); - *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ) = flip; - } - } - } - - vfsFreeFile (buffer); -} - -//=================================================================== - -/* -================= -LoadImage - -Loads any of the supported image types into a cannonical -32 bit format. -================= -*/ -void LoadImage (const char *name, byte ** pic, int *width, int *height) -{ - int len; - *pic = NULL; - *width = 0; - *height = 0; - - len = strlen (name); - if (len < 5) - { - return; - } - - if (!g_strcasecmp (name + len - 4, ".tga")) - { - LoadTGA (name, pic, width, height); - } - else if (!g_strcasecmp (name + len - 4, ".pcx")) - { - LoadPCX32 (name, pic, width, height); - } - else if (!g_strcasecmp (name + len - 4, ".bmp")) - { - LoadBMP (name, pic, width, height); - } - /* - else if (!g_strcasecmp (name + len - 4, ".jpg")) - { - LoadJPG (name, pic, width, height); - } - */ -} +/* +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 +*/ + +// lbmlib.c + +#include +#include +#include +#include "image.h" +#include "lbmlib.h" +#include "bmp.h" + +#define LittleLong(a) GINT32_FROM_LE(a) +#define LittleShort(a) GINT16_FROM_LE(a) + +#include + +#define Sys_Printf g_FuncTable.m_pfnSysPrintf +#define Sys_FPrintf g_FuncTable.m_pfnSysFPrintf + +/* +============================================================================ + +LOAD PCX + +============================================================================ +*/ +typedef struct +{ + char manufacturer; + char version; + char encoding; + char bits_per_pixel; + unsigned short xmin, ymin, xmax, ymax; + unsigned short hres, vres; + unsigned char palette[48]; + char reserved; + char color_planes; + unsigned short bytes_per_line; + unsigned short palette_type; + char filler[58]; + unsigned char data; // unbounded +} pcx_t; + +/* +============================================================================ + +TARGA IMAGE + +============================================================================ +*/ +typedef struct _TargaHeader +{ + unsigned char id_length, colormap_type, image_type; + unsigned short colormap_index, colormap_length; + unsigned char colormap_size; + unsigned short x_origin, y_origin, width, height; + unsigned char pixel_size, attributes; +} TargaHeader; + +/* +========================================================= + +BMP LOADING + +========================================================= +*/ +typedef struct +{ + char id[2]; + unsigned long fileSize; + unsigned long reserved0; + unsigned long bitmapDataOffset; + unsigned long bitmapHeaderSize; + unsigned long width; + unsigned long height; + unsigned short planes; + unsigned short bitsPerPixel; + unsigned long compression; + unsigned long bitmapDataSize; + unsigned long hRes; + unsigned long vRes; + unsigned long colors; + unsigned long importantColors; + unsigned char palette[256][4]; +} BMPHeader_t; + +static void LoadBMP (const char *name, byte ** pic, int *width, int *height) +{ + int columns, rows, numPixels; + byte *pixbuf; + int row, column; + byte *buf_p; + byte *buffer; + unsigned int length; + BMPHeader_t bmpHeader; + byte *bmpRGBA; + + *pic = NULL; + + // + // load the file + // + length = vfsLoadFile( (char *)name, (void **)&buffer, 0 ); + if (length == (unsigned int) -1) + return; + + buf_p = buffer; + + bmpHeader.id[0] = *buf_p++; + bmpHeader.id[1] = *buf_p++; + bmpHeader.fileSize = LittleLong (*(long *) buf_p); + buf_p += 4; + bmpHeader.reserved0 = LittleLong (*(long *) buf_p); + buf_p += 4; + bmpHeader.bitmapDataOffset = LittleLong (*(long *) buf_p); + buf_p += 4; + bmpHeader.bitmapHeaderSize = LittleLong (*(long *) buf_p); + buf_p += 4; + bmpHeader.width = LittleLong (*(long *) buf_p); + buf_p += 4; + bmpHeader.height = LittleLong (*(long *) buf_p); + buf_p += 4; + bmpHeader.planes = LittleShort (*(short *) buf_p); + buf_p += 2; + bmpHeader.bitsPerPixel = LittleShort (*(short *) buf_p); + buf_p += 2; + bmpHeader.compression = LittleLong (*(long *) buf_p); + buf_p += 4; + bmpHeader.bitmapDataSize = LittleLong (*(long *) buf_p); + buf_p += 4; + bmpHeader.hRes = LittleLong (*(long *) buf_p); + buf_p += 4; + bmpHeader.vRes = LittleLong (*(long *) buf_p); + buf_p += 4; + bmpHeader.colors = LittleLong (*(long *) buf_p); + buf_p += 4; + bmpHeader.importantColors = LittleLong (*(long *) buf_p); + buf_p += 4; + + memcpy (bmpHeader.palette, buf_p, sizeof (bmpHeader.palette)); + + if (bmpHeader.bitsPerPixel == 8) + buf_p += 1024; + + if (bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M') + { + Sys_Printf ("LoadBMP: only Windows-style BMP files supported (%s)\n", name); + return; + } + if (bmpHeader.fileSize != length) + { + Sys_Printf ("LoadBMP: header size does not match file size (%d vs. %d) (%s)\n", + bmpHeader.fileSize, length, name); + return; + } + if (bmpHeader.compression != 0) + { + Sys_Printf ("LoadBMP: only uncompressed BMP files supported (%s)\n", name); + return; + } + if (bmpHeader.bitsPerPixel < 8) + { + Sys_Printf ("LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name); + return; + } + + columns = bmpHeader.width; + rows = bmpHeader.height; + if (rows < 0) + rows = -rows; + numPixels = columns * rows; + + if (width) + *width = columns; + if (height) + *height = rows; + + bmpRGBA = reinterpret_cast < unsigned char *>(g_malloc (numPixels * 4)); + *pic = bmpRGBA; + + + for (row = rows - 1; row >= 0; row--) + { + pixbuf = bmpRGBA + row * columns * 4; + + for (column = 0; column < columns; column++) + { + unsigned char red, green, blue, alpha; + int palIndex; + unsigned short shortPixel; + + switch (bmpHeader.bitsPerPixel) + { + case 8: + palIndex = *buf_p++; + *pixbuf++ = bmpHeader.palette[palIndex][2]; + *pixbuf++ = bmpHeader.palette[palIndex][1]; + *pixbuf++ = bmpHeader.palette[palIndex][0]; + *pixbuf++ = 0xff; + break; + case 16: + shortPixel = *(unsigned short *) pixbuf; + pixbuf += 2; + *pixbuf++ = (shortPixel & (31 << 10)) >> 7; + *pixbuf++ = (shortPixel & (31 << 5)) >> 2; + *pixbuf++ = (shortPixel & (31)) << 3; + *pixbuf++ = 0xff; + break; + case 24: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + case 32: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alpha = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alpha; + break; + default: + Sys_Printf ("LoadBMP: illegal pixel_size '%d' in file '%s'\n", bmpHeader.bitsPerPixel, + name); + g_free (*pic); + *pic = NULL; + return; + break; + } + } + } + + vfsFreeFile (buffer); + +} + + +/* +================================================================= + +PCX LOADING + +================================================================= +*/ + + +/* +============== +LoadPCX +============== +*/ + +/* RR2DO2 */ +#define DECODEPCX( b, d, r ) d=*b++;if((d&0xC0)==0xC0){r=d&0x3F;d=*b++;}else{r=1;} + +static void LoadPCX( const char *filename, byte **pic, byte **palette, int *width, int *height ) +{ + byte *raw; + pcx_t *pcx; + int x, y, lsize; + int len; + int dataByte, runLength; + byte *out, *pix; + + + /* load the file */ + len = vfsLoadFile (filename, (void **)&raw, 0); + if( len == -1 ) + Error( "LoadPCX: Couldn't read %s", filename ); + + + /* parse the PCX file */ + pcx = (pcx_t *)raw; + raw = &pcx->data; + + pcx->xmin = LittleShort(pcx->xmin); + pcx->ymin = LittleShort(pcx->ymin); + pcx->xmax = LittleShort(pcx->xmax); + pcx->ymax = LittleShort(pcx->ymax); + pcx->hres = LittleShort(pcx->hres); + pcx->vres = LittleShort(pcx->vres); + pcx->bytes_per_line = LittleShort(pcx->bytes_per_line); + pcx->palette_type = LittleShort(pcx->palette_type); + + if (pcx->manufacturer != 0x0a + || pcx->version != 5 + || pcx->encoding != 1 + || pcx->bits_per_pixel != 8 + || pcx->xmax >= 640 + || pcx->ymax >= 480) + Error ("Bad pcx file %s", filename); + + if (palette) + { + *palette = (byte *)malloc(768); + memcpy (*palette, (byte *)pcx + len - 768, 768); + } + + if (width) + *width = pcx->xmax+1; + if (height) + *height = pcx->ymax+1; + + if (!pic) + return; + + out = (byte *)malloc ( (pcx->ymax+1) * (pcx->xmax+1) ); + if (!out) + Error( "LoadPCX: couldn't allocate"); + + *pic = out; + pix = out; + + /* RR2DO2: pcx fix */ + lsize = pcx->color_planes * pcx->bytes_per_line; + + /* go scanline by scanline */ + for( y = 0; y <= pcx->ymax; y++, pix += pcx->xmax + 1 ) + { + /* do a scanline */ + for( x=0; x <= pcx->xmax; ) + { + /* RR2DO2 */ + DECODEPCX( raw, dataByte, runLength ); + while( runLength-- > 0 ) + pix[ x++ ] = dataByte; + } + + /* RR2DO2: discard any other data */ + while( x < lsize ) + { + DECODEPCX( raw, dataByte, runLength ); + x++; + } + while( runLength-- > 0 ) + x++; + } + + /* validity check */ + if( raw - (byte *) pcx > len) + Error( "PCX file %s was malformed", filename ); + free( pcx ); +} + +/* +============== +LoadPCX32 +============== +*/ +static void LoadPCX32 (const char *filename, byte ** pic, int *width, int *height) +{ + byte *palette; + byte *pic8; + int i, c, p; + byte *pic32; + + LoadPCX (filename, &pic8, &palette, width, height); + if (!pic8) + { + *pic = NULL; + return; + } + + c = (*width) * (*height); + pic32 = *pic = reinterpret_cast < unsigned char *>(g_malloc (4 * c)); + for (i = 0; i < c; i++) + { + p = pic8[i]; + pic32[0] = palette[p * 3]; + pic32[1] = palette[p * 3 + 1]; + pic32[2] = palette[p * 3 + 2]; + pic32[3] = 255; + pic32 += 4; + } + + g_free (pic8); + g_free (palette); +} + +/* +========================================================= + +TARGA LOADING + + TTimo: added code to get rid of alphachannel from prefs or ignore it if completely empty + was required since Radiant is using alpha channel when binding the textures for proper curry operation + can be fully turned off from the prefs though +========================================================= +*/ + +/* +============= +LoadTGA +============= +*/ +void LoadTGA (const char *name, byte ** pic, int *width, int *height) +{ + int columns, rows, numPixels; + byte *pixbuf; + int row, column; + byte *buf_p; + byte *buffer; + TargaHeader targa_header; + byte *targa_rgba; + + *pic = NULL; + + // + // load the file + // + int nLen = vfsLoadFile( (char *)name, (void **)&buffer, 0 ); + if (nLen == -1) + return; + + buf_p = buffer; + + targa_header.id_length = *buf_p++; + targa_header.colormap_type = *buf_p++; + targa_header.image_type = *buf_p++; + + targa_header.colormap_index = LittleShort (*(short *) buf_p); + buf_p += 2; + targa_header.colormap_length = LittleShort (*(short *) buf_p); + buf_p += 2; + targa_header.colormap_size = *buf_p++; + targa_header.x_origin = LittleShort (*(short *) buf_p); + buf_p += 2; + targa_header.y_origin = LittleShort (*(short *) buf_p); + buf_p += 2; + targa_header.width = LittleShort (*(short *) buf_p); + buf_p += 2; + targa_header.height = LittleShort (*(short *) buf_p); + buf_p += 2; + targa_header.pixel_size = *buf_p++; + targa_header.attributes = *buf_p++; + + bool bAlphaOK = false; + + if (targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3) + { + Sys_Printf ("LoadTGA: TGA type %d not supported\n", targa_header.image_type); + Sys_Printf ("LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n"); + return; + } + + if (targa_header.colormap_type != 0) + { + Sys_Printf ("LoadTGA: colormaps not supported\n"); + return; + } + + if ((targa_header.pixel_size != 32 && targa_header.pixel_size != 24) + && targa_header.image_type != 3) + { + Sys_Printf ("LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); + return; + } + + columns = targa_header.width; + rows = targa_header.height; + numPixels = columns * rows; + + if (width) + *width = columns; + if (height) + *height = rows; + + targa_rgba = reinterpret_cast < unsigned char *>(g_malloc (numPixels * 4)); + *pic = targa_rgba; + + if (targa_header.id_length != 0) + buf_p += targa_header.id_length; // skip TARGA image comment + + if (targa_header.image_type == 2 || targa_header.image_type == 3) + { + // Uncompressed RGB or gray scale image + for (row = rows - 1; row >= 0; row--) + { + pixbuf = targa_rgba + row * columns * 4; + for (column = 0; column < columns; column++) + { + unsigned char red, green, blue, alphabyte; + switch (targa_header.pixel_size) + { + case 8: + blue = *buf_p++; + green = blue; + red = blue; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + + case 24: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + case 32: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alphabyte = *buf_p++; + // detect if the whole alpha channel is 0 + if (alphabyte != 0) + bAlphaOK = true; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alphabyte; + break; + default: + Sys_Printf ("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, + name); + g_free (*pic); + *pic = NULL; + return; + break; + } + } + } + + if (!bAlphaOK) + { + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=444 + if (targa_header.pixel_size == 32) + Sys_FPrintf (SYS_WRN, "WARNING: %s has empty alpha channel\n", name); + // disable the alpha value + for (row = rows - 1; row >= 0; row--) + { + pixbuf = targa_rgba + row * columns * 4; + for (column = 0; column < columns; column++) + { + // 32 bit + pixbuf += 3; + *pixbuf++ = 255; + } + } + } + } + else if (targa_header.image_type == 10) + { // Runlength encoded RGB images + unsigned char red, green, blue, alphabyte, packetHeader, packetSize, j; + + red = 0; + green = 0; + blue = 0; + alphabyte = 0xff; + + for (row = rows - 1; row >= 0; row--) + { + pixbuf = targa_rgba + row * columns * 4; + for (column = 0; column < columns;) + { + packetHeader = *buf_p++; + packetSize = 1 + (packetHeader & 0x7f); + if (packetHeader & 0x80) + { // run-length packet + switch (targa_header.pixel_size) + { + case 24: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alphabyte = 255; + break; + case 32: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alphabyte = *buf_p++; + // detect if the whole alpha channel is 0 + if (alphabyte != 0) + bAlphaOK = true; + break; + default: + Sys_Printf ("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, + name); + g_free (*pic); + *pic = NULL; + return; + break; + } + + for (j = 0; j < packetSize; j++) + { + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alphabyte; + column++; + if (column == columns) + { // run spans across rows + column = 0; + if (row > 0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row * columns * 4; + } + } + } + else + { // non run-length packet + for (j = 0; j < packetSize; j++) + { + switch (targa_header.pixel_size) + { + case 24: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + case 32: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alphabyte = *buf_p++; + // detect if the whole alpha channel is 0 + if (alphabyte != 0) + bAlphaOK = true; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alphabyte; + break; + default: + Sys_Printf ("LoadTGA: illegal pixel_size '%d' in file '%s'\n", + targa_header.pixel_size, name); + g_free (*pic); + *pic = NULL; + return; + break; + } + column++; + if (column == columns) + { // pixel packet run spans across rows + column = 0; + if (row > 0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row * columns * 4; + } + } + } + } + breakOut:; + } + + if (!bAlphaOK) + { + if (targa_header.pixel_size == 32) + Sys_FPrintf (SYS_WRN, "WARNING: %s has empty alpha channel\n", name); + // disable the alpha value + for (row = rows - 1; row >= 0; row--) + { + pixbuf = targa_rgba + row * columns * 4; + for (column = 0; column < columns; column++) + { + // 32 bit + pixbuf += 3; + *pixbuf++ = 255; + } + } + } + + } + + // vertically flipped + if ( (targa_header.attributes & (1<<5)) ) { + int flip; + for (row = 0; row < .5f * rows; row++) + { + for (column = 0; column < columns; column++) + { + flip = *( (int*)targa_rgba + row * columns + column); + *( (int*)targa_rgba + row * columns + column) = *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ); + *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ) = flip; + } + } + } + + vfsFreeFile (buffer); +} + +//=================================================================== + +/* +================= +LoadImage + +Loads any of the supported image types into a cannonical +32 bit format. +================= +*/ +void LoadImage (const char *name, byte ** pic, int *width, int *height) +{ + int len; + *pic = NULL; + *width = 0; + *height = 0; + + len = strlen (name); + if (len < 5) + { + return; + } + + if (!g_strcasecmp (name + len - 4, ".tga")) + { + LoadTGA (name, pic, width, height); + } + else if (!g_strcasecmp (name + len - 4, ".pcx")) + { + LoadPCX32 (name, pic, width, height); + } + else if (!g_strcasecmp (name + len - 4, ".bmp")) + { + LoadBMP (name, pic, width, height); + } + /* + else if (!g_strcasecmp (name + len - 4, ".jpg")) + { + LoadJPG (name, pic, width, height); + } + */ +} diff --git a/plugins/imagehl/imagehl.cpp b/plugins/imagehl/imagehl.cpp index 6c3fa72a..eabfd163 100644 --- a/plugins/imagehl/imagehl.cpp +++ b/plugins/imagehl/imagehl.cpp @@ -1,104 +1,104 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -// -// HalfLife WAD format image loading plugin -// -// hydra - hydra@hydras-world.com -// - -#include -#include "imagehl.h" -#include "lbmlib.h" - -// ============================================================================= -// static variables - -_QERFuncTable_1 g_FuncTable; // Radiant function table -_QERFileSystemTable g_FileSystemTable; - -// ============================================================================= -// SYNAPSE - -CSynapseServer* g_pSynapseServer = NULL; -CSynapseClientImageHL 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()); - -#ifdef USE_HLW - g_SynapseClient.AddAPI(IMAGE_MAJOR, "hlw", sizeof(_QERPlugImageTable)); -#endif -#ifdef USE_MIP - g_SynapseClient.AddAPI(IMAGE_MAJOR, "mip", sizeof(_QERPlugImageTable)); -#endif -#ifdef USE_IDSP - g_SynapseClient.AddAPI(IMAGE_MAJOR, "spr", sizeof(_QERPlugImageTable)); -#endif - // this "wad" needs to be "*" for the VFS, we don't care what VFS we have, as long as we have one. - g_SynapseClient.AddAPI(VFS_MAJOR, "wad", sizeof(_QERFileSystemTable), SYN_REQUIRE, &g_FileSystemTable); - g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); - - return &g_SynapseClient; -} - -bool CSynapseClientImageHL::RequestAPI(APIDescriptor_t *pAPI) -{ - if (!strcmp(pAPI->major_name, "image")) - { - _QERPlugImageTable* pTable= static_cast<_QERPlugImageTable*>(pAPI->mpTable); - - pTable->m_pfnLoadImage = &LoadImage; - return true; - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -#include "version.h" - -const char* CSynapseClientImageHL::GetInfo() -{ - return "imagehl formats module built " __DATE__ " " RADIANT_VERSION; -} +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// +// HalfLife WAD format image loading plugin +// +// hydra - hydra@hydras-world.com +// + +#include +#include "imagehl.h" +#include "lbmlib.h" + +// ============================================================================= +// static variables + +_QERFuncTable_1 g_FuncTable; // Radiant function table +_QERFileSystemTable g_FileSystemTable; + +// ============================================================================= +// SYNAPSE + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientImageHL 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()); + +#ifdef USE_HLW + g_SynapseClient.AddAPI(IMAGE_MAJOR, "hlw", sizeof(_QERPlugImageTable)); +#endif +#ifdef USE_MIP + g_SynapseClient.AddAPI(IMAGE_MAJOR, "mip", sizeof(_QERPlugImageTable)); +#endif +#ifdef USE_IDSP + g_SynapseClient.AddAPI(IMAGE_MAJOR, "spr", sizeof(_QERPlugImageTable)); +#endif + // this "wad" needs to be "*" for the VFS, we don't care what VFS we have, as long as we have one. + g_SynapseClient.AddAPI(VFS_MAJOR, "wad", sizeof(_QERFileSystemTable), SYN_REQUIRE, &g_FileSystemTable); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + + return &g_SynapseClient; +} + +bool CSynapseClientImageHL::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, "image")) + { + _QERPlugImageTable* pTable= static_cast<_QERPlugImageTable*>(pAPI->mpTable); + + pTable->m_pfnLoadImage = &LoadImage; + return true; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientImageHL::GetInfo() +{ + return "imagehl formats module built " __DATE__ " " RADIANT_VERSION; +} diff --git a/plugins/imagehl/lbmlib.cpp b/plugins/imagehl/lbmlib.cpp index 1d705fe4..066ef39a 100644 --- a/plugins/imagehl/lbmlib.cpp +++ b/plugins/imagehl/lbmlib.cpp @@ -1,609 +1,609 @@ -/* -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 -*/ - -// lbmlib.c - -// by Hydra - hydra@hydras-world.com -// -// This module is based on the image module, but just more stripped down. -// it still currently supports TGA file loading, even though this is not -// required for HalfLife support (unless MD2 files use TGA's) -// -// use the #defines in imagehl.h to enable/disable the various formats. -// -// HLW = Half-Life-WAD, I don't know if the actual in data in the WAD files -// has it's own name, so I'm just calling the individal textures .HLW files :) -// -// Thanks to the guys that made Wally for releasing an example WAD loader. -// without it this would not have been possible. - -#include -#include -#include -#include "imagehl.h" -#include "lbmlib.h" - -#include - -#define Sys_Printf g_FuncTable.m_pfnSysPrintf -#define Sys_FPrintf g_FuncTable.m_pfnSysFPrintf - - -#ifdef USE_IDSP -/* -============================================================================ - -IDSP IMAGE (.spr files) - -Some code copied straight from the Q1 source, also used the HalfLife SDK as -a reference. - -============================================================================ -*/ - -typedef enum {ST_SYNC=0, ST_RAND } synctype_t; -typedef enum { SPR_SINGLE=0, SPR_GROUP } spriteframetype_t; - -typedef struct dspriteheader_s { - int ident; - int version; -} dspriteheader_t; - -// Quake1 -typedef struct { - int type; - float boundingradius; - int width; - int height; - int numframes; - float beamlength; - synctype_t synctype; -} dspritev1_t; - -// Halflife -typedef struct { - int type; - int texFormat; - float boundingradius; - int width; - int height; - int numframes; - float beamlength; - synctype_t synctype; -} dspritev2_t; - -typedef struct { - int origin[2]; - int width; - int height; -} dspriteframe_t; - -typedef struct { - short type; -} dspriteframetype_t; - -/* -typedef struct { - byte rgb[256][3]; -} dpalette_t; -*/ - -#define IDSPRITEHEADER (('P'<<24)+('S'<<16)+('D'<<8)+'I') - // little-endian "IDSP" - -/* -============= -LoadIDSP -============= -*/ - -static void LoadIDSP (const char *name, byte ** pic, int *width, int *height) -{ - byte *buffer; - byte *buf_p; - unsigned int length; - int columns, rows, numPixels; - byte *pixbuf; - - int row, column; - byte *bmpRGBA; - byte *palette; - unsigned char red, green, blue, alphabyte; - - dspriteheader_t *header; - dspritev1_t *pinv1; - dspritev2_t *pinv2; - dspriteframetype_t *pframetype; - int version; - int numframes; - int size; - spriteframetype_t frametype; - dspriteframe_t *spriteframe; - - *pic = NULL; - - // - // load the file - // - length = vfsLoadFile ((char *) name, (void **) &buffer); - if (length == (unsigned int) -1) - return; - - header = (dspriteheader_t *)buffer; - - if (header->ident != IDSPRITEHEADER) - { - Sys_Printf ("WARNING: %s has wrong header\n"); - vfsFreeFile (buffer); - return; - } - - version = header->version; - if (version != 1 && version != 2 ) - { - Sys_Printf ("WARNING: %s has wrong version number " - "(%i should be 1 or 2)\n", name, version); - vfsFreeFile (buffer); - return; - } - - // initialise variables depending on the sprite version. - switch (version) - { - case 1: - pinv1 = (dspritev1_t *)(header+1); - numframes = pinv1->numframes; - columns = pinv1->width; - rows = pinv1->height; - pframetype = (dspriteframetype_t *)(pinv1 + 1); - break; - case 2: - pinv2 = (dspritev2_t *)(header+1); - numframes = pinv2->numframes; - columns = pinv2->width; - rows = pinv2->height; - pframetype = (dspriteframetype_t *)(pinv2 + 1); - break; - } - if (numframes > 1) - Sys_Printf ("WARNING: %s has multiple frames, only the first frame will be used.\n", name); - - // palette = buffer+mipdatasize+2; - // buf_p = buffer+lpMip->offsets[0]; - - numPixels = columns * rows; - - if (width) - *width = columns; - if (height) - *height = rows; - - bmpRGBA = reinterpret_cast < unsigned char *>(g_malloc (numPixels * 4)); - *pic = bmpRGBA; - -#ifdef DEBUG - frametype = spriteframetype_t(LittleLong(pframetype->type)); - if (frametype == SPR_SINGLE) - { - Sys_Printf("Single Frame\n"); - } - else if (frametype == SPR_GROUP) - { - Sys_Printf("Group of Frames\n"); - } - else - { - Sys_Printf("Bleh!\n"); // <-- we always get this, wtf! - } -#endif - - palette = (byte *)(pframetype+1); - spriteframe = (dspriteframe_t *)(palette + (256*3) + 4); // what are those 4 extra bytes ? what's missing ? - buf_p = (byte *)(spriteframe + 1); - - int temp; - - temp = buf_p - buffer; - - for (row = 0; row < rows; row++) - { - pixbuf = bmpRGBA + row * columns * 4; - - for (column = 0; column < columns; column++) - { - int palIndex; - - palIndex = *buf_p++; - - red = *(palette+(palIndex*3)); - green = *(palette+(palIndex*3)+1); - blue = *(palette+(palIndex*3)+2); - - // HalfLife engine makes pixels that are BLUE transparent. (RGB = 0x0000FF) - // So show them that way in the editor. - if (blue == 0xff && red == 0x00 && green == 0x00) - { - alphabyte = 0xff; //FIXME: backwards? (so sprite models to render correctly) - blue = 0x00; // don't set the resulting pixel to blue - } - else - { - alphabyte = 0x00; //FIXME: backwards? (so sprite models to render correctly) - } - - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - - *pixbuf++ = alphabyte; - } - } - - vfsFreeFile (buffer); -} -#endif - -#ifdef USE_HLW -/* -============================================================================ - -HLW IMAGE - - HalfLife WAD files contain files that look like this: - - Mip section - First mip - Mip header - First mip (width * height) - Second mip (width * height / 4) - Third mip (width * height / 16) - Fourth mip (width * height / 64) - Palette size (WORD) - Palette (Palette size * 3) - Padding (WORD) - -============================================================================ -*/ - -#define GET_MIP_DATA_SIZE(WIDTH, HEIGHT) (sizeof(WAD3_MIP) + (WIDTH * HEIGHT) + (WIDTH * HEIGHT / 4) + (WIDTH * HEIGHT / 16) + (WIDTH * HEIGHT / 64)) - -typedef struct -{ - char name[16]; - DWORD width, height; - DWORD offsets[4]; // four mip maps stored -} WAD3_MIP, *LPWAD3_MIP; - -/* -========================================================= - -HLW LOADING - - Hydra: this code isn't bullet proof and probably won't - like corrupt WAD files, but it works for now. - - TODO: make it more robust. -========================================================= -*/ - -/* -============= -LoadHLW -============= -*/ - -static void LoadHLW (const char *name, byte ** pic, int *width, int *height) -{ - byte *buffer; - byte *buf_p; - unsigned int length; - unsigned long mipdatasize; - int columns, rows, numPixels; - byte *pixbuf; - int row, column; - byte *bmpRGBA; - byte *palette; - LPWAD3_MIP lpMip; - unsigned char red, green, blue, alphabyte; - - *pic = NULL; - - // - // load the file - // - length = vfsLoadFile ((char *) name, (void **) &buffer); - if (length == (unsigned int) -1) - return; - - lpMip = (LPWAD3_MIP)buffer; - - mipdatasize = GET_MIP_DATA_SIZE(lpMip->width,lpMip->height); - - palette = buffer+mipdatasize+2; - - buf_p = buffer+lpMip->offsets[0]; - - columns = lpMip->width; - rows = lpMip->height; - numPixels = columns * rows; - - if (width) - *width = columns; - if (height) - *height = rows; - - bmpRGBA = reinterpret_cast < unsigned char *>(g_malloc (numPixels * 4)); - *pic = bmpRGBA; - - for (row = 0; row < rows; row++) - { - pixbuf = bmpRGBA + row * columns * 4; - - for (column = 0; column < columns; column++) - { - int palIndex; - - palIndex = *buf_p++; - - red = *(palette+(palIndex*3)); - green = *(palette+(palIndex*3)+1); - blue = *(palette+(palIndex*3)+2); - - // HalfLife engine makes pixels that are BLUE transparent. - // So show them that way in the editor. - if (blue == 0xff && red == 0x00 && green == 0x00) - { - alphabyte = 0x00; - blue = 0x00; // don't set the resulting pixel to blue - } - else - { - alphabyte = 0xff; - } - - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - - *pixbuf++ = alphabyte; - } - } - - vfsFreeFile (buffer); -} -#endif - -#ifdef USE_MIP -/* -============================================================================ - -MIP IMAGE - - Quake WAD files contain miptex files that look like this: - - Mip section - First mip - Mip header - First mip (width * height) - Second mip (width * height / 4) - Third mip (width * height / 16) - Fourth mip (width * height / 64) - -============================================================================ -*/ - -/* -========================================================= - -MIP LOADING - - LordHavoc: this code is based on the HLW code above. -========================================================= -*/ - - -static const byte quakepalette[768] = -{ - 0x00,0x00,0x00, 0x0f,0x0f,0x0f, 0x1f,0x1f,0x1f, 0x2f,0x2f,0x2f, - 0x3f,0x3f,0x3f, 0x4b,0x4b,0x4b, 0x5b,0x5b,0x5b, 0x6b,0x6b,0x6b, - 0x7b,0x7b,0x7b, 0x8b,0x8b,0x8b, 0x9b,0x9b,0x9b, 0xab,0xab,0xab, - 0xbb,0xbb,0xbb, 0xcb,0xcb,0xcb, 0xdb,0xdb,0xdb, 0xeb,0xeb,0xeb, - 0x0f,0x0b,0x07, 0x17,0x0f,0x0b, 0x1f,0x17,0x0b, 0x27,0x1b,0x0f, - 0x2f,0x23,0x13, 0x37,0x2b,0x17, 0x3f,0x2f,0x17, 0x4b,0x37,0x1b, - 0x53,0x3b,0x1b, 0x5b,0x43,0x1f, 0x63,0x4b,0x1f, 0x6b,0x53,0x1f, - 0x73,0x57,0x1f, 0x7b,0x5f,0x23, 0x83,0x67,0x23, 0x8f,0x6f,0x23, - 0x0b,0x0b,0x0f, 0x13,0x13,0x1b, 0x1b,0x1b,0x27, 0x27,0x27,0x33, - 0x2f,0x2f,0x3f, 0x37,0x37,0x4b, 0x3f,0x3f,0x57, 0x47,0x47,0x67, - 0x4f,0x4f,0x73, 0x5b,0x5b,0x7f, 0x63,0x63,0x8b, 0x6b,0x6b,0x97, - 0x73,0x73,0xa3, 0x7b,0x7b,0xaf, 0x83,0x83,0xbb, 0x8b,0x8b,0xcb, - 0x00,0x00,0x00, 0x07,0x07,0x00, 0x0b,0x0b,0x00, 0x13,0x13,0x00, - 0x1b,0x1b,0x00, 0x23,0x23,0x00, 0x2b,0x2b,0x07, 0x2f,0x2f,0x07, - 0x37,0x37,0x07, 0x3f,0x3f,0x07, 0x47,0x47,0x07, 0x4b,0x4b,0x0b, - 0x53,0x53,0x0b, 0x5b,0x5b,0x0b, 0x63,0x63,0x0b, 0x6b,0x6b,0x0f, - 0x07,0x00,0x00, 0x0f,0x00,0x00, 0x17,0x00,0x00, 0x1f,0x00,0x00, - 0x27,0x00,0x00, 0x2f,0x00,0x00, 0x37,0x00,0x00, 0x3f,0x00,0x00, - 0x47,0x00,0x00, 0x4f,0x00,0x00, 0x57,0x00,0x00, 0x5f,0x00,0x00, - 0x67,0x00,0x00, 0x6f,0x00,0x00, 0x77,0x00,0x00, 0x7f,0x00,0x00, - 0x13,0x13,0x00, 0x1b,0x1b,0x00, 0x23,0x23,0x00, 0x2f,0x2b,0x00, - 0x37,0x2f,0x00, 0x43,0x37,0x00, 0x4b,0x3b,0x07, 0x57,0x43,0x07, - 0x5f,0x47,0x07, 0x6b,0x4b,0x0b, 0x77,0x53,0x0f, 0x83,0x57,0x13, - 0x8b,0x5b,0x13, 0x97,0x5f,0x1b, 0xa3,0x63,0x1f, 0xaf,0x67,0x23, - 0x23,0x13,0x07, 0x2f,0x17,0x0b, 0x3b,0x1f,0x0f, 0x4b,0x23,0x13, - 0x57,0x2b,0x17, 0x63,0x2f,0x1f, 0x73,0x37,0x23, 0x7f,0x3b,0x2b, - 0x8f,0x43,0x33, 0x9f,0x4f,0x33, 0xaf,0x63,0x2f, 0xbf,0x77,0x2f, - 0xcf,0x8f,0x2b, 0xdf,0xab,0x27, 0xef,0xcb,0x1f, 0xff,0xf3,0x1b, - 0x0b,0x07,0x00, 0x1b,0x13,0x00, 0x2b,0x23,0x0f, 0x37,0x2b,0x13, - 0x47,0x33,0x1b, 0x53,0x37,0x23, 0x63,0x3f,0x2b, 0x6f,0x47,0x33, - 0x7f,0x53,0x3f, 0x8b,0x5f,0x47, 0x9b,0x6b,0x53, 0xa7,0x7b,0x5f, - 0xb7,0x87,0x6b, 0xc3,0x93,0x7b, 0xd3,0xa3,0x8b, 0xe3,0xb3,0x97, - 0xab,0x8b,0xa3, 0x9f,0x7f,0x97, 0x93,0x73,0x87, 0x8b,0x67,0x7b, - 0x7f,0x5b,0x6f, 0x77,0x53,0x63, 0x6b,0x4b,0x57, 0x5f,0x3f,0x4b, - 0x57,0x37,0x43, 0x4b,0x2f,0x37, 0x43,0x27,0x2f, 0x37,0x1f,0x23, - 0x2b,0x17,0x1b, 0x23,0x13,0x13, 0x17,0x0b,0x0b, 0x0f,0x07,0x07, - 0xbb,0x73,0x9f, 0xaf,0x6b,0x8f, 0xa3,0x5f,0x83, 0x97,0x57,0x77, - 0x8b,0x4f,0x6b, 0x7f,0x4b,0x5f, 0x73,0x43,0x53, 0x6b,0x3b,0x4b, - 0x5f,0x33,0x3f, 0x53,0x2b,0x37, 0x47,0x23,0x2b, 0x3b,0x1f,0x23, - 0x2f,0x17,0x1b, 0x23,0x13,0x13, 0x17,0x0b,0x0b, 0x0f,0x07,0x07, - 0xdb,0xc3,0xbb, 0xcb,0xb3,0xa7, 0xbf,0xa3,0x9b, 0xaf,0x97,0x8b, - 0xa3,0x87,0x7b, 0x97,0x7b,0x6f, 0x87,0x6f,0x5f, 0x7b,0x63,0x53, - 0x6b,0x57,0x47, 0x5f,0x4b,0x3b, 0x53,0x3f,0x33, 0x43,0x33,0x27, - 0x37,0x2b,0x1f, 0x27,0x1f,0x17, 0x1b,0x13,0x0f, 0x0f,0x0b,0x07, - 0x6f,0x83,0x7b, 0x67,0x7b,0x6f, 0x5f,0x73,0x67, 0x57,0x6b,0x5f, - 0x4f,0x63,0x57, 0x47,0x5b,0x4f, 0x3f,0x53,0x47, 0x37,0x4b,0x3f, - 0x2f,0x43,0x37, 0x2b,0x3b,0x2f, 0x23,0x33,0x27, 0x1f,0x2b,0x1f, - 0x17,0x23,0x17, 0x0f,0x1b,0x13, 0x0b,0x13,0x0b, 0x07,0x0b,0x07, - 0xff,0xf3,0x1b, 0xef,0xdf,0x17, 0xdb,0xcb,0x13, 0xcb,0xb7,0x0f, - 0xbb,0xa7,0x0f, 0xab,0x97,0x0b, 0x9b,0x83,0x07, 0x8b,0x73,0x07, - 0x7b,0x63,0x07, 0x6b,0x53,0x00, 0x5b,0x47,0x00, 0x4b,0x37,0x00, - 0x3b,0x2b,0x00, 0x2b,0x1f,0x00, 0x1b,0x0f,0x00, 0x0b,0x07,0x00, - 0x00,0x00,0xff, 0x0b,0x0b,0xef, 0x13,0x13,0xdf, 0x1b,0x1b,0xcf, - 0x23,0x23,0xbf, 0x2b,0x2b,0xaf, 0x2f,0x2f,0x9f, 0x2f,0x2f,0x8f, - 0x2f,0x2f,0x7f, 0x2f,0x2f,0x6f, 0x2f,0x2f,0x5f, 0x2b,0x2b,0x4f, - 0x23,0x23,0x3f, 0x1b,0x1b,0x2f, 0x13,0x13,0x1f, 0x0b,0x0b,0x0f, - 0x2b,0x00,0x00, 0x3b,0x00,0x00, 0x4b,0x07,0x00, 0x5f,0x07,0x00, - 0x6f,0x0f,0x00, 0x7f,0x17,0x07, 0x93,0x1f,0x07, 0xa3,0x27,0x0b, - 0xb7,0x33,0x0f, 0xc3,0x4b,0x1b, 0xcf,0x63,0x2b, 0xdb,0x7f,0x3b, - 0xe3,0x97,0x4f, 0xe7,0xab,0x5f, 0xef,0xbf,0x77, 0xf7,0xd3,0x8b, - 0xa7,0x7b,0x3b, 0xb7,0x9b,0x37, 0xc7,0xc3,0x37, 0xe7,0xe3,0x57, - 0x7f,0xbf,0xff, 0xab,0xe7,0xff, 0xd7,0xff,0xff, 0x67,0x00,0x00, - 0x8b,0x00,0x00, 0xb3,0x00,0x00, 0xd7,0x00,0x00, 0xff,0x00,0x00, - 0xff,0xf3,0x93, 0xff,0xf7,0xc7, 0xff,0xff,0xff, 0x9f,0x5b,0x53 -}; - -/* -============= -LoadMIP -============= -*/ - -static void LoadMIP (const char *name, byte ** pic, int *width, int *height) -{ - byte *buffer; - byte *buf_p; - unsigned int length, palettelength; - unsigned long mipdatasize; - int columns, rows, numPixels; - byte *pixbuf; - int i; - byte *bmpRGBA; - byte *loadedpalette; - const byte *palette; - LPWAD3_MIP lpMip; - - *pic = NULL; - loadedpalette = NULL; - - // - // load the file - // - length = vfsLoadFile ((char *) name, (void **) &buffer); - if (length == (unsigned int) -1) - return; - - lpMip = (LPWAD3_MIP)buffer; - - mipdatasize = GET_MIP_DATA_SIZE(lpMip->width,lpMip->height); - - palettelength = vfsLoadFile ("textures/palette.lmp", (void **) &loadedpalette); - if (palettelength == 768) - palette = loadedpalette; - else - { - loadedpalette = NULL; - palette = quakepalette; - } - - buf_p = buffer+lpMip->offsets[0]; - - columns = lpMip->width; - rows = lpMip->height; - numPixels = columns * rows; - - if (width) - *width = columns; - if (height) - *height = rows; - - //Sys_Printf("lpMip->width = %i, lpMip->height = %i, lpMip->offsets[0] = %i, lpMip->offsets[1] = %i, lpMip->offsets[2] = %i, lpMip->offsets[3] = %i, numPixels = %i\n", lpMip->width, lpMip->height, lpMip->offsets[0], lpMip->offsets[1], lpMip->offsets[2], lpMip->offsets[3], numPixels); - //for (i = 0; i < sizeof(*lpMip); i++) - // Sys_Printf("%02x", (int) ((unsigned char *)lpMip)[i]); - - bmpRGBA = reinterpret_cast < unsigned char *>(g_malloc (numPixels * 4)); - *pic = bmpRGBA; - pixbuf = bmpRGBA; - - for (i = 0; i < numPixels; i++) - { - int palIndex = *buf_p++; - *pixbuf++ = palette[palIndex*3]; - *pixbuf++ = palette[palIndex*3+1]; - *pixbuf++ = palette[palIndex*3+2]; - *pixbuf++ = 0xff; - } - - vfsFreeFile (buffer); - if (loadedpalette != NULL) - vfsFreeFile (loadedpalette); -} -#endif - -/* -================= -LoadImage - -Loads any of the supported image types into a cannonical -32 bit format. -================= -*/ -void LoadImage (const char *name, byte ** pic, int *width, int *height) -{ - int len; - *pic = NULL; - *width = 0; - *height = 0; - - len = strlen (name); - if (len < 5) - { - return; - } - -#ifdef USE_HLW - if (*pic == NULL && !g_strcasecmp (name + len - 4, ".hlw")) - { - LoadHLW (name, pic, width, height); - } -#endif - -#ifdef USE_MIP - if (*pic == NULL && !g_strcasecmp (name + len - 4, ".mip")) - { - LoadMIP (name, pic, width, height); - } -#endif - -#ifdef USE_IDSP - if (*pic == NULL && !g_strcasecmp (name + len - 4, ".spr")) - { - LoadIDSP (name, pic, width, height); - } -#endif -} +/* +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 +*/ + +// lbmlib.c + +// by Hydra - hydra@hydras-world.com +// +// This module is based on the image module, but just more stripped down. +// it still currently supports TGA file loading, even though this is not +// required for HalfLife support (unless MD2 files use TGA's) +// +// use the #defines in imagehl.h to enable/disable the various formats. +// +// HLW = Half-Life-WAD, I don't know if the actual in data in the WAD files +// has it's own name, so I'm just calling the individal textures .HLW files :) +// +// Thanks to the guys that made Wally for releasing an example WAD loader. +// without it this would not have been possible. + +#include +#include +#include +#include "imagehl.h" +#include "lbmlib.h" + +#include + +#define Sys_Printf g_FuncTable.m_pfnSysPrintf +#define Sys_FPrintf g_FuncTable.m_pfnSysFPrintf + + +#ifdef USE_IDSP +/* +============================================================================ + +IDSP IMAGE (.spr files) + +Some code copied straight from the Q1 source, also used the HalfLife SDK as +a reference. + +============================================================================ +*/ + +typedef enum {ST_SYNC=0, ST_RAND } synctype_t; +typedef enum { SPR_SINGLE=0, SPR_GROUP } spriteframetype_t; + +typedef struct dspriteheader_s { + int ident; + int version; +} dspriteheader_t; + +// Quake1 +typedef struct { + int type; + float boundingradius; + int width; + int height; + int numframes; + float beamlength; + synctype_t synctype; +} dspritev1_t; + +// Halflife +typedef struct { + int type; + int texFormat; + float boundingradius; + int width; + int height; + int numframes; + float beamlength; + synctype_t synctype; +} dspritev2_t; + +typedef struct { + int origin[2]; + int width; + int height; +} dspriteframe_t; + +typedef struct { + short type; +} dspriteframetype_t; + +/* +typedef struct { + byte rgb[256][3]; +} dpalette_t; +*/ + +#define IDSPRITEHEADER (('P'<<24)+('S'<<16)+('D'<<8)+'I') + // little-endian "IDSP" + +/* +============= +LoadIDSP +============= +*/ + +static void LoadIDSP (const char *name, byte ** pic, int *width, int *height) +{ + byte *buffer; + byte *buf_p; + unsigned int length; + int columns, rows, numPixels; + byte *pixbuf; + + int row, column; + byte *bmpRGBA; + byte *palette; + unsigned char red, green, blue, alphabyte; + + dspriteheader_t *header; + dspritev1_t *pinv1; + dspritev2_t *pinv2; + dspriteframetype_t *pframetype; + int version; + int numframes; + int size; + spriteframetype_t frametype; + dspriteframe_t *spriteframe; + + *pic = NULL; + + // + // load the file + // + length = vfsLoadFile ((char *) name, (void **) &buffer); + if (length == (unsigned int) -1) + return; + + header = (dspriteheader_t *)buffer; + + if (header->ident != IDSPRITEHEADER) + { + Sys_Printf ("WARNING: %s has wrong header\n"); + vfsFreeFile (buffer); + return; + } + + version = header->version; + if (version != 1 && version != 2 ) + { + Sys_Printf ("WARNING: %s has wrong version number " + "(%i should be 1 or 2)\n", name, version); + vfsFreeFile (buffer); + return; + } + + // initialise variables depending on the sprite version. + switch (version) + { + case 1: + pinv1 = (dspritev1_t *)(header+1); + numframes = pinv1->numframes; + columns = pinv1->width; + rows = pinv1->height; + pframetype = (dspriteframetype_t *)(pinv1 + 1); + break; + case 2: + pinv2 = (dspritev2_t *)(header+1); + numframes = pinv2->numframes; + columns = pinv2->width; + rows = pinv2->height; + pframetype = (dspriteframetype_t *)(pinv2 + 1); + break; + } + if (numframes > 1) + Sys_Printf ("WARNING: %s has multiple frames, only the first frame will be used.\n", name); + + // palette = buffer+mipdatasize+2; + // buf_p = buffer+lpMip->offsets[0]; + + numPixels = columns * rows; + + if (width) + *width = columns; + if (height) + *height = rows; + + bmpRGBA = reinterpret_cast < unsigned char *>(g_malloc (numPixels * 4)); + *pic = bmpRGBA; + +#ifdef DEBUG + frametype = spriteframetype_t(LittleLong(pframetype->type)); + if (frametype == SPR_SINGLE) + { + Sys_Printf("Single Frame\n"); + } + else if (frametype == SPR_GROUP) + { + Sys_Printf("Group of Frames\n"); + } + else + { + Sys_Printf("Bleh!\n"); // <-- we always get this, wtf! + } +#endif + + palette = (byte *)(pframetype+1); + spriteframe = (dspriteframe_t *)(palette + (256*3) + 4); // what are those 4 extra bytes ? what's missing ? + buf_p = (byte *)(spriteframe + 1); + + int temp; + + temp = buf_p - buffer; + + for (row = 0; row < rows; row++) + { + pixbuf = bmpRGBA + row * columns * 4; + + for (column = 0; column < columns; column++) + { + int palIndex; + + palIndex = *buf_p++; + + red = *(palette+(palIndex*3)); + green = *(palette+(palIndex*3)+1); + blue = *(palette+(palIndex*3)+2); + + // HalfLife engine makes pixels that are BLUE transparent. (RGB = 0x0000FF) + // So show them that way in the editor. + if (blue == 0xff && red == 0x00 && green == 0x00) + { + alphabyte = 0xff; //FIXME: backwards? (so sprite models to render correctly) + blue = 0x00; // don't set the resulting pixel to blue + } + else + { + alphabyte = 0x00; //FIXME: backwards? (so sprite models to render correctly) + } + + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + + *pixbuf++ = alphabyte; + } + } + + vfsFreeFile (buffer); +} +#endif + +#ifdef USE_HLW +/* +============================================================================ + +HLW IMAGE + + HalfLife WAD files contain files that look like this: + + Mip section + First mip + Mip header + First mip (width * height) + Second mip (width * height / 4) + Third mip (width * height / 16) + Fourth mip (width * height / 64) + Palette size (WORD) + Palette (Palette size * 3) + Padding (WORD) + +============================================================================ +*/ + +#define GET_MIP_DATA_SIZE(WIDTH, HEIGHT) (sizeof(WAD3_MIP) + (WIDTH * HEIGHT) + (WIDTH * HEIGHT / 4) + (WIDTH * HEIGHT / 16) + (WIDTH * HEIGHT / 64)) + +typedef struct +{ + char name[16]; + DWORD width, height; + DWORD offsets[4]; // four mip maps stored +} WAD3_MIP, *LPWAD3_MIP; + +/* +========================================================= + +HLW LOADING + + Hydra: this code isn't bullet proof and probably won't + like corrupt WAD files, but it works for now. + + TODO: make it more robust. +========================================================= +*/ + +/* +============= +LoadHLW +============= +*/ + +static void LoadHLW (const char *name, byte ** pic, int *width, int *height) +{ + byte *buffer; + byte *buf_p; + unsigned int length; + unsigned long mipdatasize; + int columns, rows, numPixels; + byte *pixbuf; + int row, column; + byte *bmpRGBA; + byte *palette; + LPWAD3_MIP lpMip; + unsigned char red, green, blue, alphabyte; + + *pic = NULL; + + // + // load the file + // + length = vfsLoadFile ((char *) name, (void **) &buffer); + if (length == (unsigned int) -1) + return; + + lpMip = (LPWAD3_MIP)buffer; + + mipdatasize = GET_MIP_DATA_SIZE(lpMip->width,lpMip->height); + + palette = buffer+mipdatasize+2; + + buf_p = buffer+lpMip->offsets[0]; + + columns = lpMip->width; + rows = lpMip->height; + numPixels = columns * rows; + + if (width) + *width = columns; + if (height) + *height = rows; + + bmpRGBA = reinterpret_cast < unsigned char *>(g_malloc (numPixels * 4)); + *pic = bmpRGBA; + + for (row = 0; row < rows; row++) + { + pixbuf = bmpRGBA + row * columns * 4; + + for (column = 0; column < columns; column++) + { + int palIndex; + + palIndex = *buf_p++; + + red = *(palette+(palIndex*3)); + green = *(palette+(palIndex*3)+1); + blue = *(palette+(palIndex*3)+2); + + // HalfLife engine makes pixels that are BLUE transparent. + // So show them that way in the editor. + if (blue == 0xff && red == 0x00 && green == 0x00) + { + alphabyte = 0x00; + blue = 0x00; // don't set the resulting pixel to blue + } + else + { + alphabyte = 0xff; + } + + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + + *pixbuf++ = alphabyte; + } + } + + vfsFreeFile (buffer); +} +#endif + +#ifdef USE_MIP +/* +============================================================================ + +MIP IMAGE + + Quake WAD files contain miptex files that look like this: + + Mip section + First mip + Mip header + First mip (width * height) + Second mip (width * height / 4) + Third mip (width * height / 16) + Fourth mip (width * height / 64) + +============================================================================ +*/ + +/* +========================================================= + +MIP LOADING + + LordHavoc: this code is based on the HLW code above. +========================================================= +*/ + + +static const byte quakepalette[768] = +{ + 0x00,0x00,0x00, 0x0f,0x0f,0x0f, 0x1f,0x1f,0x1f, 0x2f,0x2f,0x2f, + 0x3f,0x3f,0x3f, 0x4b,0x4b,0x4b, 0x5b,0x5b,0x5b, 0x6b,0x6b,0x6b, + 0x7b,0x7b,0x7b, 0x8b,0x8b,0x8b, 0x9b,0x9b,0x9b, 0xab,0xab,0xab, + 0xbb,0xbb,0xbb, 0xcb,0xcb,0xcb, 0xdb,0xdb,0xdb, 0xeb,0xeb,0xeb, + 0x0f,0x0b,0x07, 0x17,0x0f,0x0b, 0x1f,0x17,0x0b, 0x27,0x1b,0x0f, + 0x2f,0x23,0x13, 0x37,0x2b,0x17, 0x3f,0x2f,0x17, 0x4b,0x37,0x1b, + 0x53,0x3b,0x1b, 0x5b,0x43,0x1f, 0x63,0x4b,0x1f, 0x6b,0x53,0x1f, + 0x73,0x57,0x1f, 0x7b,0x5f,0x23, 0x83,0x67,0x23, 0x8f,0x6f,0x23, + 0x0b,0x0b,0x0f, 0x13,0x13,0x1b, 0x1b,0x1b,0x27, 0x27,0x27,0x33, + 0x2f,0x2f,0x3f, 0x37,0x37,0x4b, 0x3f,0x3f,0x57, 0x47,0x47,0x67, + 0x4f,0x4f,0x73, 0x5b,0x5b,0x7f, 0x63,0x63,0x8b, 0x6b,0x6b,0x97, + 0x73,0x73,0xa3, 0x7b,0x7b,0xaf, 0x83,0x83,0xbb, 0x8b,0x8b,0xcb, + 0x00,0x00,0x00, 0x07,0x07,0x00, 0x0b,0x0b,0x00, 0x13,0x13,0x00, + 0x1b,0x1b,0x00, 0x23,0x23,0x00, 0x2b,0x2b,0x07, 0x2f,0x2f,0x07, + 0x37,0x37,0x07, 0x3f,0x3f,0x07, 0x47,0x47,0x07, 0x4b,0x4b,0x0b, + 0x53,0x53,0x0b, 0x5b,0x5b,0x0b, 0x63,0x63,0x0b, 0x6b,0x6b,0x0f, + 0x07,0x00,0x00, 0x0f,0x00,0x00, 0x17,0x00,0x00, 0x1f,0x00,0x00, + 0x27,0x00,0x00, 0x2f,0x00,0x00, 0x37,0x00,0x00, 0x3f,0x00,0x00, + 0x47,0x00,0x00, 0x4f,0x00,0x00, 0x57,0x00,0x00, 0x5f,0x00,0x00, + 0x67,0x00,0x00, 0x6f,0x00,0x00, 0x77,0x00,0x00, 0x7f,0x00,0x00, + 0x13,0x13,0x00, 0x1b,0x1b,0x00, 0x23,0x23,0x00, 0x2f,0x2b,0x00, + 0x37,0x2f,0x00, 0x43,0x37,0x00, 0x4b,0x3b,0x07, 0x57,0x43,0x07, + 0x5f,0x47,0x07, 0x6b,0x4b,0x0b, 0x77,0x53,0x0f, 0x83,0x57,0x13, + 0x8b,0x5b,0x13, 0x97,0x5f,0x1b, 0xa3,0x63,0x1f, 0xaf,0x67,0x23, + 0x23,0x13,0x07, 0x2f,0x17,0x0b, 0x3b,0x1f,0x0f, 0x4b,0x23,0x13, + 0x57,0x2b,0x17, 0x63,0x2f,0x1f, 0x73,0x37,0x23, 0x7f,0x3b,0x2b, + 0x8f,0x43,0x33, 0x9f,0x4f,0x33, 0xaf,0x63,0x2f, 0xbf,0x77,0x2f, + 0xcf,0x8f,0x2b, 0xdf,0xab,0x27, 0xef,0xcb,0x1f, 0xff,0xf3,0x1b, + 0x0b,0x07,0x00, 0x1b,0x13,0x00, 0x2b,0x23,0x0f, 0x37,0x2b,0x13, + 0x47,0x33,0x1b, 0x53,0x37,0x23, 0x63,0x3f,0x2b, 0x6f,0x47,0x33, + 0x7f,0x53,0x3f, 0x8b,0x5f,0x47, 0x9b,0x6b,0x53, 0xa7,0x7b,0x5f, + 0xb7,0x87,0x6b, 0xc3,0x93,0x7b, 0xd3,0xa3,0x8b, 0xe3,0xb3,0x97, + 0xab,0x8b,0xa3, 0x9f,0x7f,0x97, 0x93,0x73,0x87, 0x8b,0x67,0x7b, + 0x7f,0x5b,0x6f, 0x77,0x53,0x63, 0x6b,0x4b,0x57, 0x5f,0x3f,0x4b, + 0x57,0x37,0x43, 0x4b,0x2f,0x37, 0x43,0x27,0x2f, 0x37,0x1f,0x23, + 0x2b,0x17,0x1b, 0x23,0x13,0x13, 0x17,0x0b,0x0b, 0x0f,0x07,0x07, + 0xbb,0x73,0x9f, 0xaf,0x6b,0x8f, 0xa3,0x5f,0x83, 0x97,0x57,0x77, + 0x8b,0x4f,0x6b, 0x7f,0x4b,0x5f, 0x73,0x43,0x53, 0x6b,0x3b,0x4b, + 0x5f,0x33,0x3f, 0x53,0x2b,0x37, 0x47,0x23,0x2b, 0x3b,0x1f,0x23, + 0x2f,0x17,0x1b, 0x23,0x13,0x13, 0x17,0x0b,0x0b, 0x0f,0x07,0x07, + 0xdb,0xc3,0xbb, 0xcb,0xb3,0xa7, 0xbf,0xa3,0x9b, 0xaf,0x97,0x8b, + 0xa3,0x87,0x7b, 0x97,0x7b,0x6f, 0x87,0x6f,0x5f, 0x7b,0x63,0x53, + 0x6b,0x57,0x47, 0x5f,0x4b,0x3b, 0x53,0x3f,0x33, 0x43,0x33,0x27, + 0x37,0x2b,0x1f, 0x27,0x1f,0x17, 0x1b,0x13,0x0f, 0x0f,0x0b,0x07, + 0x6f,0x83,0x7b, 0x67,0x7b,0x6f, 0x5f,0x73,0x67, 0x57,0x6b,0x5f, + 0x4f,0x63,0x57, 0x47,0x5b,0x4f, 0x3f,0x53,0x47, 0x37,0x4b,0x3f, + 0x2f,0x43,0x37, 0x2b,0x3b,0x2f, 0x23,0x33,0x27, 0x1f,0x2b,0x1f, + 0x17,0x23,0x17, 0x0f,0x1b,0x13, 0x0b,0x13,0x0b, 0x07,0x0b,0x07, + 0xff,0xf3,0x1b, 0xef,0xdf,0x17, 0xdb,0xcb,0x13, 0xcb,0xb7,0x0f, + 0xbb,0xa7,0x0f, 0xab,0x97,0x0b, 0x9b,0x83,0x07, 0x8b,0x73,0x07, + 0x7b,0x63,0x07, 0x6b,0x53,0x00, 0x5b,0x47,0x00, 0x4b,0x37,0x00, + 0x3b,0x2b,0x00, 0x2b,0x1f,0x00, 0x1b,0x0f,0x00, 0x0b,0x07,0x00, + 0x00,0x00,0xff, 0x0b,0x0b,0xef, 0x13,0x13,0xdf, 0x1b,0x1b,0xcf, + 0x23,0x23,0xbf, 0x2b,0x2b,0xaf, 0x2f,0x2f,0x9f, 0x2f,0x2f,0x8f, + 0x2f,0x2f,0x7f, 0x2f,0x2f,0x6f, 0x2f,0x2f,0x5f, 0x2b,0x2b,0x4f, + 0x23,0x23,0x3f, 0x1b,0x1b,0x2f, 0x13,0x13,0x1f, 0x0b,0x0b,0x0f, + 0x2b,0x00,0x00, 0x3b,0x00,0x00, 0x4b,0x07,0x00, 0x5f,0x07,0x00, + 0x6f,0x0f,0x00, 0x7f,0x17,0x07, 0x93,0x1f,0x07, 0xa3,0x27,0x0b, + 0xb7,0x33,0x0f, 0xc3,0x4b,0x1b, 0xcf,0x63,0x2b, 0xdb,0x7f,0x3b, + 0xe3,0x97,0x4f, 0xe7,0xab,0x5f, 0xef,0xbf,0x77, 0xf7,0xd3,0x8b, + 0xa7,0x7b,0x3b, 0xb7,0x9b,0x37, 0xc7,0xc3,0x37, 0xe7,0xe3,0x57, + 0x7f,0xbf,0xff, 0xab,0xe7,0xff, 0xd7,0xff,0xff, 0x67,0x00,0x00, + 0x8b,0x00,0x00, 0xb3,0x00,0x00, 0xd7,0x00,0x00, 0xff,0x00,0x00, + 0xff,0xf3,0x93, 0xff,0xf7,0xc7, 0xff,0xff,0xff, 0x9f,0x5b,0x53 +}; + +/* +============= +LoadMIP +============= +*/ + +static void LoadMIP (const char *name, byte ** pic, int *width, int *height) +{ + byte *buffer; + byte *buf_p; + unsigned int length, palettelength; + unsigned long mipdatasize; + int columns, rows, numPixels; + byte *pixbuf; + int i; + byte *bmpRGBA; + byte *loadedpalette; + const byte *palette; + LPWAD3_MIP lpMip; + + *pic = NULL; + loadedpalette = NULL; + + // + // load the file + // + length = vfsLoadFile ((char *) name, (void **) &buffer); + if (length == (unsigned int) -1) + return; + + lpMip = (LPWAD3_MIP)buffer; + + mipdatasize = GET_MIP_DATA_SIZE(lpMip->width,lpMip->height); + + palettelength = vfsLoadFile ("textures/palette.lmp", (void **) &loadedpalette); + if (palettelength == 768) + palette = loadedpalette; + else + { + loadedpalette = NULL; + palette = quakepalette; + } + + buf_p = buffer+lpMip->offsets[0]; + + columns = lpMip->width; + rows = lpMip->height; + numPixels = columns * rows; + + if (width) + *width = columns; + if (height) + *height = rows; + + //Sys_Printf("lpMip->width = %i, lpMip->height = %i, lpMip->offsets[0] = %i, lpMip->offsets[1] = %i, lpMip->offsets[2] = %i, lpMip->offsets[3] = %i, numPixels = %i\n", lpMip->width, lpMip->height, lpMip->offsets[0], lpMip->offsets[1], lpMip->offsets[2], lpMip->offsets[3], numPixels); + //for (i = 0; i < sizeof(*lpMip); i++) + // Sys_Printf("%02x", (int) ((unsigned char *)lpMip)[i]); + + bmpRGBA = reinterpret_cast < unsigned char *>(g_malloc (numPixels * 4)); + *pic = bmpRGBA; + pixbuf = bmpRGBA; + + for (i = 0; i < numPixels; i++) + { + int palIndex = *buf_p++; + *pixbuf++ = palette[palIndex*3]; + *pixbuf++ = palette[palIndex*3+1]; + *pixbuf++ = palette[palIndex*3+2]; + *pixbuf++ = 0xff; + } + + vfsFreeFile (buffer); + if (loadedpalette != NULL) + vfsFreeFile (loadedpalette); +} +#endif + +/* +================= +LoadImage + +Loads any of the supported image types into a cannonical +32 bit format. +================= +*/ +void LoadImage (const char *name, byte ** pic, int *width, int *height) +{ + int len; + *pic = NULL; + *width = 0; + *height = 0; + + len = strlen (name); + if (len < 5) + { + return; + } + +#ifdef USE_HLW + if (*pic == NULL && !g_strcasecmp (name + len - 4, ".hlw")) + { + LoadHLW (name, pic, width, height); + } +#endif + +#ifdef USE_MIP + if (*pic == NULL && !g_strcasecmp (name + len - 4, ".mip")) + { + LoadMIP (name, pic, width, height); + } +#endif + +#ifdef USE_IDSP + if (*pic == NULL && !g_strcasecmp (name + len - 4, ".spr")) + { + LoadIDSP (name, pic, width, height); + } +#endif +} diff --git a/plugins/imagem8/imagem8.cpp b/plugins/imagem8/imagem8.cpp index fef68436..7d318593 100644 --- a/plugins/imagem8/imagem8.cpp +++ b/plugins/imagem8/imagem8.cpp @@ -1,128 +1,128 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -// -// Image loading plugin -// -// Leonardo Zide (leo@lokigames.com) -// - -#include -#include "imagem8.h" - -// ============================================================================= -// global tables - -_QERFuncTable_1 g_FuncTable; // Radiant function table -_QERFileSystemTable g_FileSystemTable; - -// ============================================================================= -// SYNAPSE - -CSynapseServer* g_pSynapseServer = NULL; -CSynapseClientImage 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(IMAGE_MAJOR, "m8", sizeof(_QERPlugImageTable)); - g_SynapseClient.AddAPI(IMAGE_MAJOR, "m32", sizeof(_QERPlugImageTable)); - g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); - - Syn_Printf("Dynamic APIs for client '%s'\n", g_SynapseClient.GetInfo()); - if (!g_pSynapseServer->SelectClientConfig(g_SynapseClient.GetName())) - { - Syn_Printf("ERROR: Failed to select synapse client config in '%s'\n", g_SynapseClient.GetInfo()); - return NULL; - } - char *api, *minor; - while(g_pSynapseServer->GetNextConfig(&api, &minor)) - { - Syn_Printf("api: '%s' minor: '%s'\n", api, minor); - if (!strcmp(api, VFS_MAJOR)) - { - g_SynapseClient.AddAPI(VFS_MAJOR, minor, sizeof(_QERFileSystemTable), SYN_REQUIRE, &g_FileSystemTable); - } - else - { - Syn_Printf("WARNING: unknown API node '%s' in synapse config from module '%s'\n", api, g_SynapseClient.GetInfo()); - } - } - return &g_SynapseClient; -} - -bool CSynapseClientImage::RequestAPI(APIDescriptor_t *pAPI) -{ - if (!strcmp(pAPI->major_name, IMAGE_MAJOR )) - { - _QERPlugImageTable* pTable= static_cast<_QERPlugImageTable*>(pAPI->mpTable); - if (!strcmp(pAPI->minor_name, "m8")) - { - pTable->m_pfnLoadImage = &LoadM8; - return true; - } - if (!strcmp(pAPI->minor_name, "m32")) - { - pTable->m_pfnLoadImage = &LoadM32; - return true; - } - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -bool CSynapseClientImage::OnActivate() { - if (!g_FileSystemTable.m_nSize) { - Syn_Printf("ERROR: VFS_MAJOR table was not initialized before OnActivate in '%s' - incomplete synapse.config?\n", GetInfo()); - return false; - } - return true; -} - -#include "version.h" - -const char* CSynapseClientImage::GetInfo() -{ - return "M8 M32 formats module built " __DATE__ " " RADIANT_VERSION; -} +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// +// Image loading plugin +// +// Leonardo Zide (leo@lokigames.com) +// + +#include +#include "imagem8.h" + +// ============================================================================= +// global tables + +_QERFuncTable_1 g_FuncTable; // Radiant function table +_QERFileSystemTable g_FileSystemTable; + +// ============================================================================= +// SYNAPSE + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientImage 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(IMAGE_MAJOR, "m8", sizeof(_QERPlugImageTable)); + g_SynapseClient.AddAPI(IMAGE_MAJOR, "m32", sizeof(_QERPlugImageTable)); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + + Syn_Printf("Dynamic APIs for client '%s'\n", g_SynapseClient.GetInfo()); + if (!g_pSynapseServer->SelectClientConfig(g_SynapseClient.GetName())) + { + Syn_Printf("ERROR: Failed to select synapse client config in '%s'\n", g_SynapseClient.GetInfo()); + return NULL; + } + char *api, *minor; + while(g_pSynapseServer->GetNextConfig(&api, &minor)) + { + Syn_Printf("api: '%s' minor: '%s'\n", api, minor); + if (!strcmp(api, VFS_MAJOR)) + { + g_SynapseClient.AddAPI(VFS_MAJOR, minor, sizeof(_QERFileSystemTable), SYN_REQUIRE, &g_FileSystemTable); + } + else + { + Syn_Printf("WARNING: unknown API node '%s' in synapse config from module '%s'\n", api, g_SynapseClient.GetInfo()); + } + } + return &g_SynapseClient; +} + +bool CSynapseClientImage::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, IMAGE_MAJOR )) + { + _QERPlugImageTable* pTable= static_cast<_QERPlugImageTable*>(pAPI->mpTable); + if (!strcmp(pAPI->minor_name, "m8")) + { + pTable->m_pfnLoadImage = &LoadM8; + return true; + } + if (!strcmp(pAPI->minor_name, "m32")) + { + pTable->m_pfnLoadImage = &LoadM32; + return true; + } + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +bool CSynapseClientImage::OnActivate() { + if (!g_FileSystemTable.m_nSize) { + Syn_Printf("ERROR: VFS_MAJOR table was not initialized before OnActivate in '%s' - incomplete synapse.config?\n", GetInfo()); + return false; + } + return true; +} + +#include "version.h" + +const char* CSynapseClientImage::GetInfo() +{ + return "M8 M32 formats module built " __DATE__ " " RADIANT_VERSION; +} diff --git a/plugins/imagem8/m32.cpp b/plugins/imagem8/m32.cpp index bb2c5efa..b5a1fe93 100644 --- a/plugins/imagem8/m32.cpp +++ b/plugins/imagem8/m32.cpp @@ -1,77 +1,77 @@ -/* -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 -*/ - -#include -#include -#include -#include "m32.h" - -void LoadM32(const char *name, unsigned char **pic, int *width, int *height) -{ - FILE *f; - m32_header_t *m32_header; - //rgb_t *palette; - int i, num_pixels, size; - char text_buf[255]; - unsigned int length; - unsigned char *palette_ent, *buf_temp; - unsigned char *buffer, *m32_file_buffer; - - // open file - if ( length = vfsLoadFile ((char *) name, (void **) &m32_file_buffer) == (unsigned int) -1) - { - Sys_Printf("Unable to open file %s\n",name); - return; - } - - m32_header = (m32_header_t *)m32_file_buffer; - - // make sure we have a valid bitmap file - if ( m32_header->version != M32_VERSION) - { - vfsFreeFile(m32_file_buffer); - Sys_Printf("Invalid M32 file %s\n", name); - } - - // Get M32 Info - *width = m32_header->width[0]; // Only interested in 1st MIP - *height = m32_header->height[0]; - num_pixels = (*width) * (*height); - size = num_pixels*4; - - // Allocate buffer - buf_temp = (unsigned char *)(g_malloc(size)); - *pic = buf_temp; - - // Image data - buffer = m32_file_buffer + m32_header->offsets[0]; - - - // Load texture into buffer - palette_ent = buffer; - for(i=0; i +#include +#include +#include "m32.h" + +void LoadM32(const char *name, unsigned char **pic, int *width, int *height) +{ + FILE *f; + m32_header_t *m32_header; + //rgb_t *palette; + int i, num_pixels, size; + char text_buf[255]; + unsigned int length; + unsigned char *palette_ent, *buf_temp; + unsigned char *buffer, *m32_file_buffer; + + // open file + if ( length = vfsLoadFile ((char *) name, (void **) &m32_file_buffer) == (unsigned int) -1) + { + Sys_Printf("Unable to open file %s\n",name); + return; + } + + m32_header = (m32_header_t *)m32_file_buffer; + + // make sure we have a valid bitmap file + if ( m32_header->version != M32_VERSION) + { + vfsFreeFile(m32_file_buffer); + Sys_Printf("Invalid M32 file %s\n", name); + } + + // Get M32 Info + *width = m32_header->width[0]; // Only interested in 1st MIP + *height = m32_header->height[0]; + num_pixels = (*width) * (*height); + size = num_pixels*4; + + // Allocate buffer + buf_temp = (unsigned char *)(g_malloc(size)); + *pic = buf_temp; + + // Image data + buffer = m32_file_buffer + m32_header->offsets[0]; + + + // Load texture into buffer + palette_ent = buffer; + for(i=0; i -#include -#include -#include "m8.h" - -void LoadM8(const char *name, unsigned char **pic, int *width, int *height) -{ - FILE *f; - m8_header_t *m8_header; - rgb_t *palette; - int i, num_pixels, size; - char text_buf[255] = { 0 }; - char *text_dot_pos; - unsigned int length; - unsigned char *palette_ent, *buf_temp; - unsigned char *buffer, *m8_file_buffer; - - strcpy(text_buf, name); - text_dot_pos = strchr(text_buf, '.'); - if (text_dot_pos) - *text_dot_pos = 0; - // Fix for .pcx.m8 extention - strcat(text_buf, ".pcx.m8"); - - // open file - if ( length = vfsLoadFile ((char *) text_buf, (void **) &m8_file_buffer) == (unsigned int) -1) - { - strcpy(text_buf, name); - for(i=(strlen(text_buf)-1); i>0; i--) - { - if(text_buf[i]=='.') - { - text_buf[i]=0; - break; - } - } - strcat(text_buf, ".m8"); - if ( length = vfsLoadFile ((char *) text_buf, (void **) &m8_file_buffer) == (unsigned int) -1) - { - Sys_Printf("Unable to open file %s\n",name); - return; - } - } - - m8_header = (m8_header_t *)m8_file_buffer; - - // make sure we have a valid M8 file - if ( m8_header->version != M8_VERSION) - { - vfsFreeFile(m8_file_buffer); - Sys_Printf("Invalid M8 file %s\n", name); - return; - } - - // Get M8 Info - *width = m8_header->width[0]; // Only interested in 1st MIP - *height = m8_header->height[0]; - num_pixels = (*width) * (*height); - size = num_pixels*4; - - // Allocate buffer - buf_temp = (unsigned char *)(g_malloc(size)); - *pic = buf_temp; - - // Load Palette - palette = m8_header->palette; - - // Image data - buffer = m8_file_buffer + m8_header->offsets[0]; - - - // Load texture into buffer - palette_ent = buffer; - for(i=0; i +#include +#include +#include "m8.h" + +void LoadM8(const char *name, unsigned char **pic, int *width, int *height) +{ + FILE *f; + m8_header_t *m8_header; + rgb_t *palette; + int i, num_pixels, size; + char text_buf[255] = { 0 }; + char *text_dot_pos; + unsigned int length; + unsigned char *palette_ent, *buf_temp; + unsigned char *buffer, *m8_file_buffer; + + strcpy(text_buf, name); + text_dot_pos = strchr(text_buf, '.'); + if (text_dot_pos) + *text_dot_pos = 0; + // Fix for .pcx.m8 extention + strcat(text_buf, ".pcx.m8"); + + // open file + if ( length = vfsLoadFile ((char *) text_buf, (void **) &m8_file_buffer) == (unsigned int) -1) + { + strcpy(text_buf, name); + for(i=(strlen(text_buf)-1); i>0; i--) + { + if(text_buf[i]=='.') + { + text_buf[i]=0; + break; + } + } + strcat(text_buf, ".m8"); + if ( length = vfsLoadFile ((char *) text_buf, (void **) &m8_file_buffer) == (unsigned int) -1) + { + Sys_Printf("Unable to open file %s\n",name); + return; + } + } + + m8_header = (m8_header_t *)m8_file_buffer; + + // make sure we have a valid M8 file + if ( m8_header->version != M8_VERSION) + { + vfsFreeFile(m8_file_buffer); + Sys_Printf("Invalid M8 file %s\n", name); + return; + } + + // Get M8 Info + *width = m8_header->width[0]; // Only interested in 1st MIP + *height = m8_header->height[0]; + num_pixels = (*width) * (*height); + size = num_pixels*4; + + // Allocate buffer + buf_temp = (unsigned char *)(g_malloc(size)); + *pic = buf_temp; + + // Load Palette + palette = m8_header->palette; + + // Image data + buffer = m8_file_buffer + m8_header->offsets[0]; + + + // Load texture into buffer + palette_ent = buffer; + for(i=0; i= 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(IMAGE_MAJOR, "png", sizeof(_QERPlugImageTable)); - g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); - // NOTE: if imagepng starts being used for non "VFS" "pk3" config, need to add a dynamic config chunk - // see: - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=794 - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=800 - g_SynapseClient.AddAPI(VFS_MAJOR, "pk3", sizeof(_QERFileSystemTable), SYN_REQUIRE, &g_FileSystemTable); - - return &g_SynapseClient; -} - -bool CSynapseClientImage::RequestAPI(APIDescriptor_t *pAPI) -{ - if (!strcmp(pAPI->major_name, IMAGE_MAJOR)) - { - _QERPlugImageTable* pTable= static_cast<_QERPlugImageTable*>(pAPI->mpTable); - if (!strcmp(pAPI->minor_name, "png")) - { - pTable->m_pfnLoadImage = &LoadImage; - return true; - } - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -#include "version.h" - -const char* CSynapseClientImage::GetInfo() -{ - return "PNG loader module built " __DATE__ " " RADIANT_VERSION; -} - - - -// ====== PNG loader functionality ====== - -#include "png.h" - -#ifdef __APPLE__ //tigital -#include -#endif - -void user_warning_fn(png_structp png_ptr, png_const_charp warning_msg) -{ - g_FuncTable.m_pfnSysPrintf ("libpng warning: %s\n", warning_msg); -} - -void user_error_fn(png_structp png_ptr, png_const_charp error_msg) -{ - g_FuncTable.m_pfnSysPrintf ("libpng error: %s\n", error_msg); - longjmp(png_ptr->jmpbuf, 0); -} - -void user_read_data(png_structp png_ptr, png_bytep data, png_uint_32 length) -{ - png_bytep *p_p_fbuffer = (png_bytep*)png_get_io_ptr(png_ptr); - memcpy(data, *p_p_fbuffer, length); - *p_p_fbuffer += length; -} - -void LoadImage (const char *filename, unsigned char **pic, int *width, int *height) -{ - png_byte** row_pointers; - unsigned char *fbuffer = NULL; - png_bytep p_fbuffer; - - int nLen = g_FileSystemTable.m_pfnLoadFile( (char *)filename, (void **)&fbuffer, 0 ); - if (nLen == -1) - return; - - p_fbuffer = fbuffer; - - // the reading glue - // http://www.libpng.org/pub/png/libpng-manual.html - - png_structp png_ptr = png_create_read_struct - (PNG_LIBPNG_VER_STRING, png_voidp_NULL, - user_error_fn, user_warning_fn); - if (!png_ptr) - { - g_FuncTable.m_pfnSysPrintf ("libpng error: png_create_read_struct\n"); - return; - } - - png_infop info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_read_struct(&png_ptr, - png_infopp_NULL, png_infopp_NULL); - g_FuncTable.m_pfnSysPrintf ("libpng error: png_create_info_struct (info_ptr)\n"); - return; - } - - png_infop end_info = png_create_info_struct(png_ptr); - if (!end_info) { - png_destroy_read_struct(&png_ptr, &info_ptr, - png_infopp_NULL); - g_FuncTable.m_pfnSysPrintf ("libpng error: png_create_info_struct (end_info)\n"); - return; - } - - // configure the read function - png_set_read_fn(png_ptr, (voidp)&p_fbuffer, (png_rw_ptr)&user_read_data); - - if (setjmp(png_ptr->jmpbuf)) { - png_destroy_read_struct(&png_ptr, &info_ptr, - &end_info); - if (*pic) - { - g_free(*pic); - free(row_pointers); - } - return; - } - - png_read_info(png_ptr, info_ptr); - - int bit_depth = png_get_bit_depth(png_ptr, info_ptr); - int color_type = png_get_color_type(png_ptr, info_ptr); - - // we want to treat all images the same way - // The following code transforms grayscale images of less than 8 to 8 bits, - // changes paletted images to RGB, and adds a full alpha channel if there is - // transparency information in a tRNS chunk. - if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_palette_to_rgb(png_ptr); - - if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) - png_set_gray_1_2_4_to_8(png_ptr); - - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) - png_set_tRNS_to_alpha(png_ptr); - - if ( ! ( color_type & PNG_COLOR_MASK_ALPHA ) ) { - // Set the background color to draw transparent and alpha images over. - png_color_16 my_background, *image_background; - - if (png_get_bKGD(png_ptr, info_ptr, &image_background)) - png_set_background(png_ptr, image_background, - PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); - else - png_set_background(png_ptr, &my_background, - PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); - - // Add alpha byte after each RGB triplet - png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); - } - - // read the sucker in one chunk - png_read_update_info(png_ptr, info_ptr); - - color_type = png_get_color_type(png_ptr, info_ptr); - bit_depth = png_get_bit_depth(png_ptr, info_ptr); - - *width = png_get_image_width(png_ptr, info_ptr); - *height = png_get_image_height(png_ptr, info_ptr); - - // allocate the pixel buffer, and the row pointers - int size = (*width)*(*height)*4; - // still have to use that g_malloc heresy - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=491 - *pic = (unsigned char *)g_malloc(size); - row_pointers = (png_byte**) malloc((*height) * sizeof(png_byte*)); - - int i; - for(i = 0; i < (*height); i++) - row_pointers[i] = (png_byte*)(*pic) + i * 4 * (*width); - - // actual read - png_read_image(png_ptr, row_pointers); - - /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ - png_read_end(png_ptr, info_ptr); - - /* free up the memory structure */ - png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); - - free(row_pointers); - g_FileSystemTable.m_pfnFreeFile (fbuffer); -} - - +/* +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 +*/ + +// ============================================================================= +// global tables + +#include "plugin.h" + +_QERFuncTable_1 g_FuncTable; +_QERFileSystemTable g_FileSystemTable; + +// ============================================================================= +// SYNAPSE + +#include "synapse.h" + +class CSynapseClientImage : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + + CSynapseClientImage() { } + virtual ~CSynapseClientImage() { } +}; + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientImage 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(IMAGE_MAJOR, "png", sizeof(_QERPlugImageTable)); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + // NOTE: if imagepng starts being used for non "VFS" "pk3" config, need to add a dynamic config chunk + // see: + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=794 + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=800 + g_SynapseClient.AddAPI(VFS_MAJOR, "pk3", sizeof(_QERFileSystemTable), SYN_REQUIRE, &g_FileSystemTable); + + return &g_SynapseClient; +} + +bool CSynapseClientImage::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, IMAGE_MAJOR)) + { + _QERPlugImageTable* pTable= static_cast<_QERPlugImageTable*>(pAPI->mpTable); + if (!strcmp(pAPI->minor_name, "png")) + { + pTable->m_pfnLoadImage = &LoadImage; + return true; + } + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientImage::GetInfo() +{ + return "PNG loader module built " __DATE__ " " RADIANT_VERSION; +} + + + +// ====== PNG loader functionality ====== + +#include "png.h" + +#ifdef __APPLE__ //tigital +#include +#endif + +void user_warning_fn(png_structp png_ptr, png_const_charp warning_msg) +{ + g_FuncTable.m_pfnSysPrintf ("libpng warning: %s\n", warning_msg); +} + +void user_error_fn(png_structp png_ptr, png_const_charp error_msg) +{ + g_FuncTable.m_pfnSysPrintf ("libpng error: %s\n", error_msg); + longjmp(png_ptr->jmpbuf, 0); +} + +void user_read_data(png_structp png_ptr, png_bytep data, png_uint_32 length) +{ + png_bytep *p_p_fbuffer = (png_bytep*)png_get_io_ptr(png_ptr); + memcpy(data, *p_p_fbuffer, length); + *p_p_fbuffer += length; +} + +void LoadImage (const char *filename, unsigned char **pic, int *width, int *height) +{ + png_byte** row_pointers; + unsigned char *fbuffer = NULL; + png_bytep p_fbuffer; + + int nLen = g_FileSystemTable.m_pfnLoadFile( (char *)filename, (void **)&fbuffer, 0 ); + if (nLen == -1) + return; + + p_fbuffer = fbuffer; + + // the reading glue + // http://www.libpng.org/pub/png/libpng-manual.html + + png_structp png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, png_voidp_NULL, + user_error_fn, user_warning_fn); + if (!png_ptr) + { + g_FuncTable.m_pfnSysPrintf ("libpng error: png_create_read_struct\n"); + return; + } + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_read_struct(&png_ptr, + png_infopp_NULL, png_infopp_NULL); + g_FuncTable.m_pfnSysPrintf ("libpng error: png_create_info_struct (info_ptr)\n"); + return; + } + + png_infop end_info = png_create_info_struct(png_ptr); + if (!end_info) { + png_destroy_read_struct(&png_ptr, &info_ptr, + png_infopp_NULL); + g_FuncTable.m_pfnSysPrintf ("libpng error: png_create_info_struct (end_info)\n"); + return; + } + + // configure the read function + png_set_read_fn(png_ptr, (voidp)&p_fbuffer, (png_rw_ptr)&user_read_data); + + if (setjmp(png_ptr->jmpbuf)) { + png_destroy_read_struct(&png_ptr, &info_ptr, + &end_info); + if (*pic) + { + g_free(*pic); + free(row_pointers); + } + return; + } + + png_read_info(png_ptr, info_ptr); + + int bit_depth = png_get_bit_depth(png_ptr, info_ptr); + int color_type = png_get_color_type(png_ptr, info_ptr); + + // we want to treat all images the same way + // The following code transforms grayscale images of less than 8 to 8 bits, + // changes paletted images to RGB, and adds a full alpha channel if there is + // transparency information in a tRNS chunk. + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png_ptr); + + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_gray_1_2_4_to_8(png_ptr); + + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha(png_ptr); + + if ( ! ( color_type & PNG_COLOR_MASK_ALPHA ) ) { + // Set the background color to draw transparent and alpha images over. + png_color_16 my_background, *image_background; + + if (png_get_bKGD(png_ptr, info_ptr, &image_background)) + png_set_background(png_ptr, image_background, + PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + else + png_set_background(png_ptr, &my_background, + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + + // Add alpha byte after each RGB triplet + png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); + } + + // read the sucker in one chunk + png_read_update_info(png_ptr, info_ptr); + + color_type = png_get_color_type(png_ptr, info_ptr); + bit_depth = png_get_bit_depth(png_ptr, info_ptr); + + *width = png_get_image_width(png_ptr, info_ptr); + *height = png_get_image_height(png_ptr, info_ptr); + + // allocate the pixel buffer, and the row pointers + int size = (*width)*(*height)*4; + // still have to use that g_malloc heresy + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=491 + *pic = (unsigned char *)g_malloc(size); + row_pointers = (png_byte**) malloc((*height) * sizeof(png_byte*)); + + int i; + for(i = 0; i < (*height); i++) + row_pointers[i] = (png_byte*)(*pic) + i * 4 * (*width); + + // actual read + png_read_image(png_ptr, row_pointers); + + /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ + png_read_end(png_ptr, info_ptr); + + /* free up the memory structure */ + png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); + + free(row_pointers); + g_FileSystemTable.m_pfnFreeFile (fbuffer); +} + + diff --git a/plugins/imagewal/imagewal.cpp b/plugins/imagewal/imagewal.cpp index af592f1e..400a1cd9 100644 --- a/plugins/imagewal/imagewal.cpp +++ b/plugins/imagewal/imagewal.cpp @@ -1,97 +1,97 @@ -/* -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 -*/ - -#include -#include "imagewal.h" - -// ============================================================================= -// global tables - -_QERFuncTable_1 g_FuncTable; // Radiant function table -_QERFileSystemTable g_FileSystemTable; - -// ============================================================================= -// SYNAPSE - -CSynapseServer* g_pSynapseServer = NULL; -CSynapseClientImage g_SynapseClient; - -static const XMLConfigEntry_t entries[] = - { - { VFS_MAJOR, SYN_REQUIRE, sizeof(_QERFileSystemTable), &g_FileSystemTable }, - { NULL, SYN_UNKNOWN, 0, NULL } }; - -#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(IMAGE_MAJOR, "wal", sizeof(_QERPlugImageTable)); - g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); - - if ( !g_SynapseClient.ConfigXML( pServer, NULL, entries ) ) { - return NULL; - } - - return &g_SynapseClient; -} - -bool CSynapseClientImage::RequestAPI(APIDescriptor_t *pAPI) -{ - if (!strcmp(pAPI->major_name, IMAGE_MAJOR )) - { - _QERPlugImageTable* pTable= static_cast<_QERPlugImageTable*>(pAPI->mpTable); - if (!strcmp(pAPI->minor_name, "wal")) - { - pTable->m_pfnLoadImage = &LoadWAL; - return true; - } - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -bool CSynapseClientImage::OnActivate() { - if (!g_FileSystemTable.m_nSize) { - Syn_Printf("ERROR: VFS_MAJOR table was not initialized before OnActivate in '%s' - incomplete synapse.config?\n", GetInfo()); - return false; - } - return true; -} - -#include "version.h" - -const char* CSynapseClientImage::GetInfo() -{ - return "WAL formats module built " __DATE__ " " RADIANT_VERSION; -} +/* +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 +*/ + +#include +#include "imagewal.h" + +// ============================================================================= +// global tables + +_QERFuncTable_1 g_FuncTable; // Radiant function table +_QERFileSystemTable g_FileSystemTable; + +// ============================================================================= +// SYNAPSE + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientImage g_SynapseClient; + +static const XMLConfigEntry_t entries[] = + { + { VFS_MAJOR, SYN_REQUIRE, sizeof(_QERFileSystemTable), &g_FileSystemTable }, + { NULL, SYN_UNKNOWN, 0, NULL } }; + +#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(IMAGE_MAJOR, "wal", sizeof(_QERPlugImageTable)); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + + if ( !g_SynapseClient.ConfigXML( pServer, NULL, entries ) ) { + return NULL; + } + + return &g_SynapseClient; +} + +bool CSynapseClientImage::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, IMAGE_MAJOR )) + { + _QERPlugImageTable* pTable= static_cast<_QERPlugImageTable*>(pAPI->mpTable); + if (!strcmp(pAPI->minor_name, "wal")) + { + pTable->m_pfnLoadImage = &LoadWAL; + return true; + } + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +bool CSynapseClientImage::OnActivate() { + if (!g_FileSystemTable.m_nSize) { + Syn_Printf("ERROR: VFS_MAJOR table was not initialized before OnActivate in '%s' - incomplete synapse.config?\n", GetInfo()); + return false; + } + return true; +} + +#include "version.h" + +const char* CSynapseClientImage::GetInfo() +{ + return "WAL formats module built " __DATE__ " " RADIANT_VERSION; +} diff --git a/plugins/imagewal/wal.cpp b/plugins/imagewal/wal.cpp index 03acb5d1..b46af62b 100644 --- a/plugins/imagewal/wal.cpp +++ b/plugins/imagewal/wal.cpp @@ -1,93 +1,93 @@ -/* -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 -*/ - -#include -#include -#include -#include "wal.h" - -#include "q2_palette.h" - -#define Sys_Printf g_FuncTable.m_pfnSysPrintf - -void LoadWAL(const char *name, unsigned char **pic, int *width, int *height) -{ - FILE *f; - miptex_t *wal_header; - rgb_t *palette; - int i, num_pixels, size; - char text_buf[255]; - unsigned int length; - unsigned char *palette_ent, *buf_temp; - unsigned char *buffer, *wal_file_buffer; - - // open file - if ( length = vfsLoadFile ((char *) name, (void **) &wal_file_buffer) == (unsigned int) -1) - { - Sys_Printf("Unable to open file %s\n",name); - return; - } - - wal_header = (miptex_t *)wal_file_buffer; - - // make sure we have a valid bitmap file - if ( wal_header->width & 15) - { - vfsFreeFile(wal_file_buffer); - Sys_Printf("Invalid WAL file %s: Width not multiple of 16!\n", name); - return; - } - - if ( wal_header->height & 15) - { - vfsFreeFile(wal_file_buffer); - Sys_Printf("Invalid WAL file %s: Height not multiple of 16!\n", name); - return; - } - - - // Get WAL Info - *width = wal_header->width; // Only interested in 1st MIP - *height = wal_header->height; - num_pixels = (*width) * (*height); - size = num_pixels*4; - - // Allocate buffer - buf_temp = (unsigned char *)(g_malloc(size)); - *pic = buf_temp; - - // Image data - buffer = wal_file_buffer + wal_header->offsets[0]; - - - // Load texture into buffer - palette_ent = buffer; - for(i=0; i +#include +#include +#include "wal.h" + +#include "q2_palette.h" + +#define Sys_Printf g_FuncTable.m_pfnSysPrintf + +void LoadWAL(const char *name, unsigned char **pic, int *width, int *height) +{ + FILE *f; + miptex_t *wal_header; + rgb_t *palette; + int i, num_pixels, size; + char text_buf[255]; + unsigned int length; + unsigned char *palette_ent, *buf_temp; + unsigned char *buffer, *wal_file_buffer; + + // open file + if ( length = vfsLoadFile ((char *) name, (void **) &wal_file_buffer) == (unsigned int) -1) + { + Sys_Printf("Unable to open file %s\n",name); + return; + } + + wal_header = (miptex_t *)wal_file_buffer; + + // make sure we have a valid bitmap file + if ( wal_header->width & 15) + { + vfsFreeFile(wal_file_buffer); + Sys_Printf("Invalid WAL file %s: Width not multiple of 16!\n", name); + return; + } + + if ( wal_header->height & 15) + { + vfsFreeFile(wal_file_buffer); + Sys_Printf("Invalid WAL file %s: Height not multiple of 16!\n", name); + return; + } + + + // Get WAL Info + *width = wal_header->width; // Only interested in 1st MIP + *height = wal_header->height; + num_pixels = (*width) * (*height); + size = num_pixels*4; + + // Allocate buffer + buf_temp = (unsigned char *)(g_malloc(size)); + *pic = buf_temp; + + // Image data + buffer = wal_file_buffer + wal_header->offsets[0]; + + + // Load texture into buffer + palette_ent = buffer; + for(i=0; idata); - l = g_slist_remove (l, l->data); - } -} - -// NOTE TTimo: ideally, this would be using Str functions instead -void trim( char *str) -{ - int len; - len = strlen(str); - while(str[--len] == ' ') - str[len] = 0; -} - -void BuildWadList( char *wadstr ) -{ - char wads[2048]; // change to CString usage ? - wads[0] = 0; - char *p1,*p2; - char cleanwadname[QER_MAX_NAMELEN]; - - g_WadList = NULL; - - strcpy(wads,wadstr); - QE_ConvertDOSToUnixName(wads,wads); - - // ok, we got the list of ; delimited wads, now split it into a GSList that contains - // just the wad names themselves. - - p1 = wads; - - do - { - p2 = strchr(p1,';'); - if (p2) - *p2 = 0; // swap the ; with a null terminator - - if (strchr(p1,'/') || strchr(p1,'\\')) - { - ExtractFileName(p1,cleanwadname); - - trim(cleanwadname); - - if (*cleanwadname) - { - g_WadList = g_slist_append (g_WadList, strdup(cleanwadname)); - Sys_Printf("wad: %s\n",cleanwadname); - } - } - else - { - trim(p1); - if (*p1) - { - g_WadList = g_slist_append (g_WadList, strdup(p1)); - Sys_Printf("wad: %s\n",p1); - } - } - if (p2) - p1 = p2+1; // point back to the remainder of the string - else - p1 = NULL; // make it so we exit the loop. - - } while (p1); - - // strip the ".wad" extensions. - for (GSList *l = g_WadList; l != NULL ; l = l->next) - { - p1 = (char *)l->data; - - if (p1[strlen(p1)-4] == '.') - p1[strlen(p1)-4] = 0; - } -} - -// FIXME: usefulness of this cache sounds very discutable -char *CheckCacheForTextureName( const char *cleantexturename ) -{ - char *str; - int len; - GSList *l; - - // search our little cache first to speed things up. - // cache strings are stored as ";" - len = strlen(cleantexturename); - for (l = g_TextureNameCache; l != NULL ; l = l->next) - { - str = (char *)l->data; - if ((strnicmp(cleantexturename,str,len) == 0) && (str[len] == ';')) // must do in this order or we'll get an access violation, even though it's slower. - { - return (str + len + 1); // skip the delimiter ; - } - } - return NULL; -} - -char *AddToCache(const char *cleantexturename, const char *actualname) -{ - char *cachestr; - cachestr = (char *)malloc(strlen(cleantexturename)+1+strlen(actualname)+1); // free()'d when g_TextureNameCache is freed - sprintf(cachestr,"%s;%s",cleantexturename,actualname); - g_TextureNameCache = g_slist_append (g_TextureNameCache, cachestr); - return cachestr; -} - -char *SearchWadsForTextureName( const char *cleantexturename ) -{ - char *str; - char *wadname; - char *actualtexturename = NULL; - GSList *l; - int count; - - actualtexturename = CheckCacheForTextureName(cleantexturename); - if (actualtexturename) - return actualtexturename; - - // still here ? guess it's not in the cache then! - - // search the wads listed in the worldspawn "wad" key - for (l = g_WadList; l != NULL && actualtexturename == NULL ; l = l->next) - { - wadname = (char *)l->data; - - str = new char[strlen(wadname)+strlen(cleantexturename)+9+1+4+1]; - - // hlw here is ok as we never have anything other than hlw files in a wad. - sprintf(str,"textures/%s/%s.hlw",wadname,cleantexturename); - count = vfsGetFileCount(str, VFS_SEARCH_PAK); // only search pack files - // LordHavoc: hacked in .mip loading here - if (!count) - { - sprintf(str,"textures/%s/%s.mip",wadname,cleantexturename); - count = vfsGetFileCount(str, VFS_SEARCH_PAK); // only search pack files - } - - if (count > 0) - { - // strip the extension, build the cache string and add the the cache - str[strlen(str)-4] = 0; - - actualtexturename = AddToCache(cleantexturename,str); - - //point the return value to the actual name, not what we add to the cache - actualtexturename += 1+strlen(cleantexturename); - } - delete [] str; - } - return actualtexturename; -} -// End of half-life specific stuff - -void Patch_Parse(patchMesh_t *pPatch) -{ - int i, j; - char *str; - - char *token = Token(); - - GetToken(true); //{ - - // parse shader name - GetToken(true); - str = new char[strlen(token)+10]; - strcpy(str, "textures/"); - strcpy(str+9, token); - pPatch->pShader = QERApp_Shader_ForName(str); - pPatch->d_texture = pPatch->pShader->getTexture(); - delete [] str; - - GetToken(true); //( - - // parse matrix dimensions - GetToken(false); - pPatch->width = atoi(token); - GetToken(false); - pPatch->height = atoi(token); - - // ignore contents/flags/value - GetToken(false); - GetToken(false); - GetToken(false); - - GetToken(false); //) - - // parse matrix - GetToken(true); //( - for(i=0; iwidth; i++) - { - GetToken(true); //( - for(j=0; jheight; j++) - { - GetToken(false); //( - - GetToken(false); - pPatch->ctrl[i][j].xyz[0] = atof(token); - GetToken(false); - pPatch->ctrl[i][j].xyz[1] = atof(token); - GetToken(false); - pPatch->ctrl[i][j].xyz[2] = atof(token); - GetToken(false); - pPatch->ctrl[i][j].st[0] = atof(token); - GetToken(false); - pPatch->ctrl[i][j].st[1] = atof(token); - - GetToken(false); //) - } - GetToken(false); //) - } - GetToken(true); //) - - GetToken(true); //} -} - -void Face_Parse (face_t *face, bool bAlternateTexdef = false) -{ - int i, j; - char *str; - bool bworldcraft = false; - - char *token = Token(); - - // parse planepts - str = NULL; - for(i=0; i<3; i++) - { - GetToken(true); //( - for(j=0; j<3; j++) - { - GetToken(false); - face->planepts[i][j] = atof(token); - } - GetToken(false); //) - } - - if(bAlternateTexdef) - { - // parse alternate texdef - GetToken (false); // ( - GetToken (false); // ( - for (i=0;i<3;i++) - { - GetToken(false); - face->brushprimit_texdef.coords[0][i]=atof(token); - } - GetToken (false); // ) - GetToken (false); // ( - for (i=0;i<3;i++) - { - GetToken(false); - face->brushprimit_texdef.coords[1][i]=atof(token); - } - GetToken (false); // ) - GetToken (false); // ) - } - - - // parse shader name - GetToken(false); // shader - - // if we're loading a halflife map then we don't have a relative texture name - // we just get . So we need to convert this to a relative name - // like this: "textures//shader", so we use vfsFileFile to get the filename. - - // *** IMPORTANT *** - // For Halflife we need to see if the texture is in wads listed in the - // map's worldspawn "wad" e-pair. If we don't then the image used will be the - // first image with this texture name that is found in any of the wads on the - // user's system. this is not a huge problem, because the map compiler obeys - // the "wad" epair when compiling the map, but the user might end up looking at - // the wrong texture in the editor. (more of a problem if the texture we use - // here has a different size from the one in the wad the map compiler uses...) - - // Hydra: - TTimo: I looked all over for other places to put this, but really it - // is an issue with map loading (because of a limitation of halflife/q2 map format) - // so it's gone in here, it also stops incorrect shader/texdef names getting used - // in the radiant core and it's modules which we'd only have to change later on. - // (either in map_importentities() or the shader module). so it's actually cleaner - // in the long run, even if a little odd. And it keeps more game specific stuff - // OUT of the core, which is a good thing. - - if (g_MapVersion == MAPVERSION_HL) - { - qboolean done = false; - - // FIXME: This bit is halflife specific. - // look in the list of wads supplied in the worldspawn "wad" key/pair for the - // texture first, if it's not in any then we carry on searching the vfs for it - // as usual. - - // each time we find a texture, we add it to the a cache - // so we don't have to hunt the vfs for it each time. - // See SearchWadsForTextureName() and AddToCache() above for cache stuff - - char *wadname; - wadname = SearchWadsForTextureName(token); - - if (wadname) - { - face->texdef.SetName(wadname); - done = true; - } - else - { - // using the cache below means that this message is only ever printed out once! - Sys_Printf("WARNING: could not find \"%s\" in any listed wad files, searching all wad files instead!\n",token); - } - // end of half-life specific bit. - - // check the cache! - if (!done) - { - str = CheckCacheForTextureName(token); - if (str) - { - face->texdef.SetName(str); - done = true; - } - } - - if (!done) - { - char *fullpath; - - str = new char[strlen(token)+4+1]; - - // FIXME: halflife specific file extension, we'll have to support Q2/Q1 formats - // and maybe tga texture format for HL here too.. - sprintf(str,"%s.hlw",token); - fullpath = vfsGetFullPath(str,0,VFS_SEARCH_PAK | VFS_SEARCH_DIR); - - // MIP support for quake - if (!fullpath) - { - sprintf(str,"%s.mip",token); - fullpath = vfsGetFullPath( str, 0, 0 ); - } - - // TGA support in halflife ? - /* - if (!fullpath) - { - sprintf(str,"%s.tga",token); - fullpath = vfsGetFullPath(str); - } - */ - delete [] str; - - if (fullpath) - { - // strip the extension. - int len = strlen(fullpath); - if (fullpath[len-4] == '.') - fullpath[len-4] = '\0'; - - // and set the correct name! - face->texdef.SetName(fullpath); - AddToCache(token,fullpath); - } - else - { - Sys_Printf("WARNING: could not find \"%s\" in the vfs search path\n",token); - str = new char[strlen(token)+10]; - strcpy(str, "textures/"); - strcpy(str+9, token); - face->texdef.SetName(str); - AddToCache(token,str); - delete [] str; - } - } - } - else // !MAPVERSION_HL - { - str = new char[strlen(token)+10]; - strcpy(str, "textures/"); - strcpy(str+9, token); - face->texdef.SetName(str); - delete [] str; - } - - if(!bAlternateTexdef) - { - if (g_MapVersion == MAPVERSION_HL) // Q1 as well ? - { - GetToken(false); - if (token[0] == '[' && token[1] == '\0') - { - bworldcraft = true; - - GetToken(false); // UAxis[0] - GetToken(false); // UAxis[1] - GetToken(false); // UAxis[2] - - GetToken(false); // shift - face->texdef.shift[0] = atof(token); - - GetToken(false); // ] - - GetToken(false); // [ - GetToken(false); // VAxis[0] - GetToken(false); // VAxis[1] - GetToken(false); // VAxis[2] - - GetToken(false); // shift - face->texdef.shift[1] = atof(token); - - GetToken(false); // ] - - // rotation is derived from the U and V axes. - // ZHLT ignores this setting even if present in a .map file. - GetToken(false); - face->texdef.rotate = atof(token); - - // Scales - GetToken(false); - face->texdef.scale[0] = atof(token); - GetToken(false); - face->texdef.scale[1] = atof(token); - } - else - { - UnGetToken(); - } - } - - if (!bworldcraft) // !MAPVERSION_HL - { - // parse texdef - GetToken(false); - face->texdef.shift[0] = atof(token); - GetToken(false); - face->texdef.shift[1] = atof(token); - GetToken(false); - face->texdef.rotate = atof(token); - GetToken(false); - face->texdef.scale[0] = atof(token); - GetToken(false); - face->texdef.scale[1] = atof(token); - } - } - // parse the optional contents/flags/value - if (!bworldcraft && TokenAvailable()) - { - GetToken(true); - if (isdigit(token[0])) - { - face->texdef.contents = atoi(token); - GetToken(false); - face->texdef.flags = atoi(token); - GetToken(false); - face->texdef.value = atoi(token); - } - else - { - UnGetToken(); - } - } -} - -bool Primitive_Parse(brush_t *pBrush) -{ - char *token = Token(); - - GetToken(true); - if (!strcmp(token, "patchDef2")) - { - pBrush->patchBrush = true; - pBrush->pPatch = Patch_Alloc(); - pBrush->pPatch->pSymbiot = pBrush; - Patch_Parse(pBrush->pPatch); - GetToken(true); //} - - // A patchdef should never be loaded from a quake2 map file - // so we just return false and the brush+patch gets freed - // and the user gets told. - if (g_MapVersion != MAPVERSION_Q3) - { - // FIXME: Hydra - I wanted to write out a line number here, but I can't because there's no API to access the core's "scriptline" variable. - Syn_Printf("ERROR: patchDef2's are not supported in Quake%d format .map files!\n",g_MapVersion); - abortcode = MAP_WRONGVERSION; - return false; - } - } - else if (!strcmp(token, "brushDef")) - { - pBrush->bBrushDef = true; - GetToken(true); // { - while(1) - { - face_t *f = pBrush->brush_faces; - pBrush->brush_faces = Face_Alloc(); - Face_Parse(pBrush->brush_faces, true); - pBrush->brush_faces->next = f; - // check for end of brush - GetToken(true); - if(strcmp(token,"}") == 0) - break; - UnGetToken(); - } - GetToken(true); // } - } - else - { - UnGetToken(); - while(1) - { - face_t *f = pBrush->brush_faces; - pBrush->brush_faces = Face_Alloc(); - Face_Parse(pBrush->brush_faces); - pBrush->brush_faces->next = f; - - // check for end of brush - GetToken(true); - if(strcmp(token,"}") == 0) - break; - UnGetToken(); - } - } - return true; -} - -void Entity_Parse(entity_t *pEntity) -{ - brush_t *pBrush; - CPtrArray *brushes = NULL; - char temptoken[1024]; - - char *token = Token(); - - while(1) - { - GetToken(true); // { or } or epair - if (!strcmp(token, "}")) { - break; - } else if(!strcmp(token, "{")) { - - pBrush = Brush_Alloc(); - if (Primitive_Parse(pBrush)) { - ((CPtrArray*)pEntity->pData)->Add(pBrush); - } else { - Brush_Free( pBrush, true ); - } - - } else { - - strcpy(temptoken, token); - GetToken(false); - - SetKeyValue(pEntity, temptoken, token); - - if (g_MapVersion == MAPVERSION_HL) { - // if we've not god a "wads" key/pair already, then break it into a list. - if (!g_WadList && (stricmp(temptoken,"wad") == 0)) { - BuildWadList(token); - } - } - - } - } -} - -void Map_Read (IDataStream *in, CPtrArray *map) -{ - entity_t *pEntity; - char *buf; - - unsigned long len = in->GetLength(); - buf = new char[len+1]; - in->Read(buf, len); - buf[len] = '\0'; - StartTokenParsing(buf); - abortcode = MAP_NOERROR; - - while(abortcode == MAP_NOERROR) - { - if (!GetToken (true)) // { or NULL - break; - pEntity = Entity_Alloc(); - pEntity->pData = new CPtrArray; - Entity_Parse(pEntity); - map->Add(pEntity); - } - - delete [] buf; - - if (abortcode != MAP_NOERROR) - { - int num_ents, num_brushes,i,j; - entity_t *e; - CPtrArray *brushes; - - num_ents = map->GetSize(); - for(i=0; iGetAt(i); - brushes = (CPtrArray*)e->pData; - num_brushes = brushes->GetSize(); - for(j=0; jGetAt(j), true ); - } - brushes->RemoveAll(); - delete brushes; - Entity_Free(e); - } - map->RemoveAll(); - } -} - -void Map_ReadQ3 (IDataStream *in, CPtrArray *map) -{ - g_MapVersion = MAPVERSION_Q3; - Map_Read(in,map); -} - -void Map_ReadHL (IDataStream *in, CPtrArray *map) -{ - g_WadList = NULL; - g_TextureNameCache = NULL; - - g_MapVersion = MAPVERSION_HL; - Map_Read(in,map); - - FreeGSList(g_TextureNameCache); - FreeGSList(g_WadList); -} - -void Map_ReadQ2 (IDataStream *in, CPtrArray *map) -{ - g_MapVersion = MAPVERSION_Q2; - Map_Read(in,map); -} +/* +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 +*/ + +// Hydra - FIXME : TTimo, We need to know what game + engine we're using for +// the halflife (not Q2) specific stuff +// we need an API for modules to get this info! + +// +// parses quake3 map format into internal objects +// + +#include "plugin.h" + +// cmdlib +extern void ExtractFileName (const char *path, char *dest); + +extern int g_MapVersion; +int abortcode; // see imap.h for values. + +// Start of half-life specific stuff + +GSList *g_WadList; // halflife specific. +GSList *g_TextureNameCache; // halflife specific. + +// NOTE TTimo: yuck.. +void FreeGSList( GSList *l ) +{ + while (l) + { + free (l->data); + l = g_slist_remove (l, l->data); + } +} + +// NOTE TTimo: ideally, this would be using Str functions instead +void trim( char *str) +{ + int len; + len = strlen(str); + while(str[--len] == ' ') + str[len] = 0; +} + +void BuildWadList( char *wadstr ) +{ + char wads[2048]; // change to CString usage ? + wads[0] = 0; + char *p1,*p2; + char cleanwadname[QER_MAX_NAMELEN]; + + g_WadList = NULL; + + strcpy(wads,wadstr); + QE_ConvertDOSToUnixName(wads,wads); + + // ok, we got the list of ; delimited wads, now split it into a GSList that contains + // just the wad names themselves. + + p1 = wads; + + do + { + p2 = strchr(p1,';'); + if (p2) + *p2 = 0; // swap the ; with a null terminator + + if (strchr(p1,'/') || strchr(p1,'\\')) + { + ExtractFileName(p1,cleanwadname); + + trim(cleanwadname); + + if (*cleanwadname) + { + g_WadList = g_slist_append (g_WadList, strdup(cleanwadname)); + Sys_Printf("wad: %s\n",cleanwadname); + } + } + else + { + trim(p1); + if (*p1) + { + g_WadList = g_slist_append (g_WadList, strdup(p1)); + Sys_Printf("wad: %s\n",p1); + } + } + if (p2) + p1 = p2+1; // point back to the remainder of the string + else + p1 = NULL; // make it so we exit the loop. + + } while (p1); + + // strip the ".wad" extensions. + for (GSList *l = g_WadList; l != NULL ; l = l->next) + { + p1 = (char *)l->data; + + if (p1[strlen(p1)-4] == '.') + p1[strlen(p1)-4] = 0; + } +} + +// FIXME: usefulness of this cache sounds very discutable +char *CheckCacheForTextureName( const char *cleantexturename ) +{ + char *str; + int len; + GSList *l; + + // search our little cache first to speed things up. + // cache strings are stored as ";" + len = strlen(cleantexturename); + for (l = g_TextureNameCache; l != NULL ; l = l->next) + { + str = (char *)l->data; + if ((strnicmp(cleantexturename,str,len) == 0) && (str[len] == ';')) // must do in this order or we'll get an access violation, even though it's slower. + { + return (str + len + 1); // skip the delimiter ; + } + } + return NULL; +} + +char *AddToCache(const char *cleantexturename, const char *actualname) +{ + char *cachestr; + cachestr = (char *)malloc(strlen(cleantexturename)+1+strlen(actualname)+1); // free()'d when g_TextureNameCache is freed + sprintf(cachestr,"%s;%s",cleantexturename,actualname); + g_TextureNameCache = g_slist_append (g_TextureNameCache, cachestr); + return cachestr; +} + +char *SearchWadsForTextureName( const char *cleantexturename ) +{ + char *str; + char *wadname; + char *actualtexturename = NULL; + GSList *l; + int count; + + actualtexturename = CheckCacheForTextureName(cleantexturename); + if (actualtexturename) + return actualtexturename; + + // still here ? guess it's not in the cache then! + + // search the wads listed in the worldspawn "wad" key + for (l = g_WadList; l != NULL && actualtexturename == NULL ; l = l->next) + { + wadname = (char *)l->data; + + str = new char[strlen(wadname)+strlen(cleantexturename)+9+1+4+1]; + + // hlw here is ok as we never have anything other than hlw files in a wad. + sprintf(str,"textures/%s/%s.hlw",wadname,cleantexturename); + count = vfsGetFileCount(str, VFS_SEARCH_PAK); // only search pack files + // LordHavoc: hacked in .mip loading here + if (!count) + { + sprintf(str,"textures/%s/%s.mip",wadname,cleantexturename); + count = vfsGetFileCount(str, VFS_SEARCH_PAK); // only search pack files + } + + if (count > 0) + { + // strip the extension, build the cache string and add the the cache + str[strlen(str)-4] = 0; + + actualtexturename = AddToCache(cleantexturename,str); + + //point the return value to the actual name, not what we add to the cache + actualtexturename += 1+strlen(cleantexturename); + } + delete [] str; + } + return actualtexturename; +} +// End of half-life specific stuff + +void Patch_Parse(patchMesh_t *pPatch) +{ + int i, j; + char *str; + + char *token = Token(); + + GetToken(true); //{ + + // parse shader name + GetToken(true); + str = new char[strlen(token)+10]; + strcpy(str, "textures/"); + strcpy(str+9, token); + pPatch->pShader = QERApp_Shader_ForName(str); + pPatch->d_texture = pPatch->pShader->getTexture(); + delete [] str; + + GetToken(true); //( + + // parse matrix dimensions + GetToken(false); + pPatch->width = atoi(token); + GetToken(false); + pPatch->height = atoi(token); + + // ignore contents/flags/value + GetToken(false); + GetToken(false); + GetToken(false); + + GetToken(false); //) + + // parse matrix + GetToken(true); //( + for(i=0; iwidth; i++) + { + GetToken(true); //( + for(j=0; jheight; j++) + { + GetToken(false); //( + + GetToken(false); + pPatch->ctrl[i][j].xyz[0] = atof(token); + GetToken(false); + pPatch->ctrl[i][j].xyz[1] = atof(token); + GetToken(false); + pPatch->ctrl[i][j].xyz[2] = atof(token); + GetToken(false); + pPatch->ctrl[i][j].st[0] = atof(token); + GetToken(false); + pPatch->ctrl[i][j].st[1] = atof(token); + + GetToken(false); //) + } + GetToken(false); //) + } + GetToken(true); //) + + GetToken(true); //} +} + +void Face_Parse (face_t *face, bool bAlternateTexdef = false) +{ + int i, j; + char *str; + bool bworldcraft = false; + + char *token = Token(); + + // parse planepts + str = NULL; + for(i=0; i<3; i++) + { + GetToken(true); //( + for(j=0; j<3; j++) + { + GetToken(false); + face->planepts[i][j] = atof(token); + } + GetToken(false); //) + } + + if(bAlternateTexdef) + { + // parse alternate texdef + GetToken (false); // ( + GetToken (false); // ( + for (i=0;i<3;i++) + { + GetToken(false); + face->brushprimit_texdef.coords[0][i]=atof(token); + } + GetToken (false); // ) + GetToken (false); // ( + for (i=0;i<3;i++) + { + GetToken(false); + face->brushprimit_texdef.coords[1][i]=atof(token); + } + GetToken (false); // ) + GetToken (false); // ) + } + + + // parse shader name + GetToken(false); // shader + + // if we're loading a halflife map then we don't have a relative texture name + // we just get . So we need to convert this to a relative name + // like this: "textures//shader", so we use vfsFileFile to get the filename. + + // *** IMPORTANT *** + // For Halflife we need to see if the texture is in wads listed in the + // map's worldspawn "wad" e-pair. If we don't then the image used will be the + // first image with this texture name that is found in any of the wads on the + // user's system. this is not a huge problem, because the map compiler obeys + // the "wad" epair when compiling the map, but the user might end up looking at + // the wrong texture in the editor. (more of a problem if the texture we use + // here has a different size from the one in the wad the map compiler uses...) + + // Hydra: - TTimo: I looked all over for other places to put this, but really it + // is an issue with map loading (because of a limitation of halflife/q2 map format) + // so it's gone in here, it also stops incorrect shader/texdef names getting used + // in the radiant core and it's modules which we'd only have to change later on. + // (either in map_importentities() or the shader module). so it's actually cleaner + // in the long run, even if a little odd. And it keeps more game specific stuff + // OUT of the core, which is a good thing. + + if (g_MapVersion == MAPVERSION_HL) + { + qboolean done = false; + + // FIXME: This bit is halflife specific. + // look in the list of wads supplied in the worldspawn "wad" key/pair for the + // texture first, if it's not in any then we carry on searching the vfs for it + // as usual. + + // each time we find a texture, we add it to the a cache + // so we don't have to hunt the vfs for it each time. + // See SearchWadsForTextureName() and AddToCache() above for cache stuff + + char *wadname; + wadname = SearchWadsForTextureName(token); + + if (wadname) + { + face->texdef.SetName(wadname); + done = true; + } + else + { + // using the cache below means that this message is only ever printed out once! + Sys_Printf("WARNING: could not find \"%s\" in any listed wad files, searching all wad files instead!\n",token); + } + // end of half-life specific bit. + + // check the cache! + if (!done) + { + str = CheckCacheForTextureName(token); + if (str) + { + face->texdef.SetName(str); + done = true; + } + } + + if (!done) + { + char *fullpath; + + str = new char[strlen(token)+4+1]; + + // FIXME: halflife specific file extension, we'll have to support Q2/Q1 formats + // and maybe tga texture format for HL here too.. + sprintf(str,"%s.hlw",token); + fullpath = vfsGetFullPath(str,0,VFS_SEARCH_PAK | VFS_SEARCH_DIR); + + // MIP support for quake + if (!fullpath) + { + sprintf(str,"%s.mip",token); + fullpath = vfsGetFullPath( str, 0, 0 ); + } + + // TGA support in halflife ? + /* + if (!fullpath) + { + sprintf(str,"%s.tga",token); + fullpath = vfsGetFullPath(str); + } + */ + delete [] str; + + if (fullpath) + { + // strip the extension. + int len = strlen(fullpath); + if (fullpath[len-4] == '.') + fullpath[len-4] = '\0'; + + // and set the correct name! + face->texdef.SetName(fullpath); + AddToCache(token,fullpath); + } + else + { + Sys_Printf("WARNING: could not find \"%s\" in the vfs search path\n",token); + str = new char[strlen(token)+10]; + strcpy(str, "textures/"); + strcpy(str+9, token); + face->texdef.SetName(str); + AddToCache(token,str); + delete [] str; + } + } + } + else // !MAPVERSION_HL + { + str = new char[strlen(token)+10]; + strcpy(str, "textures/"); + strcpy(str+9, token); + face->texdef.SetName(str); + delete [] str; + } + + if(!bAlternateTexdef) + { + if (g_MapVersion == MAPVERSION_HL) // Q1 as well ? + { + GetToken(false); + if (token[0] == '[' && token[1] == '\0') + { + bworldcraft = true; + + GetToken(false); // UAxis[0] + GetToken(false); // UAxis[1] + GetToken(false); // UAxis[2] + + GetToken(false); // shift + face->texdef.shift[0] = atof(token); + + GetToken(false); // ] + + GetToken(false); // [ + GetToken(false); // VAxis[0] + GetToken(false); // VAxis[1] + GetToken(false); // VAxis[2] + + GetToken(false); // shift + face->texdef.shift[1] = atof(token); + + GetToken(false); // ] + + // rotation is derived from the U and V axes. + // ZHLT ignores this setting even if present in a .map file. + GetToken(false); + face->texdef.rotate = atof(token); + + // Scales + GetToken(false); + face->texdef.scale[0] = atof(token); + GetToken(false); + face->texdef.scale[1] = atof(token); + } + else + { + UnGetToken(); + } + } + + if (!bworldcraft) // !MAPVERSION_HL + { + // parse texdef + GetToken(false); + face->texdef.shift[0] = atof(token); + GetToken(false); + face->texdef.shift[1] = atof(token); + GetToken(false); + face->texdef.rotate = atof(token); + GetToken(false); + face->texdef.scale[0] = atof(token); + GetToken(false); + face->texdef.scale[1] = atof(token); + } + } + // parse the optional contents/flags/value + if (!bworldcraft && TokenAvailable()) + { + GetToken(true); + if (isdigit(token[0])) + { + face->texdef.contents = atoi(token); + GetToken(false); + face->texdef.flags = atoi(token); + GetToken(false); + face->texdef.value = atoi(token); + } + else + { + UnGetToken(); + } + } +} + +bool Primitive_Parse(brush_t *pBrush) +{ + char *token = Token(); + + GetToken(true); + if (!strcmp(token, "patchDef2")) + { + pBrush->patchBrush = true; + pBrush->pPatch = Patch_Alloc(); + pBrush->pPatch->pSymbiot = pBrush; + Patch_Parse(pBrush->pPatch); + GetToken(true); //} + + // A patchdef should never be loaded from a quake2 map file + // so we just return false and the brush+patch gets freed + // and the user gets told. + if (g_MapVersion != MAPVERSION_Q3) + { + // FIXME: Hydra - I wanted to write out a line number here, but I can't because there's no API to access the core's "scriptline" variable. + Syn_Printf("ERROR: patchDef2's are not supported in Quake%d format .map files!\n",g_MapVersion); + abortcode = MAP_WRONGVERSION; + return false; + } + } + else if (!strcmp(token, "brushDef")) + { + pBrush->bBrushDef = true; + GetToken(true); // { + while(1) + { + face_t *f = pBrush->brush_faces; + pBrush->brush_faces = Face_Alloc(); + Face_Parse(pBrush->brush_faces, true); + pBrush->brush_faces->next = f; + // check for end of brush + GetToken(true); + if(strcmp(token,"}") == 0) + break; + UnGetToken(); + } + GetToken(true); // } + } + else + { + UnGetToken(); + while(1) + { + face_t *f = pBrush->brush_faces; + pBrush->brush_faces = Face_Alloc(); + Face_Parse(pBrush->brush_faces); + pBrush->brush_faces->next = f; + + // check for end of brush + GetToken(true); + if(strcmp(token,"}") == 0) + break; + UnGetToken(); + } + } + return true; +} + +void Entity_Parse(entity_t *pEntity) +{ + brush_t *pBrush; + CPtrArray *brushes = NULL; + char temptoken[1024]; + + char *token = Token(); + + while(1) + { + GetToken(true); // { or } or epair + if (!strcmp(token, "}")) { + break; + } else if(!strcmp(token, "{")) { + + pBrush = Brush_Alloc(); + if (Primitive_Parse(pBrush)) { + ((CPtrArray*)pEntity->pData)->Add(pBrush); + } else { + Brush_Free( pBrush, true ); + } + + } else { + + strcpy(temptoken, token); + GetToken(false); + + SetKeyValue(pEntity, temptoken, token); + + if (g_MapVersion == MAPVERSION_HL) { + // if we've not god a "wads" key/pair already, then break it into a list. + if (!g_WadList && (stricmp(temptoken,"wad") == 0)) { + BuildWadList(token); + } + } + + } + } +} + +void Map_Read (IDataStream *in, CPtrArray *map) +{ + entity_t *pEntity; + char *buf; + + unsigned long len = in->GetLength(); + buf = new char[len+1]; + in->Read(buf, len); + buf[len] = '\0'; + StartTokenParsing(buf); + abortcode = MAP_NOERROR; + + while(abortcode == MAP_NOERROR) + { + if (!GetToken (true)) // { or NULL + break; + pEntity = Entity_Alloc(); + pEntity->pData = new CPtrArray; + Entity_Parse(pEntity); + map->Add(pEntity); + } + + delete [] buf; + + if (abortcode != MAP_NOERROR) + { + int num_ents, num_brushes,i,j; + entity_t *e; + CPtrArray *brushes; + + num_ents = map->GetSize(); + for(i=0; iGetAt(i); + brushes = (CPtrArray*)e->pData; + num_brushes = brushes->GetSize(); + for(j=0; jGetAt(j), true ); + } + brushes->RemoveAll(); + delete brushes; + Entity_Free(e); + } + map->RemoveAll(); + } +} + +void Map_ReadQ3 (IDataStream *in, CPtrArray *map) +{ + g_MapVersion = MAPVERSION_Q3; + Map_Read(in,map); +} + +void Map_ReadHL (IDataStream *in, CPtrArray *map) +{ + g_WadList = NULL; + g_TextureNameCache = NULL; + + g_MapVersion = MAPVERSION_HL; + Map_Read(in,map); + + FreeGSList(g_TextureNameCache); + FreeGSList(g_WadList); +} + +void Map_ReadQ2 (IDataStream *in, CPtrArray *map) +{ + g_MapVersion = MAPVERSION_Q2; + Map_Read(in,map); +} diff --git a/plugins/map/plugin.cpp b/plugins/map/plugin.cpp index d5b722d6..1a7def7a 100644 --- a/plugins/map/plugin.cpp +++ b/plugins/map/plugin.cpp @@ -1,134 +1,134 @@ -/* -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 -*/ - -#include "plugin.h" - -// ============================================================================= -// Globals - -// function tables -_QERFuncTable_1 g_FuncTable; -_QERScripLibTable g_ScripLibTable; -_QERShadersTable g_ShadersTable; -_QEREntityTable __ENTITYTABLENAME; -_QERBrushTable g_BrushTable; -_QERPatchTable g_PatchTable; -_QERFileSystemTable g_FileSystemTable; -/*! -the map version we have been initialized with: Q1/Q2/Q3 -we provide all three formats in the same module -*/ -int g_MapVersion; - -// ============================================================================= -// SYNAPSE - -CSynapseServer* g_pSynapseServer = NULL; -CSynapseClientMap g_SynapseClient; - -static const XMLConfigEntry_t entries[] = - { - { SHADERS_MAJOR, SYN_REQUIRE, sizeof(g_ShadersTable), &g_ShadersTable }, - { NULL, SYN_UNKNOWN, 0, NULL } }; - -#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(MAP_MAJOR, "mapq3", sizeof(_QERPlugMapTable)); - g_SynapseClient.AddAPI(MAP_MAJOR, "maphl", sizeof(_QERPlugMapTable)); - g_SynapseClient.AddAPI(MAP_MAJOR, "mapq2", sizeof(_QERPlugMapTable)); - g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable); - g_SynapseClient.AddAPI(SCRIPLIB_MAJOR, NULL, sizeof(g_ScripLibTable), SYN_REQUIRE, &g_ScripLibTable); - - // same trick as bobtoolz, see bug #828 - g_SynapseClient.AddAPI( VFS_MAJOR, "*", sizeof(g_FileSystemTable), SYN_REQUIRE, &g_FileSystemTable ); - - if ( !g_SynapseClient.ConfigXML( pServer, NULL, entries ) ) { - return NULL; - } - - g_SynapseClient.AddAPI(ENTITY_MAJOR, NULL, sizeof(__ENTITYTABLENAME), SYN_REQUIRE, &__ENTITYTABLENAME); - g_SynapseClient.AddAPI(BRUSH_MAJOR, NULL, sizeof(g_BrushTable), SYN_REQUIRE, &g_BrushTable); - g_SynapseClient.AddAPI(PATCH_MAJOR, NULL, sizeof(g_PatchTable), SYN_REQUIRE, &g_PatchTable); - - return &g_SynapseClient; -} - -bool CSynapseClientMap::RequestAPI(APIDescriptor_t *pAPI) -{ - if (!strcmp(pAPI->major_name, MAP_MAJOR)) - { - _QERPlugMapTable* pTable= static_cast<_QERPlugMapTable*>(pAPI->mpTable); - if (!strcmp(pAPI->minor_name, "mapq3")) - { - pTable->m_pfnMap_Read = &Map_ReadQ3; - pTable->m_pfnMap_Write = &Map_WriteQ3; - return true; - } - if (!strcmp(pAPI->minor_name, "maphl")) - { - pTable->m_pfnMap_Read = &Map_ReadHL; - pTable->m_pfnMap_Write = &Map_WriteHL; - mbMapHL = true; - return true; - } - if (!strcmp(pAPI->minor_name, "mapq2")) - { - pTable->m_pfnMap_Read = &Map_ReadQ2; - pTable->m_pfnMap_Write = &Map_WriteQ2; - return true; - } - Syn_Printf("ERROR: RequestAPI( Major: '%s' Minor: '%s' ) not found in '%s'\n", pAPI->major_name, pAPI->minor_name, GetInfo()); - return false; - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -bool CSynapseClientMap::OnActivate() { - return true; -} - -#include "version.h" - -const char* CSynapseClientMap::GetInfo() -{ - return "MAP format module built " __DATE__ " " RADIANT_VERSION; -} - -const char* CSynapseClientMap::GetName() -{ - return "map"; -} +/* +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 +*/ + +#include "plugin.h" + +// ============================================================================= +// Globals + +// function tables +_QERFuncTable_1 g_FuncTable; +_QERScripLibTable g_ScripLibTable; +_QERShadersTable g_ShadersTable; +_QEREntityTable __ENTITYTABLENAME; +_QERBrushTable g_BrushTable; +_QERPatchTable g_PatchTable; +_QERFileSystemTable g_FileSystemTable; +/*! +the map version we have been initialized with: Q1/Q2/Q3 +we provide all three formats in the same module +*/ +int g_MapVersion; + +// ============================================================================= +// SYNAPSE + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientMap g_SynapseClient; + +static const XMLConfigEntry_t entries[] = + { + { SHADERS_MAJOR, SYN_REQUIRE, sizeof(g_ShadersTable), &g_ShadersTable }, + { NULL, SYN_UNKNOWN, 0, NULL } }; + +#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(MAP_MAJOR, "mapq3", sizeof(_QERPlugMapTable)); + g_SynapseClient.AddAPI(MAP_MAJOR, "maphl", sizeof(_QERPlugMapTable)); + g_SynapseClient.AddAPI(MAP_MAJOR, "mapq2", sizeof(_QERPlugMapTable)); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(SCRIPLIB_MAJOR, NULL, sizeof(g_ScripLibTable), SYN_REQUIRE, &g_ScripLibTable); + + // same trick as bobtoolz, see bug #828 + g_SynapseClient.AddAPI( VFS_MAJOR, "*", sizeof(g_FileSystemTable), SYN_REQUIRE, &g_FileSystemTable ); + + if ( !g_SynapseClient.ConfigXML( pServer, NULL, entries ) ) { + return NULL; + } + + g_SynapseClient.AddAPI(ENTITY_MAJOR, NULL, sizeof(__ENTITYTABLENAME), SYN_REQUIRE, &__ENTITYTABLENAME); + g_SynapseClient.AddAPI(BRUSH_MAJOR, NULL, sizeof(g_BrushTable), SYN_REQUIRE, &g_BrushTable); + g_SynapseClient.AddAPI(PATCH_MAJOR, NULL, sizeof(g_PatchTable), SYN_REQUIRE, &g_PatchTable); + + return &g_SynapseClient; +} + +bool CSynapseClientMap::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, MAP_MAJOR)) + { + _QERPlugMapTable* pTable= static_cast<_QERPlugMapTable*>(pAPI->mpTable); + if (!strcmp(pAPI->minor_name, "mapq3")) + { + pTable->m_pfnMap_Read = &Map_ReadQ3; + pTable->m_pfnMap_Write = &Map_WriteQ3; + return true; + } + if (!strcmp(pAPI->minor_name, "maphl")) + { + pTable->m_pfnMap_Read = &Map_ReadHL; + pTable->m_pfnMap_Write = &Map_WriteHL; + mbMapHL = true; + return true; + } + if (!strcmp(pAPI->minor_name, "mapq2")) + { + pTable->m_pfnMap_Read = &Map_ReadQ2; + pTable->m_pfnMap_Write = &Map_WriteQ2; + return true; + } + Syn_Printf("ERROR: RequestAPI( Major: '%s' Minor: '%s' ) not found in '%s'\n", pAPI->major_name, pAPI->minor_name, GetInfo()); + return false; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +bool CSynapseClientMap::OnActivate() { + return true; +} + +#include "version.h" + +const char* CSynapseClientMap::GetInfo() +{ + return "MAP format module built " __DATE__ " " RADIANT_VERSION; +} + +const char* CSynapseClientMap::GetName() +{ + return "map"; +} diff --git a/plugins/map/write.cpp b/plugins/map/write.cpp index d4198db4..fb0700e2 100644 --- a/plugins/map/write.cpp +++ b/plugins/map/write.cpp @@ -1,227 +1,227 @@ -/* -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 -*/ - -// -// writes quake3 map format from internal objects -// - -static int g_count_entities; -static int g_count_brushes; - -#include "plugin.h" -extern int g_MapVersion; - -void Float_Write(float data, IDataStream *out) -{ - if (data == (int)data) - out->printf("%i ", (int)data); - else - out->printf("%f ", data); -} - -void Patch_Write(patchMesh_t *pPatch, IDataStream *out) -{ - int i, j; - const char *str; - - // write shader name and matrix dimensions - str = pPatch->pShader->getName(); - if (strchr(str, ' ')) - { - Sys_FPrintf(SYS_WRN, "WARNING: Patch_Write: shader names with spaces are not allowed, ignoring '%s'\n", str); - str = SHADER_NOT_FOUND; - } - if(!strncmp(str, "textures/", 9)) str+=9; - out->printf("patchDef2\n{\n%s\n( %i %i 0 0 0 )\n", - str, pPatch->width, pPatch->height); - - // write matrix - out->printf("(\n"); - for(i=0; iwidth; i++) - { - out->printf("( "); - for(j=0; jheight; j++) - { - out->printf("( "); - - Float_Write(pPatch->ctrl[i][j].xyz[0], out); - Float_Write(pPatch->ctrl[i][j].xyz[1], out); - Float_Write(pPatch->ctrl[i][j].xyz[2], out); - Float_Write(pPatch->ctrl[i][j].st[0], out); - Float_Write(pPatch->ctrl[i][j].st[1], out); - - out->printf(") "); - } - out->printf(")\n"); - } - out->printf(")\n}\n"); -} - -void Face_Write (face_t *face, IDataStream *out, bool bAlternateTexdef = false) -{ - int i, j; - const char *str; - - // write planepts - for(i=0; i<3; i++) - { - out->printf("( "); - for(j=0; j<3; j++) - { - Float_Write(face->planepts[i][j], out); - } - out->printf(") "); - } - - if(bAlternateTexdef) - { - // write alternate texdef - out->printf("( ( "); - for (i=0;i<3;i++) - Float_Write(face->brushprimit_texdef.coords[0][i], out); - out->printf(") ( "); - for (i=0;i<3;i++) - Float_Write(face->brushprimit_texdef.coords[1][i], out); - out->printf(") ) "); - } - - // write shader name - str = face->texdef.GetName(); - if (strchr(str, ' ')) - { - Sys_FPrintf(SYS_WRN, "WARNING: Face_Write: shader names with spaces are not allowed, ignoring '%s'\n", str); - str = SHADER_NOT_FOUND; - } - if(!strncmp(str, "textures/", 9)) str+=9; - - // Strip all remaining paths. - // FIXME: Hydra - this is actually a HalfLife specific bit, not Q2 map format specific. - if (g_MapVersion == MAPVERSION_HL) - { - char *pos; - while ( pos = (char*)strchr( str, '/' ) ) { - str = pos+1; // to speed optimize, change the "while" to an "if" - } - } - out->printf("%s ", str); - - if(!bAlternateTexdef) - { - // write texdef - out->printf("%i %i %i %f %f ", - (int)face->texdef.shift[0], - (int)face->texdef.shift[1], - (int)face->texdef.rotate, - face->texdef.scale[0], - face->texdef.scale[1]); - } - - if (g_MapVersion == MAPVERSION_Q3) - { - // write surface flags - out->printf("%i %i %i\n", - face->texdef.contents, - face->texdef.flags, - face->texdef.value); - } - - if ( (g_MapVersion == MAPVERSION_HL) || (g_MapVersion == MAPVERSION_Q2) ) - { - // write surface flags if non-zero values. - if (face->texdef.contents || face->texdef.flags || face->texdef.value) - { - out->printf("%i %i %i\n", - face->texdef.contents, - face->texdef.flags, - face->texdef.value); - } - else - { - out->printf("\n"); - } - } - -} - -void Primitive_Write (brush_t *pBrush, IDataStream *out) -{ - if ( (g_MapVersion == MAPVERSION_Q2) && (pBrush->patchBrush) ) - { - Sys_FPrintf(SYS_WRN, "WARNING: Primitive_Write: Patches are not supported in Quake2, ignoring Brush %d\n", g_count_brushes++); - } - else - { - out->printf("// brush %i\n", g_count_brushes++); - out->printf("{\n"); - if(pBrush->patchBrush) - Patch_Write(pBrush->pPatch, out); - else if(pBrush->bBrushDef) - { - out->printf("brushDef\n{\n"); - for(face_t *face = pBrush->brush_faces; face != NULL; face = face->next) - Face_Write (face, out, true); - out->printf("}\n"); - } - else - for(face_t *face = pBrush->brush_faces; face != NULL; face = face->next) - Face_Write (face, out); - out->printf("}\n"); - } -} - -void Entity_Write(entity_t *pEntity, IDataStream *out) -{ - epair_t *pEpair; - CPtrArray *brushes = (CPtrArray*)pEntity->pData; - out->printf("// entity %i\n", g_count_entities++); - out->printf("{\n"); - for(pEpair = pEntity->epairs; pEpair != NULL; pEpair = pEpair->next) - out->printf("\"%s\" \"%s\"\n", pEpair->key, pEpair->value); - g_count_brushes = 0; - for(int i=0; iGetSize(); i++) - Primitive_Write((brush_t*)brushes->GetAt(i), out); - out->printf("}\n"); -} - -void Map_Write (CPtrArray *map, IDataStream *out) -{ - g_count_entities = 0; - for(int i=0; iGetSize(); i++) - Entity_Write((entity_t*)map->GetAt(i), out); -} - -void Map_WriteQ3 (CPtrArray *map, IDataStream *out) -{ - g_MapVersion = MAPVERSION_Q3; - Map_Write (map,out); -} - -void Map_WriteHL (CPtrArray *map, IDataStream *out) -{ - g_MapVersion = MAPVERSION_HL; - Map_Write (map,out); -} - -void Map_WriteQ2 (CPtrArray *map, IDataStream *out) -{ - g_MapVersion = MAPVERSION_Q2; - Map_Write (map,out); -} +/* +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 +*/ + +// +// writes quake3 map format from internal objects +// + +static int g_count_entities; +static int g_count_brushes; + +#include "plugin.h" +extern int g_MapVersion; + +void Float_Write(float data, IDataStream *out) +{ + if (data == (int)data) + out->printf("%i ", (int)data); + else + out->printf("%f ", data); +} + +void Patch_Write(patchMesh_t *pPatch, IDataStream *out) +{ + int i, j; + const char *str; + + // write shader name and matrix dimensions + str = pPatch->pShader->getName(); + if (strchr(str, ' ')) + { + Sys_FPrintf(SYS_WRN, "WARNING: Patch_Write: shader names with spaces are not allowed, ignoring '%s'\n", str); + str = SHADER_NOT_FOUND; + } + if(!strncmp(str, "textures/", 9)) str+=9; + out->printf("patchDef2\n{\n%s\n( %i %i 0 0 0 )\n", + str, pPatch->width, pPatch->height); + + // write matrix + out->printf("(\n"); + for(i=0; iwidth; i++) + { + out->printf("( "); + for(j=0; jheight; j++) + { + out->printf("( "); + + Float_Write(pPatch->ctrl[i][j].xyz[0], out); + Float_Write(pPatch->ctrl[i][j].xyz[1], out); + Float_Write(pPatch->ctrl[i][j].xyz[2], out); + Float_Write(pPatch->ctrl[i][j].st[0], out); + Float_Write(pPatch->ctrl[i][j].st[1], out); + + out->printf(") "); + } + out->printf(")\n"); + } + out->printf(")\n}\n"); +} + +void Face_Write (face_t *face, IDataStream *out, bool bAlternateTexdef = false) +{ + int i, j; + const char *str; + + // write planepts + for(i=0; i<3; i++) + { + out->printf("( "); + for(j=0; j<3; j++) + { + Float_Write(face->planepts[i][j], out); + } + out->printf(") "); + } + + if(bAlternateTexdef) + { + // write alternate texdef + out->printf("( ( "); + for (i=0;i<3;i++) + Float_Write(face->brushprimit_texdef.coords[0][i], out); + out->printf(") ( "); + for (i=0;i<3;i++) + Float_Write(face->brushprimit_texdef.coords[1][i], out); + out->printf(") ) "); + } + + // write shader name + str = face->texdef.GetName(); + if (strchr(str, ' ')) + { + Sys_FPrintf(SYS_WRN, "WARNING: Face_Write: shader names with spaces are not allowed, ignoring '%s'\n", str); + str = SHADER_NOT_FOUND; + } + if(!strncmp(str, "textures/", 9)) str+=9; + + // Strip all remaining paths. + // FIXME: Hydra - this is actually a HalfLife specific bit, not Q2 map format specific. + if (g_MapVersion == MAPVERSION_HL) + { + char *pos; + while ( pos = (char*)strchr( str, '/' ) ) { + str = pos+1; // to speed optimize, change the "while" to an "if" + } + } + out->printf("%s ", str); + + if(!bAlternateTexdef) + { + // write texdef + out->printf("%i %i %i %f %f ", + (int)face->texdef.shift[0], + (int)face->texdef.shift[1], + (int)face->texdef.rotate, + face->texdef.scale[0], + face->texdef.scale[1]); + } + + if (g_MapVersion == MAPVERSION_Q3) + { + // write surface flags + out->printf("%i %i %i\n", + face->texdef.contents, + face->texdef.flags, + face->texdef.value); + } + + if ( (g_MapVersion == MAPVERSION_HL) || (g_MapVersion == MAPVERSION_Q2) ) + { + // write surface flags if non-zero values. + if (face->texdef.contents || face->texdef.flags || face->texdef.value) + { + out->printf("%i %i %i\n", + face->texdef.contents, + face->texdef.flags, + face->texdef.value); + } + else + { + out->printf("\n"); + } + } + +} + +void Primitive_Write (brush_t *pBrush, IDataStream *out) +{ + if ( (g_MapVersion == MAPVERSION_Q2) && (pBrush->patchBrush) ) + { + Sys_FPrintf(SYS_WRN, "WARNING: Primitive_Write: Patches are not supported in Quake2, ignoring Brush %d\n", g_count_brushes++); + } + else + { + out->printf("// brush %i\n", g_count_brushes++); + out->printf("{\n"); + if(pBrush->patchBrush) + Patch_Write(pBrush->pPatch, out); + else if(pBrush->bBrushDef) + { + out->printf("brushDef\n{\n"); + for(face_t *face = pBrush->brush_faces; face != NULL; face = face->next) + Face_Write (face, out, true); + out->printf("}\n"); + } + else + for(face_t *face = pBrush->brush_faces; face != NULL; face = face->next) + Face_Write (face, out); + out->printf("}\n"); + } +} + +void Entity_Write(entity_t *pEntity, IDataStream *out) +{ + epair_t *pEpair; + CPtrArray *brushes = (CPtrArray*)pEntity->pData; + out->printf("// entity %i\n", g_count_entities++); + out->printf("{\n"); + for(pEpair = pEntity->epairs; pEpair != NULL; pEpair = pEpair->next) + out->printf("\"%s\" \"%s\"\n", pEpair->key, pEpair->value); + g_count_brushes = 0; + for(int i=0; iGetSize(); i++) + Primitive_Write((brush_t*)brushes->GetAt(i), out); + out->printf("}\n"); +} + +void Map_Write (CPtrArray *map, IDataStream *out) +{ + g_count_entities = 0; + for(int i=0; iGetSize(); i++) + Entity_Write((entity_t*)map->GetAt(i), out); +} + +void Map_WriteQ3 (CPtrArray *map, IDataStream *out) +{ + g_MapVersion = MAPVERSION_Q3; + Map_Write (map,out); +} + +void Map_WriteHL (CPtrArray *map, IDataStream *out) +{ + g_MapVersion = MAPVERSION_HL; + Map_Write (map,out); +} + +void Map_WriteQ2 (CPtrArray *map, IDataStream *out) +{ + g_MapVersion = MAPVERSION_Q2; + Map_Write (map,out); +} diff --git a/plugins/mapxml/plugin.cpp b/plugins/mapxml/plugin.cpp index 205649c2..e66f52cd 100644 --- a/plugins/mapxml/plugin.cpp +++ b/plugins/mapxml/plugin.cpp @@ -1,78 +1,78 @@ -#include "plugin.h" - -// ============================================================================= -// Globals - -// function tables -_QERFuncTable_1 g_FuncTable; -_QERShadersTable g_ShadersTable; -_QEREntityTable g_EntityTable; -_QERBrushTable g_BrushTable; -_QERPatchTable g_PatchTable; - -// ============================================================================= -// SYNAPSE - -CSynapseServer* g_pSynapseServer = NULL; -CSynapseClientXMap g_SynapseClient; - -static const XMLConfigEntry_t entries[] = - { - { SHADERS_MAJOR, SYN_REQUIRE, sizeof(g_ShadersTable), &g_ShadersTable }, - { NULL, SYN_UNKNOWN, 0, NULL } }; - -#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(MAP_MAJOR, "mapxml", sizeof(_QERPlugMapTable)); - g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); - g_SynapseClient.AddAPI(ENTITY_MAJOR, NULL, sizeof(g_EntityTable), SYN_REQUIRE, &g_EntityTable); - g_SynapseClient.AddAPI(BRUSH_MAJOR, NULL, sizeof(g_BrushTable), SYN_REQUIRE, &g_BrushTable); - g_SynapseClient.AddAPI(PATCH_MAJOR, NULL, sizeof(g_PatchTable), SYN_REQUIRE, &g_PatchTable); - - if ( !g_SynapseClient.ConfigXML( pServer, NULL, entries ) ) { - return NULL; - } - - return &g_SynapseClient; -} - -bool CSynapseClientXMap::RequestAPI(APIDescriptor_t *pAPI) -{ - if (!strcmp(pAPI->major_name, MAP_MAJOR)) - { - _QERPlugMapTable* pTable= static_cast<_QERPlugMapTable*>(pAPI->mpTable); - pTable->m_pfnMap_Read = &Map_Read; - pTable->m_pfnMap_Write = &Map_Write; - - return true; - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -#include "version.h" - -const char* CSynapseClientXMap::GetInfo() -{ - return "XMAP module built " __DATE__ " " RADIANT_VERSION; -} - -const char* CSynapseClientXMap::GetName() -{ - return "xmap"; -} +#include "plugin.h" + +// ============================================================================= +// Globals + +// function tables +_QERFuncTable_1 g_FuncTable; +_QERShadersTable g_ShadersTable; +_QEREntityTable g_EntityTable; +_QERBrushTable g_BrushTable; +_QERPatchTable g_PatchTable; + +// ============================================================================= +// SYNAPSE + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientXMap g_SynapseClient; + +static const XMLConfigEntry_t entries[] = + { + { SHADERS_MAJOR, SYN_REQUIRE, sizeof(g_ShadersTable), &g_ShadersTable }, + { NULL, SYN_UNKNOWN, 0, NULL } }; + +#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(MAP_MAJOR, "mapxml", sizeof(_QERPlugMapTable)); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(ENTITY_MAJOR, NULL, sizeof(g_EntityTable), SYN_REQUIRE, &g_EntityTable); + g_SynapseClient.AddAPI(BRUSH_MAJOR, NULL, sizeof(g_BrushTable), SYN_REQUIRE, &g_BrushTable); + g_SynapseClient.AddAPI(PATCH_MAJOR, NULL, sizeof(g_PatchTable), SYN_REQUIRE, &g_PatchTable); + + if ( !g_SynapseClient.ConfigXML( pServer, NULL, entries ) ) { + return NULL; + } + + return &g_SynapseClient; +} + +bool CSynapseClientXMap::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, MAP_MAJOR)) + { + _QERPlugMapTable* pTable= static_cast<_QERPlugMapTable*>(pAPI->mpTable); + pTable->m_pfnMap_Read = &Map_Read; + pTable->m_pfnMap_Write = &Map_Write; + + return true; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientXMap::GetInfo() +{ + return "XMAP module built " __DATE__ " " RADIANT_VERSION; +} + +const char* CSynapseClientXMap::GetName() +{ + return "xmap"; +} diff --git a/plugins/mapxml/xmlparse.cpp b/plugins/mapxml/xmlparse.cpp index 85795cdf..f9093a5f 100644 --- a/plugins/mapxml/xmlparse.cpp +++ b/plugins/mapxml/xmlparse.cpp @@ -1,295 +1,295 @@ -// -// parses xml tree format into internal objects -// - - -#include "plugin.h" - -void Patch_XMLParse(patchMesh_t *pPatch, xmlNodePtr surface) -{ - char *str, *content; - int i, j; - - for(xmlNodePtr current = surface->children; current != NULL; current = current->next) - { - if(current->type != XML_ELEMENT_NODE) continue; - if(!strcmp((char *)current->name, "matrix")) - { - str = (char *)xmlGetProp(current, (xmlChar *)"width"); - pPatch->width = atoi(str); - xmlFree(str); - str = (char *)xmlGetProp(current, (xmlChar *)"height"); - pPatch->height = atoi(str); - xmlFree(str); - - content = Q_StrDup((char *)current->children->content); - - str = strtok(content, " \n\r\t\v\0"); - for(i=0; iwidth; i++) - { - for(j=0; jheight; j++) - { - pPatch->ctrl[i][j].xyz[0] = atof(str); - str = strtok(NULL, " \n\r\t\v\0"); - pPatch->ctrl[i][j].xyz[1] = atof(str); - str = strtok(NULL, " \n\r\t\v\0"); - pPatch->ctrl[i][j].xyz[2] = atof(str); - str = strtok(NULL, " \n\r\t\v\0"); - pPatch->ctrl[i][j].st[0] = atof(str); - str = strtok(NULL, " \n\r\t\v\0"); - pPatch->ctrl[i][j].st[1] = atof(str); - str = strtok(NULL, " \n\r\t\v\0"); - } - } - - delete [] content; - } - else if(!strcmp((char *)current->name, "shader")) { - pPatch->pShader = QERApp_Shader_ForName((char*)current->children->content); - pPatch->d_texture = pPatch->pShader->getTexture(); - } - } -} - -void Face_XMLParse (face_t *face, xmlNodePtr surface) -{ - char *str, *content; - int i, j; - - for(xmlNodePtr current = surface->children; current != NULL; current = current->next) - { - if(current->type != XML_ELEMENT_NODE) continue; - if(!strcmp((char *)current->name, "planepts")) - { - content = Q_StrDup((char *)current->children->content); - - str = strtok(content, " \n\r\t\v\0"); - for (i=0 ; i<3 ; i++) - { - for (j=0 ; j<3 ; j++) - { - face->planepts[i][j] = atof(str); - str = strtok(NULL, " \n\r\t\v\0"); - } - } - - delete [] content; - } - else if(!strcmp((char *)current->name, "texdef")) - { - content = Q_StrDup((char *)current->children->content); - - str = strtok(content, " \n\r\t\v\0"); - face->texdef.shift[0] = atof(str); - str = strtok(NULL, " \n\r\t\v\0"); - face->texdef.shift[1] = atof(str); - str = strtok(NULL, " \n\r\t\v\0"); - face->texdef.rotate = atof(str); - str = strtok(NULL, " \n\r\t\v\0"); - face->texdef.scale[0] = atof(str); - str = strtok(NULL, " \n\r\t\v\0"); - face->texdef.scale[1] = atof(str); - - delete [] content; - } - else if(!strcmp((char *)current->name, "bpmatrix")) - { - content = Q_StrDup((char *)current->children->content); - - str = strtok(content, " \n\r\t\v\0"); - face->brushprimit_texdef.coords[0][0] = atof(str); - str = strtok(NULL, " \n\r\t\v\0"); - face->brushprimit_texdef.coords[0][1] = atof(str); - str = strtok(NULL, " \n\r\t\v\0"); - face->brushprimit_texdef.coords[0][2] = atof(str); - str = strtok(NULL, " \n\r\t\v\0"); - face->brushprimit_texdef.coords[1][0] = atof(str); - str = strtok(NULL, " \n\r\t\v\0"); - face->brushprimit_texdef.coords[1][1] = atof(str); - str = strtok(NULL, " \n\r\t\v\0"); - face->brushprimit_texdef.coords[1][2] = atof(str); - - delete [] content; - } - else if(!strcmp((char *)current->name, "flags")) - { - content = Q_StrDup((char *)current->children->content); - - str = strtok(content, " \n\r\t\v\0"); - face->texdef.contents = atoi(str); - str = strtok(NULL, " \n\r\t\v\0"); - face->texdef.flags = atoi(str); - str = strtok(NULL, " \n\r\t\v\0"); - face->texdef.value = atoi(str); - - delete [] content; - } - else if(!strcmp((char *)current->name, "shader")) - { - face->texdef.SetName((char *)current->children->content); - } - } -} - -void Brush_XMLParse (brush_t *pBrush, xmlNodePtr primitive) -{ - face_t *f; - - for(xmlNodePtr current = primitive->children; current != NULL; current = current->next) - { - if(current->type != XML_ELEMENT_NODE) continue; - f = pBrush->brush_faces; - pBrush->brush_faces = Face_Alloc(); - Face_XMLParse(pBrush->brush_faces, current); - pBrush->brush_faces->next = f; - } -} - -void Entity_XMLParse(entity_t *pEntity, xmlNodePtr entity) -{ - brush_t *pBrush; - - for(xmlNodePtr current = entity->children; current != NULL; current = current->next) - { - if(current->type != XML_ELEMENT_NODE) continue; - if(!strcmp((char *)current->name, "epair")) - { - char *key = (char *)xmlGetProp(current, (xmlChar *)"key"); - char *value = (char *)xmlGetProp(current, (xmlChar *)"value"); - SetKeyValue(pEntity, key, value); - xmlFree(key); - xmlFree(value); - } - else if(strcmp((char *)current->name, "brush") == 0) - { - pBrush = Brush_Alloc(); - Brush_XMLParse(pBrush, current); - ((CPtrArray*)pEntity->pData)->Add(pBrush); - } - else if(strcmp((char *)current->name, "patch") == 0) - { - pBrush = Brush_Alloc(); - pBrush->patchBrush = true; - pBrush->pPatch = Patch_Alloc(); - pBrush->pPatch->pSymbiot = pBrush; - Patch_XMLParse(pBrush->pPatch, current); - ((CPtrArray*)pEntity->pData)->Add(pBrush); - } - } -} - -void Map_XMLRead(CPtrArray *map, xmlNodePtr map_node) -{ - entity_t *pEntity; - xmlNodePtr current; - - for(current = map_node->children; current != NULL; current = current->next) - { - if(current->type != XML_ELEMENT_NODE) continue; - pEntity = Entity_Alloc(); - pEntity->pData = new CPtrArray; - Entity_XMLParse(pEntity, current); - map->Add(pEntity); - } -} - -// SPoG -// temporarily copied from qe3.cpp -// duplicate code starts here (note: g_strAppPath swapped for g_FuncTable.m_pfnGetQERPath()) - -void HandleXMLError( void* ctxt, const char* text, ... ) -{ - va_list argptr; - static char buf[32768]; - - va_start (argptr,text); - vsprintf (buf, text, argptr); - Sys_FPrintf (SYS_ERR, "XML %s\n", buf); - va_end (argptr); -} - -#define DTD_BUFFER_LENGTH 1024 -xmlDocPtr ParseXMLStream(IDataStream *stream, bool validate = false) -{ - xmlDocPtr doc = NULL; - bool wellFormed = false, valid = false; - int res, size = 1024; - char chars[1024]; - xmlParserCtxtPtr ctxt; - - // SPoG - // HACK: use AppPath to resolve DTD location - // do a buffer-safe string copy and concatenate - int i; - char* w; - const char* r; - char buf[DTD_BUFFER_LENGTH]; - - w = buf; - i = 0; - // copy - //assert(g_FuncTable.m_pfnGetQERPath() != NULL); - for(r = g_FuncTable.m_pfnGetQERPath(); iRead(chars, 4); - if (res > 0) - { - ctxt = xmlCreatePushParserCtxt(NULL, NULL, chars, res, buf); - - while ((res = stream->Read(chars, size)) > 0) - { - xmlParseChunk(ctxt, chars, res, 0); - } - xmlParseChunk(ctxt, chars, 0, 1); - doc = ctxt->myDoc; - - wellFormed = (ctxt->wellFormed == 1); - valid = (ctxt->valid == 1); - - xmlFreeParserCtxt(ctxt); - } - - if(wellFormed && (!validate || (validate && valid))) - return doc; - - if(doc != NULL) - xmlFreeDoc(doc); - - return NULL; -} - -// duplicate code ends here - -void Map_Read (IDataStream *in, CPtrArray *map) -{ - xmlDocPtr doc; - - doc = ParseXMLStream(in, false ); // quick hack while dtd validation is broken - - if(doc != NULL) - { - xmlNodePtr node=doc->children; - while(node != NULL && node->type != XML_ELEMENT_NODE) node=node->next; - if(node != NULL) - Map_XMLRead(map, node); - } - - xmlFreeDoc(doc); -} +// +// parses xml tree format into internal objects +// + + +#include "plugin.h" + +void Patch_XMLParse(patchMesh_t *pPatch, xmlNodePtr surface) +{ + char *str, *content; + int i, j; + + for(xmlNodePtr current = surface->children; current != NULL; current = current->next) + { + if(current->type != XML_ELEMENT_NODE) continue; + if(!strcmp((char *)current->name, "matrix")) + { + str = (char *)xmlGetProp(current, (xmlChar *)"width"); + pPatch->width = atoi(str); + xmlFree(str); + str = (char *)xmlGetProp(current, (xmlChar *)"height"); + pPatch->height = atoi(str); + xmlFree(str); + + content = Q_StrDup((char *)current->children->content); + + str = strtok(content, " \n\r\t\v\0"); + for(i=0; iwidth; i++) + { + for(j=0; jheight; j++) + { + pPatch->ctrl[i][j].xyz[0] = atof(str); + str = strtok(NULL, " \n\r\t\v\0"); + pPatch->ctrl[i][j].xyz[1] = atof(str); + str = strtok(NULL, " \n\r\t\v\0"); + pPatch->ctrl[i][j].xyz[2] = atof(str); + str = strtok(NULL, " \n\r\t\v\0"); + pPatch->ctrl[i][j].st[0] = atof(str); + str = strtok(NULL, " \n\r\t\v\0"); + pPatch->ctrl[i][j].st[1] = atof(str); + str = strtok(NULL, " \n\r\t\v\0"); + } + } + + delete [] content; + } + else if(!strcmp((char *)current->name, "shader")) { + pPatch->pShader = QERApp_Shader_ForName((char*)current->children->content); + pPatch->d_texture = pPatch->pShader->getTexture(); + } + } +} + +void Face_XMLParse (face_t *face, xmlNodePtr surface) +{ + char *str, *content; + int i, j; + + for(xmlNodePtr current = surface->children; current != NULL; current = current->next) + { + if(current->type != XML_ELEMENT_NODE) continue; + if(!strcmp((char *)current->name, "planepts")) + { + content = Q_StrDup((char *)current->children->content); + + str = strtok(content, " \n\r\t\v\0"); + for (i=0 ; i<3 ; i++) + { + for (j=0 ; j<3 ; j++) + { + face->planepts[i][j] = atof(str); + str = strtok(NULL, " \n\r\t\v\0"); + } + } + + delete [] content; + } + else if(!strcmp((char *)current->name, "texdef")) + { + content = Q_StrDup((char *)current->children->content); + + str = strtok(content, " \n\r\t\v\0"); + face->texdef.shift[0] = atof(str); + str = strtok(NULL, " \n\r\t\v\0"); + face->texdef.shift[1] = atof(str); + str = strtok(NULL, " \n\r\t\v\0"); + face->texdef.rotate = atof(str); + str = strtok(NULL, " \n\r\t\v\0"); + face->texdef.scale[0] = atof(str); + str = strtok(NULL, " \n\r\t\v\0"); + face->texdef.scale[1] = atof(str); + + delete [] content; + } + else if(!strcmp((char *)current->name, "bpmatrix")) + { + content = Q_StrDup((char *)current->children->content); + + str = strtok(content, " \n\r\t\v\0"); + face->brushprimit_texdef.coords[0][0] = atof(str); + str = strtok(NULL, " \n\r\t\v\0"); + face->brushprimit_texdef.coords[0][1] = atof(str); + str = strtok(NULL, " \n\r\t\v\0"); + face->brushprimit_texdef.coords[0][2] = atof(str); + str = strtok(NULL, " \n\r\t\v\0"); + face->brushprimit_texdef.coords[1][0] = atof(str); + str = strtok(NULL, " \n\r\t\v\0"); + face->brushprimit_texdef.coords[1][1] = atof(str); + str = strtok(NULL, " \n\r\t\v\0"); + face->brushprimit_texdef.coords[1][2] = atof(str); + + delete [] content; + } + else if(!strcmp((char *)current->name, "flags")) + { + content = Q_StrDup((char *)current->children->content); + + str = strtok(content, " \n\r\t\v\0"); + face->texdef.contents = atoi(str); + str = strtok(NULL, " \n\r\t\v\0"); + face->texdef.flags = atoi(str); + str = strtok(NULL, " \n\r\t\v\0"); + face->texdef.value = atoi(str); + + delete [] content; + } + else if(!strcmp((char *)current->name, "shader")) + { + face->texdef.SetName((char *)current->children->content); + } + } +} + +void Brush_XMLParse (brush_t *pBrush, xmlNodePtr primitive) +{ + face_t *f; + + for(xmlNodePtr current = primitive->children; current != NULL; current = current->next) + { + if(current->type != XML_ELEMENT_NODE) continue; + f = pBrush->brush_faces; + pBrush->brush_faces = Face_Alloc(); + Face_XMLParse(pBrush->brush_faces, current); + pBrush->brush_faces->next = f; + } +} + +void Entity_XMLParse(entity_t *pEntity, xmlNodePtr entity) +{ + brush_t *pBrush; + + for(xmlNodePtr current = entity->children; current != NULL; current = current->next) + { + if(current->type != XML_ELEMENT_NODE) continue; + if(!strcmp((char *)current->name, "epair")) + { + char *key = (char *)xmlGetProp(current, (xmlChar *)"key"); + char *value = (char *)xmlGetProp(current, (xmlChar *)"value"); + SetKeyValue(pEntity, key, value); + xmlFree(key); + xmlFree(value); + } + else if(strcmp((char *)current->name, "brush") == 0) + { + pBrush = Brush_Alloc(); + Brush_XMLParse(pBrush, current); + ((CPtrArray*)pEntity->pData)->Add(pBrush); + } + else if(strcmp((char *)current->name, "patch") == 0) + { + pBrush = Brush_Alloc(); + pBrush->patchBrush = true; + pBrush->pPatch = Patch_Alloc(); + pBrush->pPatch->pSymbiot = pBrush; + Patch_XMLParse(pBrush->pPatch, current); + ((CPtrArray*)pEntity->pData)->Add(pBrush); + } + } +} + +void Map_XMLRead(CPtrArray *map, xmlNodePtr map_node) +{ + entity_t *pEntity; + xmlNodePtr current; + + for(current = map_node->children; current != NULL; current = current->next) + { + if(current->type != XML_ELEMENT_NODE) continue; + pEntity = Entity_Alloc(); + pEntity->pData = new CPtrArray; + Entity_XMLParse(pEntity, current); + map->Add(pEntity); + } +} + +// SPoG +// temporarily copied from qe3.cpp +// duplicate code starts here (note: g_strAppPath swapped for g_FuncTable.m_pfnGetQERPath()) + +void HandleXMLError( void* ctxt, const char* text, ... ) +{ + va_list argptr; + static char buf[32768]; + + va_start (argptr,text); + vsprintf (buf, text, argptr); + Sys_FPrintf (SYS_ERR, "XML %s\n", buf); + va_end (argptr); +} + +#define DTD_BUFFER_LENGTH 1024 +xmlDocPtr ParseXMLStream(IDataStream *stream, bool validate = false) +{ + xmlDocPtr doc = NULL; + bool wellFormed = false, valid = false; + int res, size = 1024; + char chars[1024]; + xmlParserCtxtPtr ctxt; + + // SPoG + // HACK: use AppPath to resolve DTD location + // do a buffer-safe string copy and concatenate + int i; + char* w; + const char* r; + char buf[DTD_BUFFER_LENGTH]; + + w = buf; + i = 0; + // copy + //assert(g_FuncTable.m_pfnGetQERPath() != NULL); + for(r = g_FuncTable.m_pfnGetQERPath(); iRead(chars, 4); + if (res > 0) + { + ctxt = xmlCreatePushParserCtxt(NULL, NULL, chars, res, buf); + + while ((res = stream->Read(chars, size)) > 0) + { + xmlParseChunk(ctxt, chars, res, 0); + } + xmlParseChunk(ctxt, chars, 0, 1); + doc = ctxt->myDoc; + + wellFormed = (ctxt->wellFormed == 1); + valid = (ctxt->valid == 1); + + xmlFreeParserCtxt(ctxt); + } + + if(wellFormed && (!validate || (validate && valid))) + return doc; + + if(doc != NULL) + xmlFreeDoc(doc); + + return NULL; +} + +// duplicate code ends here + +void Map_Read (IDataStream *in, CPtrArray *map) +{ + xmlDocPtr doc; + + doc = ParseXMLStream(in, false ); // quick hack while dtd validation is broken + + if(doc != NULL) + { + xmlNodePtr node=doc->children; + while(node != NULL && node->type != XML_ELEMENT_NODE) node=node->next; + if(node != NULL) + Map_XMLRead(map, node); + } + + xmlFreeDoc(doc); +} diff --git a/plugins/mapxml/xmlwrite.cpp b/plugins/mapxml/xmlwrite.cpp index b972abad..b1409132 100644 --- a/plugins/mapxml/xmlwrite.cpp +++ b/plugins/mapxml/xmlwrite.cpp @@ -1,217 +1,217 @@ -// -// writes xml tree format from internal objects -// - - -#include "plugin.h" - -char *str_append_token(char *str1, const char *str2) -{ - char *str; - if(str1 != NULL) - { - str = new char[strlen(str1)+strlen(str2)+2]; - sprintf(str, "%s %s", str1, str2); - delete [] str1; - } - else - { - str = new char[strlen(str2)+1]; - strcpy(str, str2); - } - return str; -} - -void str_from_float(char *buf, float f) -{ - if(f == (int)f) sprintf(buf, "%i", (int)f); - else sprintf(buf, "%f", f); -} - -void Patch_XMLWrite(patchMesh_t *pPatch, xmlNodePtr surface) -{ - char buf[16]; - char *str; - int i, j; - xmlNodePtr node; - - // write shader - node = xmlNewChild(surface, NULL, (xmlChar *)"shader", (xmlChar *)pPatch->pShader->getName()); - - // write matrix - str = NULL; - for(i=0; iwidth; i++) - { - for(j=0; jheight; j++) - { - str_from_float(buf, pPatch->ctrl[i][j].xyz[0]); - str = str_append_token(str, buf); - str_from_float(buf, pPatch->ctrl[i][j].xyz[1]); - str = str_append_token(str, buf); - str_from_float(buf, pPatch->ctrl[i][j].xyz[2]); - str = str_append_token(str, buf); - str_from_float(buf, pPatch->ctrl[i][j].st[0]); - str = str_append_token(str, buf); - str_from_float(buf, pPatch->ctrl[i][j].st[1]); - str = str_append_token(str, buf); - } - } - - node = xmlNewChild(surface, NULL, (xmlChar *)"matrix", (xmlChar *)str); - delete [] str; - sprintf(buf, "%i", pPatch->width); - xmlSetProp(node, (xmlChar *)"width", (xmlChar *)buf); - sprintf(buf, "%i", pPatch->height); - xmlSetProp(node, (xmlChar *)"height", (xmlChar *)buf); -} - -void Face_XMLWrite (face_t *face, xmlNodePtr surface, bool bAlternateTexdef = false) -{ - char buf[16]; - xmlNodePtr node; - int i, j; - char *str; - - // write shader - node = xmlNewChild(surface, NULL, (xmlChar *)"shader", (xmlChar *)face->texdef.GetName()); - - // write planepts - str = NULL; - for (i=0 ; i<3 ; i++) - { - for (j=0 ; j<3 ; j++) - { - str_from_float(buf, face->planepts[i][j]); - str = str_append_token(str, buf); - } - } - - node = xmlNewChild(surface, NULL, (xmlChar *)"planepts", (xmlChar *)str); - delete [] str; - - if(!bAlternateTexdef) - { - // write texdef - sprintf(buf, "%i", (int)face->texdef.shift[0]); - str = str_append_token(NULL, buf); - sprintf(buf, "%i", (int)face->texdef.shift[1]); - str = str_append_token(str, buf); - sprintf(buf, "%i", (int)face->texdef.rotate); - str = str_append_token(str, buf); - sprintf(buf, "%f", face->texdef.scale[0]); - str = str_append_token(str, buf); - sprintf(buf, "%f", face->texdef.scale[1]); - str = str_append_token(str, buf); - - node = xmlNewChild(surface, NULL, (xmlChar *)"texdef", (xmlChar *)str); - delete [] str; - } - else - { - // write matrix texdef - str = NULL; - for (i=0 ; i<2 ; i++) - { - for (j=0 ; j<3 ; j++) - { - str_from_float(buf, face->brushprimit_texdef.coords[i][j]); - str = str_append_token(str, buf); - } - } - node = xmlNewChild(surface, NULL, (xmlChar *)"bpmatrix", (xmlChar *)str); - delete [] str; - } - - // write flags - sprintf(buf, "%i", face->texdef.contents); - str = str_append_token(NULL, buf); - sprintf(buf, "%i", face->texdef.flags); - str = str_append_token(str, buf); - sprintf(buf, "%i", face->texdef.value); - str = str_append_token(str, buf); - - node = xmlNewChild(surface, NULL, (xmlChar *)"flags", (xmlChar *)str); - delete [] str; -} - -void Brush_XMLWrite (brush_t *brush, xmlNodePtr primitive) -{ - xmlNodePtr node; - - for(face_t *face = brush->brush_faces; face != NULL; face = face->next) - { - node = xmlNewChild(primitive, NULL, (xmlChar *)"plane", NULL); - Face_XMLWrite (face, node, brush->bBrushDef); - } -} - -void Epair_XMLWrite(epair_t *pEpair, xmlNodePtr epair) -{ - xmlSetProp(epair, (xmlChar *)"key", (xmlChar *)pEpair->key); - xmlSetProp(epair, (xmlChar *)"value", (xmlChar *)pEpair->value); -} - -void Entity_XMLWrite(entity_t *pEntity, xmlNodePtr entity) -{ - brush_t *pBrush; - epair_t *pEpair; - xmlNodePtr node; - - CPtrArray *brushes = (CPtrArray*)pEntity->pData; - - for(pEpair = pEntity->epairs; pEpair != NULL; pEpair = pEpair->next) - { - node = xmlNewChild(entity, NULL, (xmlChar *)"epair", NULL); - Epair_XMLWrite(pEpair, node); - } - - for(int i=0; iGetSize(); i++) - { - pBrush = (brush_t*)brushes->GetAt(i); - - if(pBrush->patchBrush) - { - node = xmlNewChild(entity, NULL, (xmlChar *)"patch", NULL); - Patch_XMLWrite(pBrush->pPatch, node); - } - else - { - node = xmlNewChild(entity, NULL, (xmlChar *)"brush", NULL); - Brush_XMLWrite(pBrush, node); - } - } -} - -void Map_XMLWrite (CPtrArray *map, xmlNodePtr map_node) -{ - entity_t *pEntity; - xmlNodePtr node; - - for(int i=0; iGetSize(); i++) - { - pEntity = (entity_t*)map->GetAt(i); - - node = xmlNewChild(map_node, NULL, (xmlChar *)"entity", NULL); - Entity_XMLWrite(pEntity, node); - } -} - -void Map_Write (CPtrArray *map, IDataStream *out) -{ - xmlChar* buf; - int len; - - xmlDocPtr doc = xmlNewDoc((xmlChar *)"1.0"); - xmlCreateIntSubset(doc, (xmlChar *)"mapq3", NULL, (xmlChar *)"mapq3.dtd"); - doc->children->next = xmlNewDocNode(doc, NULL, (xmlChar *)"mapq3", NULL); - - Map_XMLWrite(map, doc->children->next); - - // xmlDocDumpMemory(doc, &buf, &len); - xmlDocDumpFormatMemory(doc, &buf, &len, 1); - xmlFreeDoc(doc); - - out->Write(buf, len); - - xmlFree(buf); -} +// +// writes xml tree format from internal objects +// + + +#include "plugin.h" + +char *str_append_token(char *str1, const char *str2) +{ + char *str; + if(str1 != NULL) + { + str = new char[strlen(str1)+strlen(str2)+2]; + sprintf(str, "%s %s", str1, str2); + delete [] str1; + } + else + { + str = new char[strlen(str2)+1]; + strcpy(str, str2); + } + return str; +} + +void str_from_float(char *buf, float f) +{ + if(f == (int)f) sprintf(buf, "%i", (int)f); + else sprintf(buf, "%f", f); +} + +void Patch_XMLWrite(patchMesh_t *pPatch, xmlNodePtr surface) +{ + char buf[16]; + char *str; + int i, j; + xmlNodePtr node; + + // write shader + node = xmlNewChild(surface, NULL, (xmlChar *)"shader", (xmlChar *)pPatch->pShader->getName()); + + // write matrix + str = NULL; + for(i=0; iwidth; i++) + { + for(j=0; jheight; j++) + { + str_from_float(buf, pPatch->ctrl[i][j].xyz[0]); + str = str_append_token(str, buf); + str_from_float(buf, pPatch->ctrl[i][j].xyz[1]); + str = str_append_token(str, buf); + str_from_float(buf, pPatch->ctrl[i][j].xyz[2]); + str = str_append_token(str, buf); + str_from_float(buf, pPatch->ctrl[i][j].st[0]); + str = str_append_token(str, buf); + str_from_float(buf, pPatch->ctrl[i][j].st[1]); + str = str_append_token(str, buf); + } + } + + node = xmlNewChild(surface, NULL, (xmlChar *)"matrix", (xmlChar *)str); + delete [] str; + sprintf(buf, "%i", pPatch->width); + xmlSetProp(node, (xmlChar *)"width", (xmlChar *)buf); + sprintf(buf, "%i", pPatch->height); + xmlSetProp(node, (xmlChar *)"height", (xmlChar *)buf); +} + +void Face_XMLWrite (face_t *face, xmlNodePtr surface, bool bAlternateTexdef = false) +{ + char buf[16]; + xmlNodePtr node; + int i, j; + char *str; + + // write shader + node = xmlNewChild(surface, NULL, (xmlChar *)"shader", (xmlChar *)face->texdef.GetName()); + + // write planepts + str = NULL; + for (i=0 ; i<3 ; i++) + { + for (j=0 ; j<3 ; j++) + { + str_from_float(buf, face->planepts[i][j]); + str = str_append_token(str, buf); + } + } + + node = xmlNewChild(surface, NULL, (xmlChar *)"planepts", (xmlChar *)str); + delete [] str; + + if(!bAlternateTexdef) + { + // write texdef + sprintf(buf, "%i", (int)face->texdef.shift[0]); + str = str_append_token(NULL, buf); + sprintf(buf, "%i", (int)face->texdef.shift[1]); + str = str_append_token(str, buf); + sprintf(buf, "%i", (int)face->texdef.rotate); + str = str_append_token(str, buf); + sprintf(buf, "%f", face->texdef.scale[0]); + str = str_append_token(str, buf); + sprintf(buf, "%f", face->texdef.scale[1]); + str = str_append_token(str, buf); + + node = xmlNewChild(surface, NULL, (xmlChar *)"texdef", (xmlChar *)str); + delete [] str; + } + else + { + // write matrix texdef + str = NULL; + for (i=0 ; i<2 ; i++) + { + for (j=0 ; j<3 ; j++) + { + str_from_float(buf, face->brushprimit_texdef.coords[i][j]); + str = str_append_token(str, buf); + } + } + node = xmlNewChild(surface, NULL, (xmlChar *)"bpmatrix", (xmlChar *)str); + delete [] str; + } + + // write flags + sprintf(buf, "%i", face->texdef.contents); + str = str_append_token(NULL, buf); + sprintf(buf, "%i", face->texdef.flags); + str = str_append_token(str, buf); + sprintf(buf, "%i", face->texdef.value); + str = str_append_token(str, buf); + + node = xmlNewChild(surface, NULL, (xmlChar *)"flags", (xmlChar *)str); + delete [] str; +} + +void Brush_XMLWrite (brush_t *brush, xmlNodePtr primitive) +{ + xmlNodePtr node; + + for(face_t *face = brush->brush_faces; face != NULL; face = face->next) + { + node = xmlNewChild(primitive, NULL, (xmlChar *)"plane", NULL); + Face_XMLWrite (face, node, brush->bBrushDef); + } +} + +void Epair_XMLWrite(epair_t *pEpair, xmlNodePtr epair) +{ + xmlSetProp(epair, (xmlChar *)"key", (xmlChar *)pEpair->key); + xmlSetProp(epair, (xmlChar *)"value", (xmlChar *)pEpair->value); +} + +void Entity_XMLWrite(entity_t *pEntity, xmlNodePtr entity) +{ + brush_t *pBrush; + epair_t *pEpair; + xmlNodePtr node; + + CPtrArray *brushes = (CPtrArray*)pEntity->pData; + + for(pEpair = pEntity->epairs; pEpair != NULL; pEpair = pEpair->next) + { + node = xmlNewChild(entity, NULL, (xmlChar *)"epair", NULL); + Epair_XMLWrite(pEpair, node); + } + + for(int i=0; iGetSize(); i++) + { + pBrush = (brush_t*)brushes->GetAt(i); + + if(pBrush->patchBrush) + { + node = xmlNewChild(entity, NULL, (xmlChar *)"patch", NULL); + Patch_XMLWrite(pBrush->pPatch, node); + } + else + { + node = xmlNewChild(entity, NULL, (xmlChar *)"brush", NULL); + Brush_XMLWrite(pBrush, node); + } + } +} + +void Map_XMLWrite (CPtrArray *map, xmlNodePtr map_node) +{ + entity_t *pEntity; + xmlNodePtr node; + + for(int i=0; iGetSize(); i++) + { + pEntity = (entity_t*)map->GetAt(i); + + node = xmlNewChild(map_node, NULL, (xmlChar *)"entity", NULL); + Entity_XMLWrite(pEntity, node); + } +} + +void Map_Write (CPtrArray *map, IDataStream *out) +{ + xmlChar* buf; + int len; + + xmlDocPtr doc = xmlNewDoc((xmlChar *)"1.0"); + xmlCreateIntSubset(doc, (xmlChar *)"mapq3", NULL, (xmlChar *)"mapq3.dtd"); + doc->children->next = xmlNewDocNode(doc, NULL, (xmlChar *)"mapq3", NULL); + + Map_XMLWrite(map, doc->children->next); + + // xmlDocDumpMemory(doc, &buf, &len); + xmlDocDumpFormatMemory(doc, &buf, &len, 1); + xmlFreeDoc(doc); + + out->Write(buf, len); + + xmlFree(buf); +} diff --git a/plugins/model/cpicomodel.cpp b/plugins/model/cpicomodel.cpp index d02c5be4..b4338242 100644 --- a/plugins/model/cpicomodel.cpp +++ b/plugins/model/cpicomodel.cpp @@ -1,220 +1,220 @@ -/* -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 -*/ - -#include "cpicomodel.h" -#include "cpicosurface.h" - -CPicoModel::CPicoModel(const PicoModelKey& key) -: m_refcount(1) -{ - load(key.first.GetBuffer(), key.second); -} - -CPicoModel::CPicoModel(const Str& name) -: m_refcount(1) -{ - load(name.GetBuffer(), 0); -} - -CPicoModel::CPicoModel(const Str& name, const int frame) -: m_refcount(1) -{ - load(name.GetBuffer(), frame); -} - -CPicoModel::CPicoModel(const char *name, const int frame) -: m_refcount(1) -{ - load(name, frame); -} - -void CPicoModel::load(const char *name, const int frame) -{ - CPicoSurface *surf; - picoSurface_t *pSurface; - int i; - - m_name= new char[strlen(name)+1]; - strcpy(m_name,name); - - m_frame = frame; - - if( !(m_pModel = PicoLoadModel(m_name, frame)) ) - { - int len = strlen(m_name); - - // Try loading an mdc if md3 fails and vice-versa (fixme: only do this for games with mdc support) - if( !strcmp( m_name + len - 4, ".md3" ) ) - { - m_name[len - 1] = 'c'; - m_pModel = PicoLoadModel(m_name, frame); - } else if( !strcmp( m_name + len - 4, ".mdc" ) ) - { - m_name[len - 1] = '3'; - m_pModel = PicoLoadModel(m_name, frame); - } - } - - if( m_pModel ) - { - m_children = g_ptr_array_new(); - aabb_clear(&m_BBox); - for (i = 0; i < PicoGetModelNumSurfaces(m_pModel); i++ ) - { - pSurface = PicoGetModelSurface(m_pModel,i); - surf = new CPicoSurface(pSurface); - g_ptr_array_add(m_children, surf); - aabb_extend_by_aabb(&m_BBox, surf->GetAABB()); - } - } - else - { - m_BBox.origin[0] = m_BBox.origin[1] = m_BBox.origin[2] = 0; - m_BBox.extents[0] = m_BBox.extents[1] = m_BBox.extents[2] = 0; - } - - m_parents = g_ptr_array_new(); -} - -CPicoModel::~CPicoModel() -{ - if( m_pModel ) { - for(unsigned int i=0; ilen; i++) - ((CPicoSurface*)m_children->pdata[i])->DecRef(); - g_ptr_array_free(m_children, FALSE); - } - g_ptr_array_free(m_parents, FALSE); - delete [] m_name; -} - -void CPicoModel::AddParent( CPicoParent *parent ) -{ - g_ptr_array_add(m_parents, parent); -} - -void CPicoModel::RemoveParent( CPicoParent *parent ) -{ - unsigned int i; - for(i=0; ilen; i++) { - if( parent == (CPicoParent*)m_parents->pdata[i] ) - g_ptr_array_remove_index_fast(m_parents, i); - } -} - -void CPicoModel::Reload( void ) -{ - CPicoSurface *surf; - picoSurface_t *pSurface; - int i; - unsigned int j; - - // Get rid of the old model - if( m_pModel ) { - for(j=0; jlen; j++) { - ((CPicoSurface*)m_children->pdata[j])->DecRef(); - g_ptr_array_remove_index_fast(m_children, j); - } - } - - // And reload it - m_pModel = PicoLoadModel(m_name, m_frame); - - if( m_pModel ) - { - m_children = g_ptr_array_new(); - aabb_clear(&m_BBox); - for (i = 0; i < PicoGetModelNumSurfaces(m_pModel); i++ ) - { - pSurface = PicoGetModelSurface(m_pModel,i); - surf = new CPicoSurface(pSurface); - g_ptr_array_add(m_children, surf); - aabb_extend_by_aabb(&m_BBox, surf->GetAABB()); - } - } - else - { - m_BBox.origin[0] = m_BBox.origin[1] = m_BBox.origin[2] = 0; - m_BBox.extents[0] = m_BBox.extents[1] = m_BBox.extents[2] = 0; - } - - for(j=0; jlen; j++) { - ((CPicoParent*)m_parents->pdata[j])->UpdateShaders(); - } -} - -void CPicoModel::Draw(int state, vector shaders, int rflags) const -{ - if( m_pModel ) { - for(unsigned int i=0; ilen; i++) - ((CPicoSurface*)m_children->pdata[i])->Draw(state, shaders[i], rflags); - } -} - -void CPicoModel::Draw(int state, int rflags) const -{ - if( m_pModel ) { - for(unsigned int i=0; ilen; i++) - ((CPicoSurface*)m_children->pdata[i])->Draw(state, rflags); - } -} - -bool CPicoModel::TestRay(const ray_t *ray, vec_t *dist) const -{ - vec_t dist_start = *dist; - vec_t dist_local = *dist; - ray_t ray_local = *ray; - - if( !m_pModel ) { - return false; - } - - if (!aabb_intersect_ray(&m_BBox, &ray_local, &dist_local)) - return false; - dist_local = dist_start; - - for(unsigned int i=0; ilen; i++) - { - if(((CPicoSurface*)m_children->pdata[i])->TestRay(&ray_local, &dist_local)) - { - *dist = dist_local; - } - } - - return *dist < dist_start; -} - -int CPicoModel::GetNumSurfaces( void ) -{ - if( !m_pModel ) { - return 0; - } - - return m_children->len; -} - -char *CPicoModel::GetShaderNameForSurface( const unsigned int surf ) -{ - if( !m_pModel || surf < 0 || surf >= m_children->len ) { - return 0; - } - - return ((CPicoSurface*)m_children->pdata[surf])->GetShaderName(); -} +/* +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 +*/ + +#include "cpicomodel.h" +#include "cpicosurface.h" + +CPicoModel::CPicoModel(const PicoModelKey& key) +: m_refcount(1) +{ + load(key.first.GetBuffer(), key.second); +} + +CPicoModel::CPicoModel(const Str& name) +: m_refcount(1) +{ + load(name.GetBuffer(), 0); +} + +CPicoModel::CPicoModel(const Str& name, const int frame) +: m_refcount(1) +{ + load(name.GetBuffer(), frame); +} + +CPicoModel::CPicoModel(const char *name, const int frame) +: m_refcount(1) +{ + load(name, frame); +} + +void CPicoModel::load(const char *name, const int frame) +{ + CPicoSurface *surf; + picoSurface_t *pSurface; + int i; + + m_name= new char[strlen(name)+1]; + strcpy(m_name,name); + + m_frame = frame; + + if( !(m_pModel = PicoLoadModel(m_name, frame)) ) + { + int len = strlen(m_name); + + // Try loading an mdc if md3 fails and vice-versa (fixme: only do this for games with mdc support) + if( !strcmp( m_name + len - 4, ".md3" ) ) + { + m_name[len - 1] = 'c'; + m_pModel = PicoLoadModel(m_name, frame); + } else if( !strcmp( m_name + len - 4, ".mdc" ) ) + { + m_name[len - 1] = '3'; + m_pModel = PicoLoadModel(m_name, frame); + } + } + + if( m_pModel ) + { + m_children = g_ptr_array_new(); + aabb_clear(&m_BBox); + for (i = 0; i < PicoGetModelNumSurfaces(m_pModel); i++ ) + { + pSurface = PicoGetModelSurface(m_pModel,i); + surf = new CPicoSurface(pSurface); + g_ptr_array_add(m_children, surf); + aabb_extend_by_aabb(&m_BBox, surf->GetAABB()); + } + } + else + { + m_BBox.origin[0] = m_BBox.origin[1] = m_BBox.origin[2] = 0; + m_BBox.extents[0] = m_BBox.extents[1] = m_BBox.extents[2] = 0; + } + + m_parents = g_ptr_array_new(); +} + +CPicoModel::~CPicoModel() +{ + if( m_pModel ) { + for(unsigned int i=0; ilen; i++) + ((CPicoSurface*)m_children->pdata[i])->DecRef(); + g_ptr_array_free(m_children, FALSE); + } + g_ptr_array_free(m_parents, FALSE); + delete [] m_name; +} + +void CPicoModel::AddParent( CPicoParent *parent ) +{ + g_ptr_array_add(m_parents, parent); +} + +void CPicoModel::RemoveParent( CPicoParent *parent ) +{ + unsigned int i; + for(i=0; ilen; i++) { + if( parent == (CPicoParent*)m_parents->pdata[i] ) + g_ptr_array_remove_index_fast(m_parents, i); + } +} + +void CPicoModel::Reload( void ) +{ + CPicoSurface *surf; + picoSurface_t *pSurface; + int i; + unsigned int j; + + // Get rid of the old model + if( m_pModel ) { + for(j=0; jlen; j++) { + ((CPicoSurface*)m_children->pdata[j])->DecRef(); + g_ptr_array_remove_index_fast(m_children, j); + } + } + + // And reload it + m_pModel = PicoLoadModel(m_name, m_frame); + + if( m_pModel ) + { + m_children = g_ptr_array_new(); + aabb_clear(&m_BBox); + for (i = 0; i < PicoGetModelNumSurfaces(m_pModel); i++ ) + { + pSurface = PicoGetModelSurface(m_pModel,i); + surf = new CPicoSurface(pSurface); + g_ptr_array_add(m_children, surf); + aabb_extend_by_aabb(&m_BBox, surf->GetAABB()); + } + } + else + { + m_BBox.origin[0] = m_BBox.origin[1] = m_BBox.origin[2] = 0; + m_BBox.extents[0] = m_BBox.extents[1] = m_BBox.extents[2] = 0; + } + + for(j=0; jlen; j++) { + ((CPicoParent*)m_parents->pdata[j])->UpdateShaders(); + } +} + +void CPicoModel::Draw(int state, vector shaders, int rflags) const +{ + if( m_pModel ) { + for(unsigned int i=0; ilen; i++) + ((CPicoSurface*)m_children->pdata[i])->Draw(state, shaders[i], rflags); + } +} + +void CPicoModel::Draw(int state, int rflags) const +{ + if( m_pModel ) { + for(unsigned int i=0; ilen; i++) + ((CPicoSurface*)m_children->pdata[i])->Draw(state, rflags); + } +} + +bool CPicoModel::TestRay(const ray_t *ray, vec_t *dist) const +{ + vec_t dist_start = *dist; + vec_t dist_local = *dist; + ray_t ray_local = *ray; + + if( !m_pModel ) { + return false; + } + + if (!aabb_intersect_ray(&m_BBox, &ray_local, &dist_local)) + return false; + dist_local = dist_start; + + for(unsigned int i=0; ilen; i++) + { + if(((CPicoSurface*)m_children->pdata[i])->TestRay(&ray_local, &dist_local)) + { + *dist = dist_local; + } + } + + return *dist < dist_start; +} + +int CPicoModel::GetNumSurfaces( void ) +{ + if( !m_pModel ) { + return 0; + } + + return m_children->len; +} + +char *CPicoModel::GetShaderNameForSurface( const unsigned int surf ) +{ + if( !m_pModel || surf < 0 || surf >= m_children->len ) { + return 0; + } + + return ((CPicoSurface*)m_children->pdata[surf])->GetShaderName(); +} diff --git a/plugins/model/cpicosurface.cpp b/plugins/model/cpicosurface.cpp index f3655246..0fc88fb8 100644 --- a/plugins/model/cpicosurface.cpp +++ b/plugins/model/cpicosurface.cpp @@ -1,203 +1,203 @@ -/* -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 -*/ - -#include "cpicosurface.h" - -// public - -CPicoSurface::CPicoSurface(picoSurface_t *pSurface) -{ - refCount = 1; - - m_pSurface = pSurface; - - // PicoFixSurfaceNormals( pSurface ); - - AccumulateBBox(); - - m_shader = QERApp_Shader_ForName(GetShaderName()); -} - -CPicoSurface::~CPicoSurface() -{ - m_shader->DecRef(); -} - -void CPicoSurface::Draw(int state, int rflags) -{ - Draw(state, m_shader, rflags); -} - -void CPicoSurface::Draw(int state, IShader *pShader, int rflags) -{ - int j; - - if( !(rflags & (DRAW_RF_SEL_OUTLINE|DRAW_RF_SEL_FILL|DRAW_RF_XY)) ) - { - if(state & DRAW_GL_TEXTURE_2D) - { - g_QglTable.m_pfn_qglBindTexture(GL_TEXTURE_2D, pShader->getTexture()->texture_number); - if( (rflags & DRAW_RF_CAM) && (pShader->getFlags() & QER_ALPHAFUNC) ) { - int nFunc = 0; - float fRef = 0.f; - - g_QglTable.m_pfn_qglColor4f( 1.f, 1.f, 1.f, 1.f ); // identity - - g_QglTable.m_pfn_qglEnable( GL_ALPHA_TEST ); - - pShader->getAlphaFunc( &nFunc, &fRef ); - g_QglTable.m_pfn_qglAlphaFunc( nFunc, fRef ); - } - } - else - { - //g_QglTable.m_pfn_qglColor3fv( pShader->getTexture()->color ); -/* g_QglTable.m_pfn_qglEnableClientState(GL_COLOR_ARRAY);*/ - } - - if( !(state & DRAW_GL_WIRE) && (pShader->getFlags() & QER_CULL) ) - { - if( pShader->getCull() == 2 ) - { - g_QglTable.m_pfn_qglDisable( GL_CULL_FACE ); - g_QglTable.m_pfn_qglPolygonMode (GL_FRONT, GL_FILL); - } - else // is 1 - { - g_QglTable.m_pfn_qglCullFace( GL_BACK ); - } - } - } - - switch( PicoGetSurfaceType(m_pSurface) ) - { - case PICO_TRIANGLES: g_QglTable.m_pfn_qglBegin(GL_TRIANGLES); - for (j=0; jgetFlags() & QER_ALPHAFUNC) ) { - g_QglTable.m_pfn_qglDisable( GL_ALPHA_TEST ); - } - -/* if(!(state & DRAW_GL_TEXTURE_2D)) { - g_QglTable.m_pfn_qglDisableClientState(GL_COLOR_ARRAY); - }*/ - - if( !(state & DRAW_GL_WIRE) && (pShader->getFlags() & QER_CULL) ) - { - if( pShader->getCull() == 2 ) - { - g_QglTable.m_pfn_qglPolygonMode (GL_FRONT, GL_LINE); - g_QglTable.m_pfn_qglEnable( GL_CULL_FACE ); - } - else // is 1 - { - g_QglTable.m_pfn_qglCullFace( GL_FRONT ); - } - } - } -} - -// private - -void CPicoSurface::AccumulateBBox() -{ - int i; - picoVec_t *p; - aabb_clear(&m_BBox); - for (i=0; iDecRef(); +} + +void CPicoSurface::Draw(int state, int rflags) +{ + Draw(state, m_shader, rflags); +} + +void CPicoSurface::Draw(int state, IShader *pShader, int rflags) +{ + int j; + + if( !(rflags & (DRAW_RF_SEL_OUTLINE|DRAW_RF_SEL_FILL|DRAW_RF_XY)) ) + { + if(state & DRAW_GL_TEXTURE_2D) + { + g_QglTable.m_pfn_qglBindTexture(GL_TEXTURE_2D, pShader->getTexture()->texture_number); + if( (rflags & DRAW_RF_CAM) && (pShader->getFlags() & QER_ALPHAFUNC) ) { + int nFunc = 0; + float fRef = 0.f; + + g_QglTable.m_pfn_qglColor4f( 1.f, 1.f, 1.f, 1.f ); // identity + + g_QglTable.m_pfn_qglEnable( GL_ALPHA_TEST ); + + pShader->getAlphaFunc( &nFunc, &fRef ); + g_QglTable.m_pfn_qglAlphaFunc( nFunc, fRef ); + } + } + else + { + //g_QglTable.m_pfn_qglColor3fv( pShader->getTexture()->color ); +/* g_QglTable.m_pfn_qglEnableClientState(GL_COLOR_ARRAY);*/ + } + + if( !(state & DRAW_GL_WIRE) && (pShader->getFlags() & QER_CULL) ) + { + if( pShader->getCull() == 2 ) + { + g_QglTable.m_pfn_qglDisable( GL_CULL_FACE ); + g_QglTable.m_pfn_qglPolygonMode (GL_FRONT, GL_FILL); + } + else // is 1 + { + g_QglTable.m_pfn_qglCullFace( GL_BACK ); + } + } + } + + switch( PicoGetSurfaceType(m_pSurface) ) + { + case PICO_TRIANGLES: g_QglTable.m_pfn_qglBegin(GL_TRIANGLES); + for (j=0; jgetFlags() & QER_ALPHAFUNC) ) { + g_QglTable.m_pfn_qglDisable( GL_ALPHA_TEST ); + } + +/* if(!(state & DRAW_GL_TEXTURE_2D)) { + g_QglTable.m_pfn_qglDisableClientState(GL_COLOR_ARRAY); + }*/ + + if( !(state & DRAW_GL_WIRE) && (pShader->getFlags() & QER_CULL) ) + { + if( pShader->getCull() == 2 ) + { + g_QglTable.m_pfn_qglPolygonMode (GL_FRONT, GL_LINE); + g_QglTable.m_pfn_qglEnable( GL_CULL_FACE ); + } + else // is 1 + { + g_QglTable.m_pfn_qglCullFace( GL_FRONT ); + } + } + } +} + +// private + +void CPicoSurface::AccumulateBBox() +{ + int i; + picoVec_t *p; + aabb_clear(&m_BBox); + for (i=0; i - -#include "entitymodel.h" - -extern CModelManager g_model_cache; - -// -// CEntityMiscModel implementation -// - -CEntityMiscModel::CEntityMiscModel () -{ - refCount = 1; - m_name = NULL; - m_model = NULL; - m_entity = NULL; - m_frame = 0; - m_remaps = g_ptr_array_new (); - m_shaders = g_ptr_array_new (); - VectorSet(m_translate, 0,0,0); - VectorSet(m_euler, 0,0,0); - VectorSet(m_scale, 1,1,1); - VectorSet(m_pivot, 0,0,0); - m4x4_identity(m_transform); - m4x4_identity(m_inverse_transform); -} - -typedef struct remap_s { - char m_key[64]; - char m_remapbuff[64+1024]; - char *m_remap[2]; -} remap_t; - -CEntityMiscModel::~CEntityMiscModel () -{ - unsigned int i; - - if(m_name && *m_name != '\0') { - if( !g_model_cache.DeleteByNameAndFrame(m_name,m_frame) && m_model ) - m_model->RemoveParent( this ); - m_model = NULL; - delete [] m_name; - } - - for( i = 0; i < m_remaps->len; i++ ) - delete (remap_t*)m_remaps->pdata[i]; - g_ptr_array_free(m_remaps, FALSE); - - for( i = 0; i < m_shaders->len; i++ ) - { - (*(IShader**)m_shaders->pdata[i])->DecRef(); - delete (IShader**)m_shaders->pdata[i]; - } - g_ptr_array_free(m_shaders, FALSE); - - if(m_entity) { - // This might be just an evasion of the actual problem - m_entity->model.pRender = NULL; - m_entity->model.pSelect = NULL; - m_entity->model.pEdit = NULL; - } -} - -// IRender - -void CEntityMiscModel::Draw(int state, int rflags) const -{ - m4x4_t matrix; - vec3_t pivot; - - memcpy(matrix, m_transform, sizeof(m4x4_t)); - m4x4_transpose(matrix); - - VectorAdd(m_pivot, m_translate, pivot); - pivot_draw(pivot); - - // push the current modelview matrix - // FIXME: put in a check for stack recursion depth.. - // or avoid recursion of opengl matrix stack - g_QglTable.m_pfn_qglPushMatrix(); - // apply the parent-to-local transform - g_QglTable.m_pfn_qglMultMatrixf(matrix); - - // draw children - if(m_model) - m_model->Draw(state, m_shaders, rflags); - - g_QglTable.m_pfn_qglPopMatrix(); -} - -// ISelect - -bool CEntityMiscModel::TestRay(const ray_t *ray, vec_t *dist) const -{ - vec_t dist_start = *dist; - vec_t dist_local = *dist; - ray_t ray_local = *ray; - - if (!aabb_intersect_ray(&m_BBox, &ray_local, &dist_local)) - return false; - - if(m_model){ - ray_transform(&ray_local, m_inverse_transform); - dist_local = dist_start; - if(m_model->TestRay(&ray_local, &dist_local)) - *dist = dist_local; - } else *dist = dist_local; - - return *dist < dist_start; -} - - -//IEdit - -void CEntityMiscModel::Translate(const vec3_t translation) -{ - VectorIncrement(translation, m_translate); - UpdateCachedData(); -} - -void CEntityMiscModel::Rotate(const vec3_t pivot, const vec3_t rotation) -{ - m4x4_t rotation_matrix; - - m4x4_identity(rotation_matrix); - m4x4_pivoted_rotate_by_vec3(rotation_matrix, rotation, pivot); - m4x4_transform_point(rotation_matrix, m_translate); - - VectorIncrement(rotation, m_euler); - - UpdateCachedData(); -} - -void CEntityMiscModel::OnKeyChanged(entity_t *e, const char *key) -{ - const char *value; - - // FIXME: keys are case-sensitive? - - m_entity = e; - - if(strcmp(key,"model") == 0) - SetName(ValueForKey(e,"model")); - else if(strcmp(key,"_frame") == 0) - SetFrame(IntForKey(e,"_frame")); - else if(strcmp(key,"angle") == 0 || strcmp(key,"angles") == 0) - { - VectorSet(m_euler, 0.f, 0.f, 0.f); - m_euler[2] = FloatForKey(e,"angle"); - value = ValueForKey(e,"angles"); - if (value[0] != '\0') - sscanf (value, "%f %f %f", &m_euler[0], &m_euler[2], &m_euler[1]); - UpdateCachedData(); - } - else if(strcmp(key,"modelscale") == 0 || strcmp(key,"modelscale_vec") == 0) - { - VectorSet(m_scale, 1.f, 1.f, 1.f); - value = ValueForKey(e,"modelscale"); - if (value[0] != '\0') - { - float f = atof(value); - if( f != 0 ) - VectorSet(m_scale, f, f, f); - else - Sys_FPrintf(SYS_WRN, "WARNING: ignoring 0 modelscale key\n"); - } - value = ValueForKey(e,"modelscale_vec"); - if (value[0] != '\0') - { - sscanf (value, "%f %f %f", &m_scale[0], &m_scale[1], &m_scale[2]); - if (m_scale[0] == 0.0 && m_scale[1] == 0.0 && m_scale[2] == 0.0) - { - VectorSet(m_scale, 1,1,1); - Sys_FPrintf(SYS_WRN, "WARNING: ignoring 0 0 0 modelscale_vec key\n"); - } - } - UpdateCachedData(); - } - else if(strcmp(key,"origin") == 0) - { - value = ValueForKey(e,"origin"); - sscanf(value, "%f %f %f", &m_translate[0], &m_translate[1], &m_translate[2]); - UpdateCachedData(); - } - else if(strncmp(key,"_remap",6) == 0) - { - unsigned int i; - remap_t *pRemap; - char *ch; - - value = ValueForKey(e,key); - - for(i=0; ilen; i++) - { - pRemap = (remap_t*)m_remaps->pdata[i]; - if(strcmp(key,pRemap->m_key) == 0) - break; - } - - if( i == m_remaps->len ) - { - if( value[0] == '\0' ) - return; - - pRemap = new remap_t; - g_ptr_array_add(m_remaps, pRemap); - } - else if( value[0] == '\0' ) - { - g_ptr_array_remove_index_fast(m_remaps, i); - delete pRemap; - - UpdateShaders(); - return; - } - - strncpy(pRemap->m_remapbuff,value,sizeof(pRemap->m_remapbuff)); - strncpy(pRemap->m_key,key,sizeof(pRemap->m_key)); - - pRemap->m_remap[0] = ch = pRemap->m_remapbuff; - - while( *ch && *ch != ';' ) - ch++; - - if( *ch == '\0' ) - { - // bad remap - Sys_FPrintf(SYS_WRN, "WARNING: Shader _remap key found in misc_model without a ; character\n" ); - g_ptr_array_remove_index_fast(m_remaps, i); - delete pRemap; - return; - } - else - { - *ch = '\0'; - pRemap->m_remap[1] = ch + 1; - } - - UpdateShaders(); - } -} - -// -// CEntityMiscModel -// - -// private: - -void CEntityMiscModel::SetName(const char *name) -{ - if(m_name && *m_name != '\0') { - if(strcmp(m_name, name) == 0) - return; - if( !g_model_cache.DeleteByNameAndFrame(m_name,m_frame) && m_model ) - m_model->RemoveParent( this ); - delete [] m_name; - } - - m_model = NULL; - m_name = new char[strlen(name)+1]; - strcpy(m_name,name); - - if(*m_name != '\0') { - m_model = g_model_cache.GetByNameAndFrame(m_name, m_frame); - m_model->AddParent( this ); - } - - UpdateCachedData(); - UpdateShaders(); -} - -void CEntityMiscModel::SetFrame(const int frame) -{ - if( m_frame == frame ) - return; - - if(m_name && *m_name != '\0') { - if( !g_model_cache.DeleteByNameAndFrame(m_name,m_frame) && m_model ) - m_model->RemoveParent( this ); - } - - m_model = NULL; - - m_frame = frame; - - if(*m_name != '\0') { - m_model = g_model_cache.GetByNameAndFrame(m_name, m_frame); - m_model->AddParent( this ); - } - - UpdateCachedData(); -} - -void CEntityMiscModel::UpdateCachedData() -{ - aabb_t aabb_temp; - bbox_t bbox_temp; - - m4x4_identity(m_transform); - m4x4_pivoted_transform_by_vec3(m_transform, m_translate, m_euler, m_scale, m_pivot); - memcpy(m_inverse_transform, m_transform, sizeof(m4x4_t)); - if(m4x4_invert(m_inverse_transform) == 1) { - Sys_Printf("ERROR: Singular Matrix, cannot invert"); - } - - aabb_clear(&aabb_temp); - - if(m_model) - aabb_extend_by_aabb(&aabb_temp, m_model->GetAABB()); - else - { - if (m_entity->eclass) - VectorSet(aabb_temp.extents, m_entity->eclass->maxs[0], m_entity->eclass->maxs[1], m_entity->eclass->maxs[2]); - else - VectorSet(aabb_temp.extents, 8, 8, 8); - } - - // create an oriented BBox in world-space - bbox_for_oriented_aabb(&bbox_temp, &aabb_temp, m_transform, m_euler, m_scale); - // create an axis aligned bbox in world-space - aabb_for_bbox(&m_BBox, &bbox_temp); - - aabb_update_radius(&m_BBox); -} - -void CEntityMiscModel::UpdateShaders() -{ - unsigned int i, j, numSurfaces; - remap_t *pRemap, *pGlobRemap = NULL; - char *surfShaderName; - IShader **pShader; - - if( !m_model ) - { - if( m_shaders->len ) - { - // free our shaders - for( i = 0; i < m_shaders->len; i++ ) - { - g_ptr_array_remove_index_fast(m_shaders, i); - (*(IShader**)m_shaders->pdata[i])->DecRef(); - delete (IShader**)m_shaders->pdata[i]; - } - } - return; - } - - numSurfaces = m_model->GetNumSurfaces(); - - if( numSurfaces < m_shaders->len ) - { - // free unneeded shader pointers - for( i = m_shaders->len - 1; i >= numSurfaces; i-- ) - { - g_ptr_array_remove_index_fast(m_shaders, i); - (*(IShader**)m_shaders->pdata[i])->DecRef(); - delete (IShader**)m_shaders->pdata[i]; - } - } - - // now go through our surface and find our shaders, remap if needed - for( j = 0; j < numSurfaces; j++ ) - { - surfShaderName = m_model->GetShaderNameForSurface(j); - - if( j < m_shaders->len ) - { - pShader = (IShader **)m_shaders->pdata[j]; - } - else - { - pShader = new (IShader *); - *pShader = NULL; - g_ptr_array_add(m_shaders, pShader); - } - - if( m_remaps->len ) - { - for( i = 0; i < m_remaps->len; i++ ) - { - pRemap = (remap_t*)m_remaps->pdata[i]; - if( stricmp(pRemap->m_remap[0],surfShaderName) == 0 ) - { - // only do the shader lookups if really needed - if( !(*pShader) || stricmp(pRemap->m_remap[1],(*pShader)->getName()) ) - { - if( *pShader ) - (*pShader)->DecRef(); - *pShader = QERApp_Shader_ForName(pRemap->m_remap[1]); - } - - pGlobRemap = NULL; - break; - } - else if( pRemap->m_remap[0][0] == '*' && pRemap->m_remap[0][1] == '\0' ) - pGlobRemap = pRemap; - } - - if( pGlobRemap ) - { - if( !(*pShader) || stricmp(pGlobRemap->m_remap[1],(*pShader)->getName()) ) - { - if( *pShader ) - (*pShader)->DecRef(); - *pShader = QERApp_Shader_ForName(pGlobRemap->m_remap[1]); - } - } - else if( i == m_remaps->len ) - { - // Back to the default one, if needed - if( !(*pShader) || (stricmp(surfShaderName,(*pShader)->getName()) && !(surfShaderName[0] == '\0')) ) - { - if( *pShader ) - (*pShader)->DecRef(); - *pShader = QERApp_Shader_ForName(surfShaderName); - } - } - } - else - { - // Model specified shader, if needed - if( !(*pShader) || (stricmp(surfShaderName,(*pShader)->getName()) && !(surfShaderName[0] == '\0')) ) - { - if( *pShader ) - (*pShader)->DecRef(); - *pShader = QERApp_Shader_ForName(surfShaderName); - } - } - } -} +/* +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 +*/ + +#include + +#include "entitymodel.h" + +extern CModelManager g_model_cache; + +// +// CEntityMiscModel implementation +// + +CEntityMiscModel::CEntityMiscModel () +{ + refCount = 1; + m_name = NULL; + m_model = NULL; + m_entity = NULL; + m_frame = 0; + m_remaps = g_ptr_array_new (); + m_shaders = g_ptr_array_new (); + VectorSet(m_translate, 0,0,0); + VectorSet(m_euler, 0,0,0); + VectorSet(m_scale, 1,1,1); + VectorSet(m_pivot, 0,0,0); + m4x4_identity(m_transform); + m4x4_identity(m_inverse_transform); +} + +typedef struct remap_s { + char m_key[64]; + char m_remapbuff[64+1024]; + char *m_remap[2]; +} remap_t; + +CEntityMiscModel::~CEntityMiscModel () +{ + unsigned int i; + + if(m_name && *m_name != '\0') { + if( !g_model_cache.DeleteByNameAndFrame(m_name,m_frame) && m_model ) + m_model->RemoveParent( this ); + m_model = NULL; + delete [] m_name; + } + + for( i = 0; i < m_remaps->len; i++ ) + delete (remap_t*)m_remaps->pdata[i]; + g_ptr_array_free(m_remaps, FALSE); + + for( i = 0; i < m_shaders->len; i++ ) + { + (*(IShader**)m_shaders->pdata[i])->DecRef(); + delete (IShader**)m_shaders->pdata[i]; + } + g_ptr_array_free(m_shaders, FALSE); + + if(m_entity) { + // This might be just an evasion of the actual problem + m_entity->model.pRender = NULL; + m_entity->model.pSelect = NULL; + m_entity->model.pEdit = NULL; + } +} + +// IRender + +void CEntityMiscModel::Draw(int state, int rflags) const +{ + m4x4_t matrix; + vec3_t pivot; + + memcpy(matrix, m_transform, sizeof(m4x4_t)); + m4x4_transpose(matrix); + + VectorAdd(m_pivot, m_translate, pivot); + pivot_draw(pivot); + + // push the current modelview matrix + // FIXME: put in a check for stack recursion depth.. + // or avoid recursion of opengl matrix stack + g_QglTable.m_pfn_qglPushMatrix(); + // apply the parent-to-local transform + g_QglTable.m_pfn_qglMultMatrixf(matrix); + + // draw children + if(m_model) + m_model->Draw(state, m_shaders, rflags); + + g_QglTable.m_pfn_qglPopMatrix(); +} + +// ISelect + +bool CEntityMiscModel::TestRay(const ray_t *ray, vec_t *dist) const +{ + vec_t dist_start = *dist; + vec_t dist_local = *dist; + ray_t ray_local = *ray; + + if (!aabb_intersect_ray(&m_BBox, &ray_local, &dist_local)) + return false; + + if(m_model){ + ray_transform(&ray_local, m_inverse_transform); + dist_local = dist_start; + if(m_model->TestRay(&ray_local, &dist_local)) + *dist = dist_local; + } else *dist = dist_local; + + return *dist < dist_start; +} + + +//IEdit + +void CEntityMiscModel::Translate(const vec3_t translation) +{ + VectorIncrement(translation, m_translate); + UpdateCachedData(); +} + +void CEntityMiscModel::Rotate(const vec3_t pivot, const vec3_t rotation) +{ + m4x4_t rotation_matrix; + + m4x4_identity(rotation_matrix); + m4x4_pivoted_rotate_by_vec3(rotation_matrix, rotation, pivot); + m4x4_transform_point(rotation_matrix, m_translate); + + VectorIncrement(rotation, m_euler); + + UpdateCachedData(); +} + +void CEntityMiscModel::OnKeyChanged(entity_t *e, const char *key) +{ + const char *value; + + // FIXME: keys are case-sensitive? + + m_entity = e; + + if(strcmp(key,"model") == 0) + SetName(ValueForKey(e,"model")); + else if(strcmp(key,"_frame") == 0) + SetFrame(IntForKey(e,"_frame")); + else if(strcmp(key,"angle") == 0 || strcmp(key,"angles") == 0) + { + VectorSet(m_euler, 0.f, 0.f, 0.f); + m_euler[2] = FloatForKey(e,"angle"); + value = ValueForKey(e,"angles"); + if (value[0] != '\0') + sscanf (value, "%f %f %f", &m_euler[0], &m_euler[2], &m_euler[1]); + UpdateCachedData(); + } + else if(strcmp(key,"modelscale") == 0 || strcmp(key,"modelscale_vec") == 0) + { + VectorSet(m_scale, 1.f, 1.f, 1.f); + value = ValueForKey(e,"modelscale"); + if (value[0] != '\0') + { + float f = atof(value); + if( f != 0 ) + VectorSet(m_scale, f, f, f); + else + Sys_FPrintf(SYS_WRN, "WARNING: ignoring 0 modelscale key\n"); + } + value = ValueForKey(e,"modelscale_vec"); + if (value[0] != '\0') + { + sscanf (value, "%f %f %f", &m_scale[0], &m_scale[1], &m_scale[2]); + if (m_scale[0] == 0.0 && m_scale[1] == 0.0 && m_scale[2] == 0.0) + { + VectorSet(m_scale, 1,1,1); + Sys_FPrintf(SYS_WRN, "WARNING: ignoring 0 0 0 modelscale_vec key\n"); + } + } + UpdateCachedData(); + } + else if(strcmp(key,"origin") == 0) + { + value = ValueForKey(e,"origin"); + sscanf(value, "%f %f %f", &m_translate[0], &m_translate[1], &m_translate[2]); + UpdateCachedData(); + } + else if(strncmp(key,"_remap",6) == 0) + { + unsigned int i; + remap_t *pRemap; + char *ch; + + value = ValueForKey(e,key); + + for(i=0; ilen; i++) + { + pRemap = (remap_t*)m_remaps->pdata[i]; + if(strcmp(key,pRemap->m_key) == 0) + break; + } + + if( i == m_remaps->len ) + { + if( value[0] == '\0' ) + return; + + pRemap = new remap_t; + g_ptr_array_add(m_remaps, pRemap); + } + else if( value[0] == '\0' ) + { + g_ptr_array_remove_index_fast(m_remaps, i); + delete pRemap; + + UpdateShaders(); + return; + } + + strncpy(pRemap->m_remapbuff,value,sizeof(pRemap->m_remapbuff)); + strncpy(pRemap->m_key,key,sizeof(pRemap->m_key)); + + pRemap->m_remap[0] = ch = pRemap->m_remapbuff; + + while( *ch && *ch != ';' ) + ch++; + + if( *ch == '\0' ) + { + // bad remap + Sys_FPrintf(SYS_WRN, "WARNING: Shader _remap key found in misc_model without a ; character\n" ); + g_ptr_array_remove_index_fast(m_remaps, i); + delete pRemap; + return; + } + else + { + *ch = '\0'; + pRemap->m_remap[1] = ch + 1; + } + + UpdateShaders(); + } +} + +// +// CEntityMiscModel +// + +// private: + +void CEntityMiscModel::SetName(const char *name) +{ + if(m_name && *m_name != '\0') { + if(strcmp(m_name, name) == 0) + return; + if( !g_model_cache.DeleteByNameAndFrame(m_name,m_frame) && m_model ) + m_model->RemoveParent( this ); + delete [] m_name; + } + + m_model = NULL; + m_name = new char[strlen(name)+1]; + strcpy(m_name,name); + + if(*m_name != '\0') { + m_model = g_model_cache.GetByNameAndFrame(m_name, m_frame); + m_model->AddParent( this ); + } + + UpdateCachedData(); + UpdateShaders(); +} + +void CEntityMiscModel::SetFrame(const int frame) +{ + if( m_frame == frame ) + return; + + if(m_name && *m_name != '\0') { + if( !g_model_cache.DeleteByNameAndFrame(m_name,m_frame) && m_model ) + m_model->RemoveParent( this ); + } + + m_model = NULL; + + m_frame = frame; + + if(*m_name != '\0') { + m_model = g_model_cache.GetByNameAndFrame(m_name, m_frame); + m_model->AddParent( this ); + } + + UpdateCachedData(); +} + +void CEntityMiscModel::UpdateCachedData() +{ + aabb_t aabb_temp; + bbox_t bbox_temp; + + m4x4_identity(m_transform); + m4x4_pivoted_transform_by_vec3(m_transform, m_translate, m_euler, m_scale, m_pivot); + memcpy(m_inverse_transform, m_transform, sizeof(m4x4_t)); + if(m4x4_invert(m_inverse_transform) == 1) { + Sys_Printf("ERROR: Singular Matrix, cannot invert"); + } + + aabb_clear(&aabb_temp); + + if(m_model) + aabb_extend_by_aabb(&aabb_temp, m_model->GetAABB()); + else + { + if (m_entity->eclass) + VectorSet(aabb_temp.extents, m_entity->eclass->maxs[0], m_entity->eclass->maxs[1], m_entity->eclass->maxs[2]); + else + VectorSet(aabb_temp.extents, 8, 8, 8); + } + + // create an oriented BBox in world-space + bbox_for_oriented_aabb(&bbox_temp, &aabb_temp, m_transform, m_euler, m_scale); + // create an axis aligned bbox in world-space + aabb_for_bbox(&m_BBox, &bbox_temp); + + aabb_update_radius(&m_BBox); +} + +void CEntityMiscModel::UpdateShaders() +{ + unsigned int i, j, numSurfaces; + remap_t *pRemap, *pGlobRemap = NULL; + char *surfShaderName; + IShader **pShader; + + if( !m_model ) + { + if( m_shaders->len ) + { + // free our shaders + for( i = 0; i < m_shaders->len; i++ ) + { + g_ptr_array_remove_index_fast(m_shaders, i); + (*(IShader**)m_shaders->pdata[i])->DecRef(); + delete (IShader**)m_shaders->pdata[i]; + } + } + return; + } + + numSurfaces = m_model->GetNumSurfaces(); + + if( numSurfaces < m_shaders->len ) + { + // free unneeded shader pointers + for( i = m_shaders->len - 1; i >= numSurfaces; i-- ) + { + g_ptr_array_remove_index_fast(m_shaders, i); + (*(IShader**)m_shaders->pdata[i])->DecRef(); + delete (IShader**)m_shaders->pdata[i]; + } + } + + // now go through our surface and find our shaders, remap if needed + for( j = 0; j < numSurfaces; j++ ) + { + surfShaderName = m_model->GetShaderNameForSurface(j); + + if( j < m_shaders->len ) + { + pShader = (IShader **)m_shaders->pdata[j]; + } + else + { + pShader = new (IShader *); + *pShader = NULL; + g_ptr_array_add(m_shaders, pShader); + } + + if( m_remaps->len ) + { + for( i = 0; i < m_remaps->len; i++ ) + { + pRemap = (remap_t*)m_remaps->pdata[i]; + if( stricmp(pRemap->m_remap[0],surfShaderName) == 0 ) + { + // only do the shader lookups if really needed + if( !(*pShader) || stricmp(pRemap->m_remap[1],(*pShader)->getName()) ) + { + if( *pShader ) + (*pShader)->DecRef(); + *pShader = QERApp_Shader_ForName(pRemap->m_remap[1]); + } + + pGlobRemap = NULL; + break; + } + else if( pRemap->m_remap[0][0] == '*' && pRemap->m_remap[0][1] == '\0' ) + pGlobRemap = pRemap; + } + + if( pGlobRemap ) + { + if( !(*pShader) || stricmp(pGlobRemap->m_remap[1],(*pShader)->getName()) ) + { + if( *pShader ) + (*pShader)->DecRef(); + *pShader = QERApp_Shader_ForName(pGlobRemap->m_remap[1]); + } + } + else if( i == m_remaps->len ) + { + // Back to the default one, if needed + if( !(*pShader) || (stricmp(surfShaderName,(*pShader)->getName()) && !(surfShaderName[0] == '\0')) ) + { + if( *pShader ) + (*pShader)->DecRef(); + *pShader = QERApp_Shader_ForName(surfShaderName); + } + } + } + else + { + // Model specified shader, if needed + if( !(*pShader) || (stricmp(surfShaderName,(*pShader)->getName()) && !(surfShaderName[0] == '\0')) ) + { + if( *pShader ) + (*pShader)->DecRef(); + *pShader = QERApp_Shader_ForName(surfShaderName); + } + } + } +} diff --git a/plugins/model/model.cpp b/plugins/model/model.cpp index 70ea078c..1d83f93e 100644 --- a/plugins/model/model.cpp +++ b/plugins/model/model.cpp @@ -1,88 +1,88 @@ -/* -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 -*/ - -#include "plugin.h" -#include "picomodel.h" - -void pivot_draw(const vec3_t pivot) -{ - vec3_t vCenter, vMin, vMax; - VectorCopy(pivot, vCenter); - - g_QglTable.m_pfn_qglPointSize(4); - - g_QglTable.m_pfn_qglBegin(GL_POINTS); - g_QglTable.m_pfn_qglVertex3fv(vCenter); - g_QglTable.m_pfn_qglEnd(); - - g_QglTable.m_pfn_qglBegin(GL_LINES); - vCenter[0] -= 8; - g_QglTable.m_pfn_qglVertex3fv(vCenter); - vCenter[0] += 16; - g_QglTable.m_pfn_qglVertex3fv(vCenter); - vCenter[0] -= 8; - vCenter[1] -= 8; - g_QglTable.m_pfn_qglVertex3fv(vCenter); - vCenter[1] += 16; - g_QglTable.m_pfn_qglVertex3fv(vCenter); - vCenter[1] -= 8; - vCenter[2] -= 8; - g_QglTable.m_pfn_qglVertex3fv(vCenter); - vCenter[2] += 16; - g_QglTable.m_pfn_qglVertex3fv(vCenter); - vCenter[2] -= 8; - g_QglTable.m_pfn_qglEnd(); - - VectorCopy(vCenter, vMin); - VectorCopy(vCenter, vMax); - vMin[0] -= 4; - vMin[1] -= 4; - vMin[2] -= 4; - vMax[0] += 4; - vMax[1] += 4; - vMax[2] += 4; - - g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP); - g_QglTable.m_pfn_qglVertex3f(vMin[0],vMin[1],vMin[2]); - g_QglTable.m_pfn_qglVertex3f(vMax[0],vMin[1],vMin[2]); - g_QglTable.m_pfn_qglVertex3f(vMax[0],vMax[1],vMin[2]); - g_QglTable.m_pfn_qglVertex3f(vMin[0],vMax[1],vMin[2]); - g_QglTable.m_pfn_qglEnd(); - - g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP); - g_QglTable.m_pfn_qglVertex3f(vMin[0],vMin[1],vMax[2]); - g_QglTable.m_pfn_qglVertex3f(vMax[0],vMin[1],vMax[2]); - g_QglTable.m_pfn_qglVertex3f(vMax[0],vMax[1],vMax[2]); - g_QglTable.m_pfn_qglVertex3f(vMin[0],vMax[1],vMax[2]); - g_QglTable.m_pfn_qglEnd(); - - g_QglTable.m_pfn_qglBegin(GL_LINES); - g_QglTable.m_pfn_qglVertex3f(vMin[0],vMin[1],vMin[2]); - g_QglTable.m_pfn_qglVertex3f(vMin[0],vMin[1],vMax[2]); - g_QglTable.m_pfn_qglVertex3f(vMin[0],vMax[1],vMax[2]); - g_QglTable.m_pfn_qglVertex3f(vMin[0],vMax[1],vMin[2]); - g_QglTable.m_pfn_qglVertex3f(vMax[0],vMin[1],vMin[2]); - g_QglTable.m_pfn_qglVertex3f(vMax[0],vMin[1],vMax[2]); - g_QglTable.m_pfn_qglVertex3f(vMax[0],vMax[1],vMax[2]); - g_QglTable.m_pfn_qglVertex3f(vMax[0],vMax[1],vMin[2]); - g_QglTable.m_pfn_qglEnd(); -} - +/* +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 +*/ + +#include "plugin.h" +#include "picomodel.h" + +void pivot_draw(const vec3_t pivot) +{ + vec3_t vCenter, vMin, vMax; + VectorCopy(pivot, vCenter); + + g_QglTable.m_pfn_qglPointSize(4); + + g_QglTable.m_pfn_qglBegin(GL_POINTS); + g_QglTable.m_pfn_qglVertex3fv(vCenter); + g_QglTable.m_pfn_qglEnd(); + + g_QglTable.m_pfn_qglBegin(GL_LINES); + vCenter[0] -= 8; + g_QglTable.m_pfn_qglVertex3fv(vCenter); + vCenter[0] += 16; + g_QglTable.m_pfn_qglVertex3fv(vCenter); + vCenter[0] -= 8; + vCenter[1] -= 8; + g_QglTable.m_pfn_qglVertex3fv(vCenter); + vCenter[1] += 16; + g_QglTable.m_pfn_qglVertex3fv(vCenter); + vCenter[1] -= 8; + vCenter[2] -= 8; + g_QglTable.m_pfn_qglVertex3fv(vCenter); + vCenter[2] += 16; + g_QglTable.m_pfn_qglVertex3fv(vCenter); + vCenter[2] -= 8; + g_QglTable.m_pfn_qglEnd(); + + VectorCopy(vCenter, vMin); + VectorCopy(vCenter, vMax); + vMin[0] -= 4; + vMin[1] -= 4; + vMin[2] -= 4; + vMax[0] += 4; + vMax[1] += 4; + vMax[2] += 4; + + g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMin[1],vMin[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMin[1],vMin[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMax[1],vMin[2]); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMax[1],vMin[2]); + g_QglTable.m_pfn_qglEnd(); + + g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMin[1],vMax[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMin[1],vMax[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMax[1],vMax[2]); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMax[1],vMax[2]); + g_QglTable.m_pfn_qglEnd(); + + g_QglTable.m_pfn_qglBegin(GL_LINES); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMin[1],vMin[2]); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMin[1],vMax[2]); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMax[1],vMax[2]); + g_QglTable.m_pfn_qglVertex3f(vMin[0],vMax[1],vMin[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMin[1],vMin[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMin[1],vMax[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMax[1],vMax[2]); + g_QglTable.m_pfn_qglVertex3f(vMax[0],vMax[1],vMin[2]); + g_QglTable.m_pfn_qglEnd(); +} + diff --git a/plugins/model/plugin.cpp b/plugins/model/plugin.cpp index 6c5d6b95..add809f6 100644 --- a/plugins/model/plugin.cpp +++ b/plugins/model/plugin.cpp @@ -1,434 +1,434 @@ - -/* -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 -*/ - -#include "plugin.h" - -#if 0 // stop using windowing systems in plugins - put the text in SynapseClient::GetInfo -// ============================================================================= -// Utility functions -static void dialog_button_callback (GtkWidget *widget, gpointer data) -{ - GtkWidget *parent; - int *loop, *ret; - - parent = gtk_widget_get_toplevel (widget); - loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); - ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); - - *loop = 0; - *ret = (int)data; -} - -static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) -{ - int *loop; - - gtk_widget_hide (widget); - loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); - *loop = 0; - - return TRUE; -} - -int DoAboutBox( GtkWidget *parent ) -{ - GtkWidget *window, *w, *text, *vbox, *hbox, *hbox2, *frame; - GdkPixmap *pixmap; - GdkBitmap *mask; - GtkStyle *style; - int ret, loop = 1; - char buf[2048]; - const picoModule_t **modules, *pm; - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_signal_connect (GTK_OBJECT (window), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (window), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - gtk_window_set_title (GTK_WINDOW (window), "About..."); - gtk_container_border_width (GTK_CONTAINER (window), 10); - g_object_set_data (G_OBJECT (window), "loop", &loop); - g_object_set_data (G_OBJECT (window), "ret", &ret); - gtk_widget_realize (window); - - if (parent != NULL) - gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (parent)); - - vbox = gtk_vbox_new (FALSE, 10); - gtk_container_add (GTK_CONTAINER (window), vbox); - gtk_widget_show (vbox); - - style = gtk_widget_get_style(window); - - hbox2 = gtk_hbox_new (FALSE, 10); - gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 2); - gtk_widget_show (hbox2); - - frame = gtk_frame_new (NULL); - gtk_box_pack_start (GTK_BOX (hbox2), frame, FALSE, FALSE, 2); - gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); - gtk_widget_show (frame); - - if( g_FuncTable.m_pfnLoadBitmap( "picomodel.bmp", (void **)&pixmap, (void **)&mask ) ) { - w = gtk_pixmap_new (pixmap, mask); - gtk_container_add (GTK_CONTAINER (frame), w); - gtk_widget_show (w); - } - - w = gtk_label_new ("Model Module v1.0 for GtkRadiant\nby Arnout van Meer (rr2do2@splashdamage.com)\n\nBased on the MD3Model Module by SPoG\nPicoModel Library Copyright (c) 2002, Randy Reddig & seaw0lf" ); - gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); - gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); - gtk_widget_show (w); - - w = gtk_scrolled_window_new(NULL, NULL); - gtk_box_pack_start(GTK_BOX(vbox), w, TRUE, TRUE, 2); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(w), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); - gtk_widget_show(w); - - text = gtk_text_new(NULL, NULL); - gtk_text_set_editable(GTK_TEXT(text), FALSE); - gtk_container_add(GTK_CONTAINER(w), text); - - strcpy( buf, "#Supported Model Formats:\n" ); - gtk_text_insert(GTK_TEXT(text), NULL, NULL, NULL, buf, -1); - - for( modules = PicoModuleList( NULL ); *modules != NULL; modules++ ) - { - pm = *modules; - - if( pm == NULL) - break; - - sprintf( buf, "\n%s, version %s, (c) %s", pm->displayName, pm->version, pm->copyright ); - gtk_text_insert(GTK_TEXT(text), NULL, NULL, NULL, buf, -1); - } - - gtk_text_set_word_wrap(GTK_TEXT(text), FALSE); - gtk_widget_show(text); - - gtk_text_set_point(GTK_TEXT(text), 0); - gtk_text_forward_delete(GTK_TEXT(text), 1); - - w = gtk_hseparator_new (); - gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); - gtk_widget_show (w); - - hbox = gtk_hbox_new (FALSE, 10); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); - gtk_widget_show (hbox); - - w = gtk_button_new_with_label ("Ok"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); - gtk_widget_grab_default (w); - gtk_widget_show (w); - ret = IDOK; - - gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); - gtk_widget_show (window); - gtk_grab_add (window); - - while (loop) - gtk_main_iteration (); - - gtk_grab_remove (window); - gtk_widget_destroy (window); - - return ret; -} -#endif - -// toolbar implementation - -class CFlushReloadSelectedToolbarButton : public IToolbarButton -{ -public: - virtual const char* getImage() const - { - return "model_reload_entity.bmp"; - } - virtual const char* getText() const - { - return "Reload"; - } - virtual const char* getTooltip() const - { - return "Flush & Reload Selected Model"; - } - virtual void activate() const - { - DoFlushReloadSelected(); - } - virtual EType getType() const - { - return eButton; - } -}; - -CFlushReloadSelectedToolbarButton g_flushreloadselected; - -unsigned int ToolbarButtonCount() -{ - return 1; -} - -const IToolbarButton* GetToolbarButton(unsigned int index) -{ - return &g_flushreloadselected; -} - -// ============================================================================= -// Pico utility functions - -#include "picomodel.h" - -void PicoPrintFunc( int level, const char *str ) -{ - if( str == NULL ) - return; - switch( level ) - { - case PICO_NORMAL: - Sys_Printf( "%s\n", str ); - break; - - case PICO_VERBOSE: - Sys_FPrintf( SYS_VRB, "%s\n", str ); - break; - - case PICO_WARNING: - Sys_Printf( "WARNING: %s\n", str ); - break; - - case PICO_ERROR: - Sys_FPrintf( SYS_VRB, "ERROR: %s\n", str ); - break; - - case PICO_FATAL: - Sys_Printf( "ERROR: %s\n", str ); - break; - } -} - -void PicoLoadFileFunc( char *name, byte **buffer, int *bufSize ) -{ - *bufSize = vfsLoadFile( (const char*) name, (void**) buffer, 0 ); -} - -void PicoFreeFileFunc( void* file ) -{ - vfsFreeFile(file); -} - -static void initialise() -{ - PicoInit(); - PicoSetMallocFunc( malloc ); - PicoSetFreeFunc( free ); - PicoSetPrintFunc( PicoPrintFunc ); - PicoSetLoadFileFunc( PicoLoadFileFunc ); - PicoSetFreeFileFunc( PicoFreeFileFunc ); -} - -static void add_model_apis(CSynapseClient& client) -{ - const picoModule_t** modules = PicoModuleList( NULL ); - while(*modules != NULL) - { - const picoModule_t* module = *modules++; - if(module->canload && module->load) - for(unsigned int j = 0; module->defaultExts[j] != NULL; j++) - client.AddAPI(MODEL_MAJOR, module->defaultExts[j], sizeof(_QERPlugModelTable)); - } -} - -static bool model_is_supported(const char* extension) -{ - const picoModule_t** modules = PicoModuleList( NULL ); - while(*modules != NULL) - { - const picoModule_t* module = *modules++; - if(module->canload && module->load) - for(unsigned int j = 0; module->defaultExts[j] != NULL; j++) - if(strcmp(extension, module->defaultExts[j]) == 0) - return true; - } - return false; -} - -void init_filetypes() -{ - const picoModule_t **modules = PicoModuleList(NULL); - while(*modules != NULL) - { - const picoModule_t* module = *modules++; - if(module->canload && module->load) - { - for(char*const* ext = module->defaultExts; *ext != NULL; ++ext) - { - char buf[16]; - buf[0] = '*'; - buf[1] = '.'; - strcpy(buf+2, *ext); - GetFileTypeRegistry()->addType(MODEL_MAJOR, filetype_t(module->displayName, buf)); - } - } - } -} - -// plugin implementation - -static const char *PLUGIN_NAME = "Model loading module"; -static const char *PLUGIN_COMMANDS = "Flush & Reload Models,Flush & Reload Selected"; -static const char *PLUGIN_ABOUT = "Model loading module"; - -extern "C" const char* QERPlug_Init (void *hApp, void* pMainWidget) -{ - init_filetypes(); - 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) -{ - if( !strcmp( p, "Flush & Reload Selected" ) ) - DoFlushReloadSelected(); - else if( !strcmp( p, "Flush & Reload Models" ) ) - DoFlushReloadAll(); -} - - -void DoFlushReloadSelected() { -} - -void DoFlushReloadAll() { - GetModelCache()->RefreshAll(); -} - -// ============================================================================= - -// function tables -_QERFuncTable_1 g_FuncTable; -_QERQglTable g_QglTable; -_QERShadersTable g_ShadersTable; -_QERFileSystemTable g_FileSystemTable; - -// ============================================================================= -// SYNAPSE - -CSynapseServer* g_pSynapseServer = NULL; -CSynapseClientModel g_SynapseClient; - -static const XMLConfigEntry_t entries[] = - { { SHADERS_MAJOR, SYN_REQUIRE, sizeof(g_ShadersTable), &g_ShadersTable }, - { VFS_MAJOR, SYN_REQUIRE, sizeof(g_FileSystemTable), &g_FileSystemTable }, - { NULL, SYN_UNKNOWN, 0, NULL } }; - -#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() ); - - initialise(); - - add_model_apis(g_SynapseClient); - g_SynapseClient.AddAPI(TOOLBAR_MAJOR, "model", sizeof(_QERPlugToolbarTable)); - g_SynapseClient.AddAPI(PLUGIN_MAJOR, "model", 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); - - if ( !g_SynapseClient.ConfigXML( pServer, NULL, entries ) ) { - return NULL; - } - - return &g_SynapseClient; -} - -bool CSynapseClientModel::RequestAPI(APIDescriptor_t *pAPI) -{ - if (!strcmp(pAPI->major_name, MODEL_MAJOR)) - { - _QERPlugModelTable* pTable= static_cast<_QERPlugModelTable*>(pAPI->mpTable); - - if (model_is_supported(pAPI->minor_name)) - { - pTable->m_pfnLoadModel = &LoadModel; - return true; - } - } - else if (!strcmp(pAPI->major_name, TOOLBAR_MAJOR)) - { - _QERPlugToolbarTable* pTable= static_cast<_QERPlugToolbarTable*>(pAPI->mpTable); - - pTable->m_pfnToolbarButtonCount = &ToolbarButtonCount; - pTable->m_pfnGetToolbarButton = &GetToolbarButton; - return true; - } - else 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; - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -#include "version.h" - -const char* CSynapseClientModel::GetInfo() -{ - return "picomodel loader module built " __DATE__ " " RADIANT_VERSION; -} - -const char* CSynapseClientModel::GetName() -{ - return "model"; -} + +/* +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 +*/ + +#include "plugin.h" + +#if 0 // stop using windowing systems in plugins - put the text in SynapseClient::GetInfo +// ============================================================================= +// Utility functions +static void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} + +int DoAboutBox( GtkWidget *parent ) +{ + GtkWidget *window, *w, *text, *vbox, *hbox, *hbox2, *frame; + GdkPixmap *pixmap; + GdkBitmap *mask; + GtkStyle *style; + int ret, loop = 1; + char buf[2048]; + const picoModule_t **modules, *pm; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_window_set_title (GTK_WINDOW (window), "About..."); + gtk_container_border_width (GTK_CONTAINER (window), 10); + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + gtk_widget_realize (window); + + if (parent != NULL) + gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (parent)); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + style = gtk_widget_get_style(window); + + hbox2 = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 2); + gtk_widget_show (hbox2); + + frame = gtk_frame_new (NULL); + gtk_box_pack_start (GTK_BOX (hbox2), frame, FALSE, FALSE, 2); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + gtk_widget_show (frame); + + if( g_FuncTable.m_pfnLoadBitmap( "picomodel.bmp", (void **)&pixmap, (void **)&mask ) ) { + w = gtk_pixmap_new (pixmap, mask); + gtk_container_add (GTK_CONTAINER (frame), w); + gtk_widget_show (w); + } + + w = gtk_label_new ("Model Module v1.0 for GtkRadiant\nby Arnout van Meer (rr2do2@splashdamage.com)\n\nBased on the MD3Model Module by SPoG\nPicoModel Library Copyright (c) 2002, Randy Reddig & seaw0lf" ); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + w = gtk_scrolled_window_new(NULL, NULL); + gtk_box_pack_start(GTK_BOX(vbox), w, TRUE, TRUE, 2); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(w), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + gtk_widget_show(w); + + text = gtk_text_new(NULL, NULL); + gtk_text_set_editable(GTK_TEXT(text), FALSE); + gtk_container_add(GTK_CONTAINER(w), text); + + strcpy( buf, "#Supported Model Formats:\n" ); + gtk_text_insert(GTK_TEXT(text), NULL, NULL, NULL, buf, -1); + + for( modules = PicoModuleList( NULL ); *modules != NULL; modules++ ) + { + pm = *modules; + + if( pm == NULL) + break; + + sprintf( buf, "\n%s, version %s, (c) %s", pm->displayName, pm->version, pm->copyright ); + gtk_text_insert(GTK_TEXT(text), NULL, NULL, NULL, buf, -1); + } + + gtk_text_set_word_wrap(GTK_TEXT(text), FALSE); + gtk_widget_show(text); + + gtk_text_set_point(GTK_TEXT(text), 0); + gtk_text_forward_delete(GTK_TEXT(text), 1); + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + ret = IDOK; + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} +#endif + +// toolbar implementation + +class CFlushReloadSelectedToolbarButton : public IToolbarButton +{ +public: + virtual const char* getImage() const + { + return "model_reload_entity.bmp"; + } + virtual const char* getText() const + { + return "Reload"; + } + virtual const char* getTooltip() const + { + return "Flush & Reload Selected Model"; + } + virtual void activate() const + { + DoFlushReloadSelected(); + } + virtual EType getType() const + { + return eButton; + } +}; + +CFlushReloadSelectedToolbarButton g_flushreloadselected; + +unsigned int ToolbarButtonCount() +{ + return 1; +} + +const IToolbarButton* GetToolbarButton(unsigned int index) +{ + return &g_flushreloadselected; +} + +// ============================================================================= +// Pico utility functions + +#include "picomodel.h" + +void PicoPrintFunc( int level, const char *str ) +{ + if( str == NULL ) + return; + switch( level ) + { + case PICO_NORMAL: + Sys_Printf( "%s\n", str ); + break; + + case PICO_VERBOSE: + Sys_FPrintf( SYS_VRB, "%s\n", str ); + break; + + case PICO_WARNING: + Sys_Printf( "WARNING: %s\n", str ); + break; + + case PICO_ERROR: + Sys_FPrintf( SYS_VRB, "ERROR: %s\n", str ); + break; + + case PICO_FATAL: + Sys_Printf( "ERROR: %s\n", str ); + break; + } +} + +void PicoLoadFileFunc( char *name, byte **buffer, int *bufSize ) +{ + *bufSize = vfsLoadFile( (const char*) name, (void**) buffer, 0 ); +} + +void PicoFreeFileFunc( void* file ) +{ + vfsFreeFile(file); +} + +static void initialise() +{ + PicoInit(); + PicoSetMallocFunc( malloc ); + PicoSetFreeFunc( free ); + PicoSetPrintFunc( PicoPrintFunc ); + PicoSetLoadFileFunc( PicoLoadFileFunc ); + PicoSetFreeFileFunc( PicoFreeFileFunc ); +} + +static void add_model_apis(CSynapseClient& client) +{ + const picoModule_t** modules = PicoModuleList( NULL ); + while(*modules != NULL) + { + const picoModule_t* module = *modules++; + if(module->canload && module->load) + for(unsigned int j = 0; module->defaultExts[j] != NULL; j++) + client.AddAPI(MODEL_MAJOR, module->defaultExts[j], sizeof(_QERPlugModelTable)); + } +} + +static bool model_is_supported(const char* extension) +{ + const picoModule_t** modules = PicoModuleList( NULL ); + while(*modules != NULL) + { + const picoModule_t* module = *modules++; + if(module->canload && module->load) + for(unsigned int j = 0; module->defaultExts[j] != NULL; j++) + if(strcmp(extension, module->defaultExts[j]) == 0) + return true; + } + return false; +} + +void init_filetypes() +{ + const picoModule_t **modules = PicoModuleList(NULL); + while(*modules != NULL) + { + const picoModule_t* module = *modules++; + if(module->canload && module->load) + { + for(char*const* ext = module->defaultExts; *ext != NULL; ++ext) + { + char buf[16]; + buf[0] = '*'; + buf[1] = '.'; + strcpy(buf+2, *ext); + GetFileTypeRegistry()->addType(MODEL_MAJOR, filetype_t(module->displayName, buf)); + } + } + } +} + +// plugin implementation + +static const char *PLUGIN_NAME = "Model loading module"; +static const char *PLUGIN_COMMANDS = "Flush & Reload Models,Flush & Reload Selected"; +static const char *PLUGIN_ABOUT = "Model loading module"; + +extern "C" const char* QERPlug_Init (void *hApp, void* pMainWidget) +{ + init_filetypes(); + 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) +{ + if( !strcmp( p, "Flush & Reload Selected" ) ) + DoFlushReloadSelected(); + else if( !strcmp( p, "Flush & Reload Models" ) ) + DoFlushReloadAll(); +} + + +void DoFlushReloadSelected() { +} + +void DoFlushReloadAll() { + GetModelCache()->RefreshAll(); +} + +// ============================================================================= + +// function tables +_QERFuncTable_1 g_FuncTable; +_QERQglTable g_QglTable; +_QERShadersTable g_ShadersTable; +_QERFileSystemTable g_FileSystemTable; + +// ============================================================================= +// SYNAPSE + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientModel g_SynapseClient; + +static const XMLConfigEntry_t entries[] = + { { SHADERS_MAJOR, SYN_REQUIRE, sizeof(g_ShadersTable), &g_ShadersTable }, + { VFS_MAJOR, SYN_REQUIRE, sizeof(g_FileSystemTable), &g_FileSystemTable }, + { NULL, SYN_UNKNOWN, 0, NULL } }; + +#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() ); + + initialise(); + + add_model_apis(g_SynapseClient); + g_SynapseClient.AddAPI(TOOLBAR_MAJOR, "model", sizeof(_QERPlugToolbarTable)); + g_SynapseClient.AddAPI(PLUGIN_MAJOR, "model", 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); + + if ( !g_SynapseClient.ConfigXML( pServer, NULL, entries ) ) { + return NULL; + } + + return &g_SynapseClient; +} + +bool CSynapseClientModel::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, MODEL_MAJOR)) + { + _QERPlugModelTable* pTable= static_cast<_QERPlugModelTable*>(pAPI->mpTable); + + if (model_is_supported(pAPI->minor_name)) + { + pTable->m_pfnLoadModel = &LoadModel; + return true; + } + } + else if (!strcmp(pAPI->major_name, TOOLBAR_MAJOR)) + { + _QERPlugToolbarTable* pTable= static_cast<_QERPlugToolbarTable*>(pAPI->mpTable); + + pTable->m_pfnToolbarButtonCount = &ToolbarButtonCount; + pTable->m_pfnGetToolbarButton = &GetToolbarButton; + return true; + } + else 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; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientModel::GetInfo() +{ + return "picomodel loader module built " __DATE__ " " RADIANT_VERSION; +} + +const char* CSynapseClientModel::GetName() +{ + return "model"; +} diff --git a/plugins/model/remap.cpp b/plugins/model/remap.cpp index dbcef14f..73468ac5 100644 --- a/plugins/model/remap.cpp +++ b/plugins/model/remap.cpp @@ -1,318 +1,318 @@ - -#include "cpicomodel.h" -#include "qertypes.h" - -#include -#include - -#define RADIANT_ASSERT(condition, message) if(!(condition)) { Sys_Printf("ASSERTION FAILURE: " message "\n"); } else - -template -class cache_element -{ -public: - inline cache_element() : m_count(0), m_value(NULL) {} - inline ~cache_element() - { - RADIANT_ASSERT(m_count == 0 , "destroyed a reference before it was released\n"); - if(m_count > 0) - destroy(); - } - inline value_type* capture(const key_type& key) - { - if(++m_count == 1) - construct(key); - return m_value; - } - inline void release() - { - RADIANT_ASSERT(!empty(), "failed to release reference - not found in cache\n"); - if(--m_count == 0) - destroy(); - } - inline bool empty() - { - return m_count == 0; - } - inline void refresh(const key_type& key) - { - m_value->refresh(key); - } -private: - inline void construct(const key_type& key) - { - m_value = new value_type(key); - } - inline void destroy() - { - delete m_value; - } - - unsigned int m_count; - value_type* m_value; -}; - -class ModelCache -{ - typedef CPicoModel value_type; - -public: - typedef PicoModelKey key_type; - typedef cache_element elem_type; - typedef map cache_type; - - value_type* capture(const key_type& key) - { - return m_cache[key].capture(key); - } - void release(const key_type& key) - { - m_cache[key].release(); - } - -private: - cache_type m_cache; -}; - -ModelCache g_model_cache; - - - -typedef struct remap_s { - char m_remapbuff[64+1024]; - char *original; - char *remap; -} remap_t; - -class RemapWrapper : public IRender, public ISelect -{ - unsigned int m_refcount; -public: - RemapWrapper(entity_interfaces_t* model, const char* name) - : m_refcount(1) - { - parse_namestr(name); - - m_model = g_model_cache.capture(ModelCache::key_type(m_name.GetBuffer(), m_frame)); - - model->pRender = this; - model->pRender->IncRef(); - model->pEdit = NULL; - model->pSelect = this; - model->pSelect->IncRef(); - - construct_shaders(); - } - virtual ~RemapWrapper() - { - g_model_cache.release(ModelCache::key_type(m_name.GetBuffer(), m_frame)); - - for(shaders_t::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i) { - (*i)->DecRef(); - } - - for(remaps_t::iterator j = m_remaps.begin(); j != m_remaps.end(); ++j) - { - remap_t *pRemap = (*j); - delete pRemap; - } - m_remaps.clear(); - } - virtual void IncRef() - { - ++m_refcount; - } - virtual void DecRef() - { - if(--m_refcount == 0) - delete this; - } - virtual void Draw(int state, int rflags) const - { - m_model->Draw(state, m_shaders, rflags); - } - virtual const aabb_t *GetAABB() const - { - return m_model->GetAABB(); - } - virtual bool TestRay(const ray_t *ray, vec_t *dist) const - { - return m_model->TestRay(ray, dist); - } -private: - void add_remap(const char *remap) - { - const char *ch; - remap_t *pRemap; - - ch = remap; - - while( *ch && *ch != ';' ) - ch++; - - if( *ch == '\0' ) { - // bad remap - Sys_FPrintf( SYS_WRN, "WARNING: Shader _remap key found in a model entity without a ; character\n" ); - } else { - pRemap = new remap_t; - - strncpy( pRemap->m_remapbuff, remap, sizeof(pRemap->m_remapbuff) ); - - pRemap->m_remapbuff[ch - remap] = '\0'; - - pRemap->original = pRemap->m_remapbuff; - pRemap->remap = pRemap->m_remapbuff + ( ch - remap ) + 1; - - m_remaps.push_back( pRemap ); - } - } - - void parse_namestr(const char *name) - { - const char *ptr, *s; - char buf[1024]; - bool hasName, hasFrame; - - hasName = hasFrame = false; - - for( s = ptr = name; *ptr; ptr++ ) { - if( !hasName && *ptr == ':' ) { - // model name - hasName = true; - strncpy( buf, s, ptr - s ); - buf[ptr - s] = '\0'; - m_name = buf; - s = ptr + 1; - } else if( *ptr == '?' ) { - // model frame - hasFrame = true; - strncpy( buf, s, ptr - s ); - buf[ptr - s] = '\0'; - m_frame = atoi(buf); - s = ptr + 1; - } else if( *ptr == '&' ) { - // a remap - strncpy( buf, s, ptr - s ); - buf[ptr - s] = '\0'; - add_remap( buf ); - s = ptr + 1; - } - } - - if( !hasFrame ) { - // model frame - strncpy( buf, s, ptr - s ); - buf[ptr - s] = '\0'; - m_frame = atoi(buf); - } else { - // a remap - strncpy( buf, s, ptr - s ); - buf[ptr - s] = '\0'; - add_remap( buf ); - } - } - - void construct_shaders() - { - IShader* global_shader = shader_for_remap("*"); - - unsigned int numSurfaces = m_model->GetNumSurfaces(); - m_shaders.reserve(numSurfaces); - // now go through our surface and find our shaders, remap if needed - for(unsigned int j = 0; j < numSurfaces; j++ ) - { - const char* surfShaderName = m_model->GetShaderNameForSurface(j); - IShader* shader = shader_for_remap(surfShaderName); -// m_shaders.push_back((shader) ? shader : (global_shader) ? global_shader : QERApp_Shader_ForName(surfShaderName)); - if( shader ) { - m_shaders.push_back(shader); - } else if( global_shader ) { - m_shaders.push_back(global_shader); - } else { - m_shaders.push_back(QERApp_Shader_ForName(surfShaderName)); - } - } - } - - inline IShader* shader_for_remap(const char* remap) - { - remap_t *pRemap; - remaps_t::iterator i; - for(i = m_remaps.begin(); i != m_remaps.end(); ++i) - { - pRemap = (*i); - if( stricmp( remap, pRemap->original ) == 0 ) - break; - } - return (i != m_remaps.end()) ? QERApp_Shader_ForName(pRemap->remap) : NULL; - } - - Str m_name; - int m_frame; - CPicoModel* m_model; - - typedef vector remaps_t; - remaps_t m_remaps; - typedef vector shaders_t; - shaders_t m_shaders; -}; - -class ModelWrapper : public IRender, public ISelect -{ - unsigned int m_refcount; -public: - ModelWrapper(entity_interfaces_t* model, const char* name) - : m_refcount(1), m_name(name) - { - m_model = g_model_cache.capture(ModelCache::key_type(m_name.GetBuffer(), 0)); - - model->pRender = this; - model->pRender->IncRef(); - model->pEdit = NULL; - model->pSelect = this; - model->pSelect->IncRef(); - } - virtual ~ModelWrapper() - { - g_model_cache.release(ModelCache::key_type(m_name.GetBuffer(), 0)); - } - - virtual void IncRef() - { - ++m_refcount; - } - virtual void DecRef() - { - if(--m_refcount == 0) - delete this; - } - virtual void Draw(int state, int rflags) const - { - m_model->Draw(state, rflags); - } - virtual const aabb_t *GetAABB() const - { - return m_model->GetAABB(); - } - virtual bool TestRay(const ray_t *ray, vec_t *dist) const - { - return m_model->TestRay(ray, dist); - } - - Str m_name; - CPicoModel* m_model; -}; - -void LoadModel(entity_interfaces_t* model, const char* name) -{ - if(strchr(name, ':') != NULL || strchr(name, '?') != NULL || strchr(name, '&') != NULL) - { - RemapWrapper* wrapper = new RemapWrapper(model, name); - wrapper->DecRef(); - } - else - { - ModelWrapper* wrapper = new ModelWrapper(model, name); - wrapper->DecRef(); - } -} + +#include "cpicomodel.h" +#include "qertypes.h" + +#include +#include + +#define RADIANT_ASSERT(condition, message) if(!(condition)) { Sys_Printf("ASSERTION FAILURE: " message "\n"); } else + +template +class cache_element +{ +public: + inline cache_element() : m_count(0), m_value(NULL) {} + inline ~cache_element() + { + RADIANT_ASSERT(m_count == 0 , "destroyed a reference before it was released\n"); + if(m_count > 0) + destroy(); + } + inline value_type* capture(const key_type& key) + { + if(++m_count == 1) + construct(key); + return m_value; + } + inline void release() + { + RADIANT_ASSERT(!empty(), "failed to release reference - not found in cache\n"); + if(--m_count == 0) + destroy(); + } + inline bool empty() + { + return m_count == 0; + } + inline void refresh(const key_type& key) + { + m_value->refresh(key); + } +private: + inline void construct(const key_type& key) + { + m_value = new value_type(key); + } + inline void destroy() + { + delete m_value; + } + + unsigned int m_count; + value_type* m_value; +}; + +class ModelCache +{ + typedef CPicoModel value_type; + +public: + typedef PicoModelKey key_type; + typedef cache_element elem_type; + typedef map cache_type; + + value_type* capture(const key_type& key) + { + return m_cache[key].capture(key); + } + void release(const key_type& key) + { + m_cache[key].release(); + } + +private: + cache_type m_cache; +}; + +ModelCache g_model_cache; + + + +typedef struct remap_s { + char m_remapbuff[64+1024]; + char *original; + char *remap; +} remap_t; + +class RemapWrapper : public IRender, public ISelect +{ + unsigned int m_refcount; +public: + RemapWrapper(entity_interfaces_t* model, const char* name) + : m_refcount(1) + { + parse_namestr(name); + + m_model = g_model_cache.capture(ModelCache::key_type(m_name.GetBuffer(), m_frame)); + + model->pRender = this; + model->pRender->IncRef(); + model->pEdit = NULL; + model->pSelect = this; + model->pSelect->IncRef(); + + construct_shaders(); + } + virtual ~RemapWrapper() + { + g_model_cache.release(ModelCache::key_type(m_name.GetBuffer(), m_frame)); + + for(shaders_t::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i) { + (*i)->DecRef(); + } + + for(remaps_t::iterator j = m_remaps.begin(); j != m_remaps.end(); ++j) + { + remap_t *pRemap = (*j); + delete pRemap; + } + m_remaps.clear(); + } + virtual void IncRef() + { + ++m_refcount; + } + virtual void DecRef() + { + if(--m_refcount == 0) + delete this; + } + virtual void Draw(int state, int rflags) const + { + m_model->Draw(state, m_shaders, rflags); + } + virtual const aabb_t *GetAABB() const + { + return m_model->GetAABB(); + } + virtual bool TestRay(const ray_t *ray, vec_t *dist) const + { + return m_model->TestRay(ray, dist); + } +private: + void add_remap(const char *remap) + { + const char *ch; + remap_t *pRemap; + + ch = remap; + + while( *ch && *ch != ';' ) + ch++; + + if( *ch == '\0' ) { + // bad remap + Sys_FPrintf( SYS_WRN, "WARNING: Shader _remap key found in a model entity without a ; character\n" ); + } else { + pRemap = new remap_t; + + strncpy( pRemap->m_remapbuff, remap, sizeof(pRemap->m_remapbuff) ); + + pRemap->m_remapbuff[ch - remap] = '\0'; + + pRemap->original = pRemap->m_remapbuff; + pRemap->remap = pRemap->m_remapbuff + ( ch - remap ) + 1; + + m_remaps.push_back( pRemap ); + } + } + + void parse_namestr(const char *name) + { + const char *ptr, *s; + char buf[1024]; + bool hasName, hasFrame; + + hasName = hasFrame = false; + + for( s = ptr = name; *ptr; ptr++ ) { + if( !hasName && *ptr == ':' ) { + // model name + hasName = true; + strncpy( buf, s, ptr - s ); + buf[ptr - s] = '\0'; + m_name = buf; + s = ptr + 1; + } else if( *ptr == '?' ) { + // model frame + hasFrame = true; + strncpy( buf, s, ptr - s ); + buf[ptr - s] = '\0'; + m_frame = atoi(buf); + s = ptr + 1; + } else if( *ptr == '&' ) { + // a remap + strncpy( buf, s, ptr - s ); + buf[ptr - s] = '\0'; + add_remap( buf ); + s = ptr + 1; + } + } + + if( !hasFrame ) { + // model frame + strncpy( buf, s, ptr - s ); + buf[ptr - s] = '\0'; + m_frame = atoi(buf); + } else { + // a remap + strncpy( buf, s, ptr - s ); + buf[ptr - s] = '\0'; + add_remap( buf ); + } + } + + void construct_shaders() + { + IShader* global_shader = shader_for_remap("*"); + + unsigned int numSurfaces = m_model->GetNumSurfaces(); + m_shaders.reserve(numSurfaces); + // now go through our surface and find our shaders, remap if needed + for(unsigned int j = 0; j < numSurfaces; j++ ) + { + const char* surfShaderName = m_model->GetShaderNameForSurface(j); + IShader* shader = shader_for_remap(surfShaderName); +// m_shaders.push_back((shader) ? shader : (global_shader) ? global_shader : QERApp_Shader_ForName(surfShaderName)); + if( shader ) { + m_shaders.push_back(shader); + } else if( global_shader ) { + m_shaders.push_back(global_shader); + } else { + m_shaders.push_back(QERApp_Shader_ForName(surfShaderName)); + } + } + } + + inline IShader* shader_for_remap(const char* remap) + { + remap_t *pRemap; + remaps_t::iterator i; + for(i = m_remaps.begin(); i != m_remaps.end(); ++i) + { + pRemap = (*i); + if( stricmp( remap, pRemap->original ) == 0 ) + break; + } + return (i != m_remaps.end()) ? QERApp_Shader_ForName(pRemap->remap) : NULL; + } + + Str m_name; + int m_frame; + CPicoModel* m_model; + + typedef vector remaps_t; + remaps_t m_remaps; + typedef vector shaders_t; + shaders_t m_shaders; +}; + +class ModelWrapper : public IRender, public ISelect +{ + unsigned int m_refcount; +public: + ModelWrapper(entity_interfaces_t* model, const char* name) + : m_refcount(1), m_name(name) + { + m_model = g_model_cache.capture(ModelCache::key_type(m_name.GetBuffer(), 0)); + + model->pRender = this; + model->pRender->IncRef(); + model->pEdit = NULL; + model->pSelect = this; + model->pSelect->IncRef(); + } + virtual ~ModelWrapper() + { + g_model_cache.release(ModelCache::key_type(m_name.GetBuffer(), 0)); + } + + virtual void IncRef() + { + ++m_refcount; + } + virtual void DecRef() + { + if(--m_refcount == 0) + delete this; + } + virtual void Draw(int state, int rflags) const + { + m_model->Draw(state, rflags); + } + virtual const aabb_t *GetAABB() const + { + return m_model->GetAABB(); + } + virtual bool TestRay(const ray_t *ray, vec_t *dist) const + { + return m_model->TestRay(ray, dist); + } + + Str m_name; + CPicoModel* m_model; +}; + +void LoadModel(entity_interfaces_t* model, const char* name) +{ + if(strchr(name, ':') != NULL || strchr(name, '?') != NULL || strchr(name, '&') != NULL) + { + RemapWrapper* wrapper = new RemapWrapper(model, name); + wrapper->DecRef(); + } + else + { + ModelWrapper* wrapper = new ModelWrapper(model, name); + wrapper->DecRef(); + } +} diff --git a/plugins/shaders/plugin.cpp b/plugins/shaders/plugin.cpp index a0339ea1..2a238355 100644 --- a/plugins/shaders/plugin.cpp +++ b/plugins/shaders/plugin.cpp @@ -1,103 +1,103 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -// -// Shaders Plugin -// - -#include "plugin.h" - -// ============================================================================= -// Globals - -// function tables -_QERFuncTable_1 g_FuncTable; -_QERAppDataTable g_DataTable; -_QERQglTable g_QglTable; -_QERAppShadersTable g_ShadersTable; -_QERFileSystemTable g_VFSTable; -_QERScripLibTable g_ScripLibTable; -_QERBrushTable g_BrushTable; - -static bool g_bInterfaceInitDone = false; - -// ============================================================================= -// SYNAPSE - -CSynapseServer* g_pSynapseServer = NULL; -CSynapseClientShaders g_SynapseClient; - -static const XMLConfigEntry_t entries[] = - { - { SHADERS_MAJOR, SYN_PROVIDE, sizeof(_QERShadersTable), NULL }, - { VFS_MAJOR, SYN_REQUIRE, sizeof(g_VFSTable), &g_VFSTable }, - { NULL, SYN_UNKNOWN, 0, NULL } }; - -#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()); - - if ( !g_SynapseClient.ConfigXML( pServer, NULL, entries ) ) { - return NULL; - } - - g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); - g_SynapseClient.AddAPI(DATA_MAJOR, NULL, sizeof(_QERAppDataTable), SYN_REQUIRE, &g_DataTable); - g_SynapseClient.AddAPI(QGL_MAJOR, NULL, sizeof(_QERQglTable), SYN_REQUIRE, &g_QglTable); - g_SynapseClient.AddAPI(APPSHADERS_MAJOR, NULL, sizeof(_QERAppShadersTable), SYN_REQUIRE, &g_ShadersTable); - g_SynapseClient.AddAPI(SCRIPLIB_MAJOR, NULL, sizeof(_QERScripLibTable), SYN_REQUIRE, &g_ScripLibTable); - g_SynapseClient.AddAPI(BRUSH_MAJOR, NULL, sizeof(_QERBrushTable), SYN_REQUIRE, &g_BrushTable); - - return &g_SynapseClient; -} - -#include "version.h" - -const char* CSynapseClientShaders::GetInfo() -{ - return "Q3/Half-Life shaders module built " __DATE__ " " RADIANT_VERSION; -} - -const char* CSynapseClientShaders::GetName() -{ - return "shaders"; -} +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// +// Shaders Plugin +// + +#include "plugin.h" + +// ============================================================================= +// Globals + +// function tables +_QERFuncTable_1 g_FuncTable; +_QERAppDataTable g_DataTable; +_QERQglTable g_QglTable; +_QERAppShadersTable g_ShadersTable; +_QERFileSystemTable g_VFSTable; +_QERScripLibTable g_ScripLibTable; +_QERBrushTable g_BrushTable; + +static bool g_bInterfaceInitDone = false; + +// ============================================================================= +// SYNAPSE + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientShaders g_SynapseClient; + +static const XMLConfigEntry_t entries[] = + { + { SHADERS_MAJOR, SYN_PROVIDE, sizeof(_QERShadersTable), NULL }, + { VFS_MAJOR, SYN_REQUIRE, sizeof(g_VFSTable), &g_VFSTable }, + { NULL, SYN_UNKNOWN, 0, NULL } }; + +#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()); + + if ( !g_SynapseClient.ConfigXML( pServer, NULL, entries ) ) { + return NULL; + } + + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(DATA_MAJOR, NULL, sizeof(_QERAppDataTable), SYN_REQUIRE, &g_DataTable); + g_SynapseClient.AddAPI(QGL_MAJOR, NULL, sizeof(_QERQglTable), SYN_REQUIRE, &g_QglTable); + g_SynapseClient.AddAPI(APPSHADERS_MAJOR, NULL, sizeof(_QERAppShadersTable), SYN_REQUIRE, &g_ShadersTable); + g_SynapseClient.AddAPI(SCRIPLIB_MAJOR, NULL, sizeof(_QERScripLibTable), SYN_REQUIRE, &g_ScripLibTable); + g_SynapseClient.AddAPI(BRUSH_MAJOR, NULL, sizeof(_QERBrushTable), SYN_REQUIRE, &g_BrushTable); + + return &g_SynapseClient; +} + +#include "version.h" + +const char* CSynapseClientShaders::GetInfo() +{ + return "Q3/Half-Life shaders module built " __DATE__ " " RADIANT_VERSION; +} + +const char* CSynapseClientShaders::GetName() +{ + return "shaders"; +} diff --git a/plugins/shaders/shaders.cpp b/plugins/shaders/shaders.cpp index b151c505..c4213b87 100644 --- a/plugins/shaders/shaders.cpp +++ b/plugins/shaders/shaders.cpp @@ -1,989 +1,989 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -// -// Shaders Manager Plugin -// -// Leonardo Zide (leo@lokigames.com) -// - -// standard headers -#include -#include -#include "plugin.h" -#include "mathlib.h" -#include "missing.h" //++timo FIXME: this one is intended to go away some day, it's MFC compatibility classes -#include "shaders.h" - -// some forward declarations -IShader *WINAPI QERApp_Shader_ForName (const char *name); -qtexture_t *WINAPI QERApp_Try_Texture_ForName (const char *name); -qtexture_t *WINAPI QERApp_Texture_ForName2 (const char *filename); -IShader *WINAPI QERApp_ColorShader_ForName (const char *name); -void WINAPI QERApp_LoadShaderFile (const char *filename); - -//++timo TODO: use stl::map !! (I tried having a look to CMap but it obviously sucks) -CShaderArray g_Shaders; -// whenever a shader gets activated / deactivated this list is updated -// NOTE: make sure you don't add a shader that's already in -// NOTE: all shaders in this array are in the main g_Shaders -CShaderArray g_ActiveShaders; - -// clean a texture name to the qtexture_t name format we use internally -// NOTE: there are so many cases .. this may need to get updated to cover all of them -// we expect a "textures/" path on top, except if bAddTexture is set to true .. in case we add in needed -// NOTE: case sensitivity: the engine is case sensitive. we store the shader name with case information and save with case -// information as well. but we assume there won't be any case conflict and so when doing lookups based on shader name, -// we compare as case insensitive. That is Radiant is case insensitive, but knows that the engine is case sensitive. -//++timo FIXME: we need to put code somewhere to detect when two shaders that are case insensitive equal are present -const char *WINAPI QERApp_CleanTextureName (const char *name, bool bAddTexture = false) -{ - static char stdName[QER_MAX_NAMELEN]; -#ifdef _DEBUG - if (strlen(name)>QER_MAX_NAMELEN) - g_FuncTable.m_pfnSysFPrintf(SYS_WRN, "WARNING: name exceeds QER_MAX_NAMELEN in CleanTextureName\n"); -#endif - - strcpy (stdName, name); - g_FuncTable.m_pfnQE_ConvertDOSToUnixName (stdName, stdName); - if (stdName[strlen (name) - 4] == '.') - // strip extension - stdName[strlen (stdName) - 4] = '\0'; - - if (bAddTexture) - { - char aux[QER_MAX_NAMELEN]; - sprintf (aux, "textures/%s", stdName); - strcpy (stdName, aux); - } - return stdName; -} - -int WINAPI QERApp_GetActiveShaderCount () -{ - return g_ActiveShaders.GetSize (); -} - -IShader *WINAPI QERApp_ActiveShader_ForIndex (int i) -{ - return static_cast < CShader * >(g_ActiveShaders.GetAt (i)); -} - -void CShaderArray::SortShaders () -{ - CPtrArray aux; - int i, icount; - int j, jcount; - CShader *pSort; - const char *sSort; - // dumb sort .. would it ever grow big enough so we would have to do something clever? noooo - icount = CPtrArray::GetSize (); - for (i = 0; i < icount; i++) - { - pSort = static_cast < CShader * >(GetAt (i)); - sSort = pSort->getName (); - jcount = aux.GetSize (); - for (j = 0; j < jcount; j++) - { - if (strcmp (sSort, static_cast < CShader * >(aux.GetAt (j))->getName ()) < 0) - break; - } - aux.InsertAt (j, pSort); - } - CPtrArray::RemoveAll (); - CPtrArray::InsertAt (0, &aux); -} - -// will sort the active shaders list by name -// NOTE: it would be easier if the thing would stay sorted by using a map thing -//++timo FIXME: would need to export that to allow external override? -void WINAPI QERApp_SortActiveShaders () -{ - g_ActiveShaders.SortShaders (); -} - -// NOTE: case sensitivity -// although we store shader names with case information, Radiant does case insensitive searches -// (we assume there's no case conflict with the names) -CShader *CShaderArray::Shader_ForName (const char *name) const -{ - int i; - for (i = 0; i < CPtrArray::GetSize (); i++) - { - CShader *pShader = static_cast < CShader * >(CPtrArray::GetAt (i)); - if (stricmp (pShader->getName (), name) == 0) - return pShader; - } - return NULL; -} - -void CShader::CreateDefault (const char *name) -{ - const char *stdName = QERApp_CleanTextureName (name); - m_strTextureName = stdName; - setName (name); -} - -CShader *CShaderArray::Shader_ForTextureName (const char *name) const -{ -#ifdef _DEBUG - // check we were given a texture name that fits the qtexture_t naming conventions - if (strcmp (name, QERApp_CleanTextureName (name)) != 0) - Sys_Printf - ("WARNING: texture name %s doesn't fit qtexture_t conventions in CShaderArray::Shader_ForTextureName\n", - name); -#endif - int i; - for (i = 0; i < CPtrArray::GetSize (); i++) - { - CShader *pShader = static_cast < CShader * >(CPtrArray::GetAt (i)); - if (strcmp (name, QERApp_CleanTextureName (pShader->getTextureName ())) == 0) - return pShader; - } - return NULL; -} - -IShader *WINAPI QERApp_ActiveShader_ForTextureName (char *name) -{ - return g_ActiveShaders.Shader_ForTextureName (name); -} - -void CShaderArray::AddSingle (void *lp) -{ - int i; - for (i = 0; i < CPtrArray::GetSize (); i++) - { - if (CPtrArray::GetAt (i) == lp) - return; - } - CPtrArray::Add (lp); - static_cast < CShader * >(CPtrArray::GetAt (i))->IncRef(); -} - -void CShaderArray::operator = (const class CShaderArray & src) -{ - int i; - -#ifdef _DEBUG - if (CPtrArray::GetSize () != 0) - Sys_Printf ("WARNING: CShaderArray::operator = expects an empty array\n"); -#endif - Copy (src); - // now go through and IncRef - for (i = 0; i < CPtrArray::GetSize (); i++) - static_cast < IShader * >(CPtrArray::GetAt (i))->IncRef (); -} - -//++timo NOTE: for debugging we may need to keep track and tell wether everything has been properly unloaded -void CShaderArray::ReleaseAll () -{ - int i; - int count = CPtrArray::GetSize (); - // decref - for (i = 0; i < count; i++) - static_cast < IShader * >(CPtrArray::GetAt (i))->DecRef (); - // get rid - CPtrArray::RemoveAll (); -} - -// NOTE TTimo: -// this was hacked to work a long time ago -// in Loki's fenris tracker as bug #104655 -// since that info is no longer available, and the hack has been there for so long, it's part of the code now -// don't remember the details, but basically across a flush and reload for the shaders -// we have to keep track of the patches texture names in a seperate entry -// not sure why anymore, but I know that doesn't happen with brushes -typedef struct patchEntry_s -{ - char name[QER_MAX_NAMELEN]; - patchMesh_t *p; -} patchEntry_t; - -CPtrArray PatchShaders; - -void PushPatch (patchMesh_t * patch) -{ - patchEntry_t *pEntry = new patchEntry_s; - pEntry->p = patch; - strcpy (pEntry->name, patch->pShader->getName ()); - PatchShaders.Add (pEntry); -} - -char *ShaderNameLookup (patchMesh_t * patch) -{ - int i; - int count = PatchShaders.GetSize (); - for (i = 0; i < count; i++) - { - if (static_cast < patchEntry_t * >(PatchShaders.GetAt (i))->p == patch) - return static_cast < patchEntry_t * >(PatchShaders.GetAt (i))->name; - } - Sys_Printf ("ERROR: failed to lookup name in ShaderNameLookup??\n"); - return SHADER_NOT_FOUND; -} -//++timo end clean - -// will free all GL binded qtextures and shaders -// NOTE: doesn't make much sense out of Radiant exit or called during a reload -void WINAPI QERApp_FreeShaders () -{ - int i; - brush_t *b; - brush_t *active_brushes; - brush_t *selected_brushes; - brush_t *filtered_brushes; - qtexture_t **d_qtextures; - - active_brushes = g_DataTable.m_pfnActiveBrushes (); - selected_brushes = g_DataTable.m_pfnSelectedBrushes (); - filtered_brushes = g_DataTable.m_pfnFilteredBrushes (); - d_qtextures = g_ShadersTable.m_pfnQTextures (); - - // store the shader names used by the patches - for (i = 0; i < PatchShaders.GetSize (); i++) - delete static_cast < patchMesh_t * >(PatchShaders.GetAt (i)); - PatchShaders.RemoveAll (); - - for (b = active_brushes->next; b != NULL && b != active_brushes; b = b->next) - { - if (b->patchBrush) - PushPatch (b->pPatch); - } - for (b = selected_brushes->next; b != NULL && b != selected_brushes; b = b->next) - { - if (b->patchBrush) - PushPatch (b->pPatch); - } - for (b = filtered_brushes->next; b != NULL && b != filtered_brushes; b = b->next) - { - if (b->patchBrush) - PushPatch (b->pPatch); - } - - // reload shaders - // empty the actives shaders list - g_ActiveShaders.ReleaseAll (); - g_Shaders.ReleaseAll (); - // empty the main g_qeglobals.d_qtextures list - // FIXME: when we reload later on, we need to have the shader names - // for brushes it's stored in the texdef - // but patches don't have texdef - // see bug 104655 for details - // so the solution, build an array of patchMesh_t* and their shader names -#ifdef _DEBUG - Sys_Printf ("FIXME: patch shader reload workaround (old fenris? bug 104655)\n"); -#endif - - //GtkWidget *widget = g_QglTable.m_pfn_GetQeglobalsGLWidget (); - GHashTable *texmap = g_ShadersTable.m_pfnQTexmap (); - - // NOTE: maybe before we'd like to set all qtexture_t in the shaders list to notex? - // NOTE: maybe there are some qtexture_t we don't want to erase? For plain color faces maybe? - while (*d_qtextures) - { - qtexture_t *pTex = *d_qtextures; - qtexture_t *pNextTex = pTex->next; - - //if (widget != NULL) - g_QglTable.m_pfn_qglDeleteTextures (1, &pTex->texture_number); - - g_hash_table_remove (texmap, pTex->name); - - // all qtexture_t should be manipulated with the glib alloc handlers for now - g_free (pTex); - *d_qtextures = pNextTex; - } - - g_QglTable.m_pfn_QE_CheckOpenGLForErrors (); -} - -// those functions are only used during a shader reload phase -// the patch one relies on ShaderNameLookup, a table that is being built only when a flush is performed -// so it's not something we want to expose publicly - -void SetShader (patchMesh_t * patch) -{ - // unhook current shader - patch->pShader->DecRef(); - // don't access this one! it has been deleted .. it's DEAD - patch->d_texture = NULL; - // hook the new one, increment the refcount - // NOTE TTimo this function increments the refcount, don't incref ourselves - patch->pShader = QERApp_Shader_ForName (ShaderNameLookup (patch)); - patch->d_texture = patch->pShader->getTexture (); -} - -void SetShader (face_t * f) -{ - // unhook current shader - f->pShader->DecRef(); - // don't access the texdef! it's DEAD - f->d_texture = NULL; - // hook - // NOTE TTimo this function increments the refcount, don't incref ourselves - f->pShader = QERApp_Shader_ForName (f->texdef.GetName()); - f->d_texture = f->pShader->getTexture (); -} - -void Brush_RefreshShader(brush_t *b) -{ - if (b->patchBrush) - SetShader(b->pPatch); - else if (b->owner->eclass->fixedsize) - { - /*eclass_t *eclass = HasModel(b); - if (eclass) - { - for(entitymodel *model = eclass->model; model!=NULL; model=model->pNext) - if(model && model->strSkin) - model->nTextureBind = g_FuncTable.m_pfnTexture_LoadSkin(((GString *)model->strSkin)->str, &model->nSkinWidth, &model->nSkinHeight); - }*/ - } - else - for (face_t *f=b->brush_faces ; f ; f=f->next) - SetShader(f); -} - -void WINAPI QERApp_ReloadShaders () -{ - brush_t *b; - brush_t *active_brushes; - brush_t *selected_brushes; - brush_t *filtered_brushes; - - QERApp_FreeShaders (); - - g_DataTable.m_pfnLstSkinCache()->RemoveAll(); //md3 skins - - active_brushes = g_DataTable.m_pfnActiveBrushes (); - selected_brushes = g_DataTable.m_pfnSelectedBrushes (); - filtered_brushes = g_DataTable.m_pfnFilteredBrushes (); - - // now we must reload the shader information from shaderfiles - g_ShadersTable.m_pfnBuildShaderList(); - g_ShadersTable.m_pfnPreloadShaders(); - - // refresh the map visuals: replace our old shader objects by the new ones - // on brush faces we have the shader name in texdef.name - // on patches we have the shader name in PatchShaders - // while we walk through the map data, we DecRef the old shaders and push the new ones in - // if all goes well, most of our old shaders will get deleted on the way - - // FIXME: bug 104655, when we come accross a patch, we use the above array since the d_texture is lost - // NOTE: both face_t and patchMesh_t store pointers to the shader and qtexture_t - // in an ideal world they would only store shader and access the qtexture_t through it - // reassign all current shaders - for (b = active_brushes->next; b != NULL && b != active_brushes; b = b->next) - Brush_RefreshShader(b); - for (b = selected_brushes->next; b != NULL && b != selected_brushes; b = b->next) - Brush_RefreshShader(b); - // do that to the filtered brushes as well (we might have some region compiling going on) - for (b = filtered_brushes->next; b != NULL && b != filtered_brushes; b = b->next) - Brush_RefreshShader(b); -} - -int WINAPI QERApp_LoadShadersFromDir (const char *path) -{ - int count = 0; - // scan g_Shaders, and call QERApp_Shader_ForName for each in the given path - // this will load the texture if needed and will set it in use.. - int nSize = g_Shaders.GetSize (); - for (int i = 0; i < nSize; i++) - { - CShader *pShader = reinterpret_cast < CShader * >(g_Shaders[i]); - if (strstr (pShader->getShaderFileName (), path) || strstr (pShader->getName (), path)) - { - count++; - // request the shader, this will load the texture if needed and set "inuse" - //++timo FIXME: should we put an Activate member on CShader? - // this QERApp_Shader_ForName call is a kind of hack - IShader *pFoo = QERApp_Shader_ForName (pShader->getName ()); -#ifdef _DEBUG - // check we activated the right shader - // NOTE: if there was something else loaded, the size of g_Shaders may have changed and strange behaviours are to be expected - if (pFoo != pShader) - Sys_Printf ("WARNING: unexpected pFoo != pShader in QERApp_LoadShadersFromDir\n"); -#else - pFoo = NULL; // leo: shut up the compiler -#endif - } - } - return count; -} - -bool CShader::Parse () -{ - char *token = g_ScripLibTable.m_pfnToken (); - - // the parsing needs to be taken out in another module -// Sys_Printf("TODO: CShader::Parse\n"); - - // token is shader name (full path with a "textures\") - // we remove the "textures\" part - //setName ((char *) &token[9])); - // no we don't - setName (token); - // name of the qtexture_t we'll use to represent this shader (this one has the "textures\" before) - const char *stdName = QERApp_CleanTextureName (token); - m_strTextureName = stdName; // FIXME: BC reports stdName is uninitialised? - g_ScripLibTable.m_pfnGetToken (true); - if (strcmp (token, "{")) - return false; - else - { - // we need to read until we hit a balanced } - int nMatch = 1; - while (nMatch > 0 && g_ScripLibTable.m_pfnGetToken (true)) - { - if (strcmp (token, "{") == 0) - { - nMatch++; - continue; - } - else if (strcmp (token, "}") == 0) - { - nMatch--; - continue; - } - if (nMatch > 1) continue; // ignore layers for now - if (strcmpi (token, "qer_nocarve") == 0) - { - m_nFlags |= QER_NOCARVE; - } - else if (strcmpi (token, "qer_trans") == 0) - { - if (g_ScripLibTable.m_pfnGetToken (true)) - { - m_fTrans = (float) atof (token); - } - m_nFlags |= QER_TRANS; - } - else if (strcmpi (token, "qer_editorimage") == 0) - { - if (g_ScripLibTable.m_pfnGetToken (true)) - { - // bAddTexture changed to false to allow editorimages in other locations than "textures/" - m_strTextureName = QERApp_CleanTextureName (token, false); - } - } - else if (strcmpi (token, "qer_alphafunc") == 0) - { - if (g_ScripLibTable.m_pfnGetToken (true)) - { - - if(stricmp( token, "greater" ) == 0 ) - { - m_nAlphaFunc = GL_GREATER; - } - else if(stricmp( token, "less" ) == 0 ) - { - m_nAlphaFunc = GL_LESS; - } - else if(stricmp( token, "gequal" ) == 0 ) - { - m_nAlphaFunc = GL_GEQUAL; - } - - if( m_nAlphaFunc ) - m_nFlags |= QER_ALPHAFUNC; - } - if (g_ScripLibTable.m_pfnGetToken (true)) - { - m_fAlphaRef = (float) atof (token); - } - } - else if (strcmpi (token, "cull") == 0) - { - if (g_ScripLibTable.m_pfnGetToken (true)) - { - if( stricmp( token, "none" ) == 0 || stricmp( token, "twosided" ) == 0 || stricmp( token, "disable" ) == 0 ) - { - m_nCull = 2; - } - else if( stricmp( token, "back" ) == 0 || stricmp( token, "backside" ) == 0 || stricmp( token, "backsided" ) == 0 ) - { - m_nCull = 1; - } - - if( m_nCull ) - m_nFlags |= QER_CULL; - } - } - else if (strcmpi (token, "surfaceparm") == 0) - { - if (g_ScripLibTable.m_pfnGetToken (true)) - { - if (strcmpi (token, "fog") == 0) - { - m_nFlags |= QER_FOG; - if (m_fTrans == 1.0f) // has not been explicitly set by qer_trans - { - m_fTrans = 0.35f; - } - } - else if (strcmpi (token, "nodraw") == 0) - { - m_nFlags |= QER_NODRAW; - } - else if (strcmpi (token, "nonsolid") == 0) - { - m_nFlags |= QER_NONSOLID; - } - else if (strcmpi (token, "water") == 0) - { - m_nFlags |= QER_WATER; - } - else if (strcmpi (token, "lava") == 0) - { - m_nFlags |= QER_LAVA; - } - } - } - } - if (nMatch != 0) - return false; - } - return true; -} - -void CShader::RegisterActivate () -{ - // fill the qtexture_t with shader information - //++timo FIXME: a lot of that won't be necessary, will be stored at IShader* level -// strcpy (m_pTexture->shadername, m_Name); - // this flag is set only if we have a shaderfile name -// if (m_ShaderFileName[0] != '\0') -// m_pTexture->bFromShader = true; -// else -// m_pTexture->bFromShader = false; - //++timo FIXME: what do we do with that? - //m_pTexture->fTrans = pInfo->m_fTransValue; -// m_pTexture->fTrans = 1.0f; // if != 1.0 it's ot getting drawn in Cam_Draw -// m_pTexture->nShaderFlags = m_nFlags; - // store in the active shaders list (if necessary) - g_ActiveShaders.AddSingle (this); - // when you activate a shader, it gets displayed in the texture browser - m_bDisplayed = true; - IncRef (); -} - -void CShader::Try_Activate () -{ - m_pTexture = QERApp_Try_Texture_ForName (m_strTextureName.GetBuffer()); - if (m_pTexture) - RegisterActivate (); -} - -// Hydra: now returns false if the ORIGINAL shader could not be activated -// (missing texture, or incorrect shader script), true otherwise -// the shader is still activated in all cases. -bool CShader::Activate () -{ - Try_Activate (); - if (!m_pTexture) - { - m_pTexture = QERApp_Texture_ForName2 (SHADER_NOTEX); - RegisterActivate (); - return false; - } - return true; -} - -void WINAPI QERApp_LoadShaderFile (const char *filename) -{ - char *pBuff; - int nSize = vfsLoadFile (filename, reinterpret_cast < void **>(&pBuff), 0); - if (nSize > 0) - { - Sys_Printf ("Parsing shaderfile %s\n", filename); - g_ScripLibTable.m_pfnStartTokenParsing (pBuff); - while (g_ScripLibTable.m_pfnGetToken (true)) - { - // first token should be the path + name.. (from base) - CShader *pShader = new CShader (); - // we want the relative filename only, it's easier for later lookup .. see QERApp_ReloadShaderFile - char cTmp[1024]; - g_FuncTable.m_pfnQE_ConvertDOSToUnixName (cTmp, filename); - // given the vfs, we should not store the full path - //pShader->setShaderFileName( filename + strlen(ValueForKey(g_qeglobals.d_project_entity, "basepath"))); - pShader->setShaderFileName (filename); - if (pShader->Parse ()) - { - // do we already have this shader? - //++timo NOTE: this may a bit slow, we may need to use a map instead of a dumb list - if (g_Shaders.Shader_ForName (pShader->getName ()) != NULL) - { -#ifdef _DEBUG - Sys_Printf ("WARNING: shader %s is already in memory, definition in %s ignored.\n", - pShader->getName (), filename); -#endif - delete pShader; - } - else - { - pShader->IncRef (); - - g_Shaders.Add ((void *) pShader); - } - } - else - { - Sys_Printf ("Error parsing shader %s\n", pShader->getName ()); - delete pShader; - } - } - vfsFreeFile (pBuff); - } - else - { - Sys_Printf ("Unable to read shaderfile %s\n", filename); - } -} - -IShader *WINAPI QERApp_Try_Shader_ForName (const char *name) -{ - // look for the shader - CShader *pShader = g_Shaders.Shader_ForName (name); - if (!pShader) - // not found - return NULL; - // we may need to load the texture or use the "shader without texture" one - pShader->Activate (); - pShader->SetDisplayed (true); - return pShader; -} - -IShader *WINAPI QERApp_CreateShader_ForTextureName (const char *name) -{ - CShader *pShader; - pShader = new CShader; - // CreateDefault expects a texture / shader name relative to the "textures" directory - // (cause shader names are reletive to "textures/") - pShader->CreateDefault (name); - // hook it into the shader list - g_Shaders.Add ((void *) pShader); - pShader->IncRef (); - // if it can't find the texture, SHADER_NOT_FOUND will be used - // Hydra: display an error message, so the user can quickly find a list of missing - // textures by looking at the console. - if (!pShader->Activate ()) - { - Sys_Printf ("WARNING: Activate shader failed for %s\n",pShader->getName()); - } - pShader->SetDisplayed (true); - - return pShader; -} - -IShader *WINAPI QERApp_Shader_ForName (const char *name) -{ - if (name == NULL || strlen (name) == 0) - { - // Hydra: This error can occur if the user loaded a map with/dropped an entity that - // did not set a texture name "(r g b)" - check the entity definition loader - - g_FuncTable.m_pfnSysFPrintf (SYS_ERR, "FIXME: name == NULL || strlen(name) == 0 in QERApp_Shader_ForName\n"); - return QERApp_Shader_ForName (SHADER_NOT_FOUND); - } - // entities that should be represented with plain colors instead of textures - // request a texture name with (r g b) (it's stored in their class_t) - if (name[0] == '(') - { - return QERApp_ColorShader_ForName (name); - } - - CShader *pShader = static_cast < CShader * >(QERApp_Try_Shader_ForName (name)); - if (pShader) - { - pShader->SetDisplayed (true); - return pShader; - } - return QERApp_CreateShader_ForTextureName (name); -} - -qtexture_t *WINAPI QERApp_Try_Texture_ForName (const char *name) -{ - qtexture_t *q; -// char f1[1024], f2[1024]; - unsigned char *pPixels = NULL; - int nWidth, nHeight; - - // convert the texture name to the standard format we use in qtexture_t - const char *stdName = QERApp_CleanTextureName (name); - - // use the hash table - q = (qtexture_t*)g_hash_table_lookup (g_ShadersTable.m_pfnQTexmap (), stdName); - if (q) - return q; - -#ifdef QTEXMAP_DEBUG - for (q = g_qeglobals.d_qtextures; q; q = q->next) - { - if (!strcmp (stdName, q->name)) - { - Sys_Printf ("ERROR: %s is not in texture map, but was found in texture list\n"); - return q; - } - } -#endif - - g_FuncTable.m_pfnLoadImage (name, &pPixels, &nWidth, &nHeight); - - if (!pPixels) - return NULL; // we failed - else - Sys_Printf ("LOADED: %s\n", name); - - // instanciate a new qtexture_t - // NOTE: when called by a plugin we must make sure we have set Radiant's GL context before binding the texture - - // we'll be binding the GL texture now - // need to check we are using a right GL context - // with GL plugins that have their own window, the GL context may be the plugin's, in which case loading textures will bug - // g_QglTable.m_pfn_glwidget_make_current (g_QglTable.m_pfn_GetQeglobalsGLWidget ()); - q = g_FuncTable.m_pfnLoadTextureRGBA (pPixels, nWidth, nHeight); - if (!q) - return NULL; - g_free (pPixels); - - strcpy (q->name, name); - // only strip extension if extension there is! - if (q->name[strlen (q->name) - 4] == '.') - q->name[strlen (q->name) - 4] = '\0'; - // hook into the main qtexture_t list - qtexture_t **d_qtextures = g_ShadersTable.m_pfnQTextures (); - q->next = *d_qtextures; - *d_qtextures = q; - // push it in the map - g_hash_table_insert (g_ShadersTable.m_pfnQTexmap (), q->name, q); - return q; -} - -int WINAPI QERApp_HasShader (const char *pName) -{ - // mickey check the global shader array for existense of pName - CShader *pShader = g_Shaders.Shader_ForName (pName); - if (pShader) - return 1; - return 0; -} - -IShader *WINAPI QERApp_Shader_ForName_NoLoad (const char *pName) -{ - CShader *pShader = g_Shaders.Shader_ForName (pName); - return pShader; -} - -/*! -This should NEVER return NULL, it is the last-chance call in the load cascade -*/ -qtexture_t *WINAPI QERApp_Texture_ForName2 (const char *filename) -{ - qtexture_t *q; - q = QERApp_Try_Texture_ForName (filename); - if (q) - return q; - // not found? use "texture not found" - q = QERApp_Try_Texture_ForName (SHADER_NOT_FOUND); - if (q) - return q; - - // still not found? this is a fatal error - g_FuncTable.m_pfnError("Failed to load " SHADER_NOT_FOUND ". Looks like your installation is broken / missing some essential elements."); - return NULL; -} - -void CShader::CreateColor (const char *name) -{ - // parse - sscanf (name, "(%g %g %g)", m_vColor, m_vColor + 1, m_vColor + 2); - m_strTextureName = name; - setName ("color"); - // create the qtexture_t - qtexture_t *q1 = QERApp_Texture_ForName2 (SHADER_NOT_FOUND); - // copy this one - qtexture_t *q2 = new qtexture_t; - memcpy (q2, q1, sizeof (qtexture_t)); - strcpy (q2->name, m_strTextureName.GetBuffer ()); - VectorCopy (m_vColor, q2->color); - m_pTexture = q2; -} - -IShader *WINAPI QERApp_ColorShader_ForName (const char *name) -{ - CShader *pShader = new CShader (); - pShader->CreateColor (name); - // hook it into the shader list - pShader->IncRef (); - g_Shaders.Add ((void *) pShader); - return pShader; -} - -void CShaderArray::ReleaseForShaderFile (const char *name) -{ - int i; - // decref - for (i = 0; i < CPtrArray::GetSize (); i++) - { - IShader *pShader = static_cast < IShader * >(CPtrArray::GetAt (i)); - if (!strcmp (name, pShader->getShaderFileName ())) - { - pShader->DecRef (); - CPtrArray::RemoveAt (i); - i--; // get ready for next loop - } - } -} - -void WINAPI QERApp_ReloadShaderFile (const char *name) -{ - brush_t *b; - face_t *f; - brush_t *active_brushes; - brush_t *selected_brushes; - brush_t *filtered_brushes; - -// Sys_Printf("TODO: QERApp_ReloadShaderFile\n"); - - active_brushes = g_DataTable.m_pfnActiveBrushes (); - selected_brushes = g_DataTable.m_pfnSelectedBrushes (); - filtered_brushes = g_DataTable.m_pfnFilteredBrushes (); - -#ifdef _DEBUG - // check the shader name is a reletive path - // I hacked together a few quick tests to make sure :-) - if (strstr (name, ":\\") || !strstr (name, "scripts")) - Sys_Printf ("WARNING: is %s a reletive path to a shader file? (QERApp_ReloadShaderFile\n"); -#endif - - // in the actives and global shaders lists, decref and unhook the shaders - //++timo NOTE: maybe we'd like to keep track of the shaders we are unhooking? - g_ActiveShaders.ReleaseForShaderFile (name); - g_Shaders.ReleaseForShaderFile (name); - // go through a reload of the shader file - QERApp_LoadShaderFile (name); - // scan all the brushes, replace all the old ones by refs to their new equivalents - for (b = active_brushes->next; b != NULL && b != active_brushes; b = b->next) - { - if (b->patchBrush && !strcmp (b->pPatch->pShader->getShaderFileName (), name)) - SetShader (b->pPatch); - else - for (f = b->brush_faces; f; f = f->next) - if (!strcmp (f->pShader->getShaderFileName (), name)) - SetShader (f); - } - for (b = selected_brushes->next; b != NULL && b != selected_brushes; b = b->next) - { - if (b->patchBrush && !strcmp (b->pPatch->pShader->getShaderFileName (), name)) - SetShader (b->pPatch); - else - for (f = b->brush_faces; f; f = f->next) - if (!strcmp (f->pShader->getShaderFileName (), name)) - SetShader (f); - } - // do that to the filtered brushes as well (we might have some region compiling going on) - for (b = filtered_brushes->next; b != NULL && b != filtered_brushes; b = b->next) - { - if (b->patchBrush && !strcmp (b->pPatch->pShader->getShaderFileName (), name)) - SetShader (b->pPatch); - else - for (f = b->brush_faces; f; f = f->next) - if (!strcmp (f->pShader->getShaderFileName (), name)) - SetShader (f); - } - // call Texture_ShowInUse to clean and display only what's required - g_ShadersTable.m_pfnTexture_ShowInuse (); - QERApp_SortActiveShaders (); - g_FuncTable.m_pfnSysUpdateWindows (W_TEXTURE); -} - -void CShaderArray::SetDisplayed (bool b) -{ - int i, count; - count = CPtrArray::GetSize (); - for (i = 0; i < count; i++) - static_cast < IShader * >(CPtrArray::GetAt (i))->SetDisplayed (b); -} - -void CShaderArray::SetInUse (bool b) -{ - int i, count; - count = CPtrArray::GetSize (); - for (i = 0; i < count; i++) - static_cast < IShader * >(CPtrArray::GetAt (i))->SetInUse (b); -} - -// Set the IsDisplayed flag on all active shaders -void WINAPI QERApp_ActiveShaders_SetDisplayed (bool b) -{ - g_ActiveShaders.SetDisplayed (b); -} - -void WINAPI QERApp_ActiveShaders_SetInUse (bool b) -{ - g_ActiveShaders.SetInUse (b); -} - -// ============================================================================= -// SYNAPSE - -bool CSynapseClientShaders::RequestAPI(APIDescriptor_t *pAPI) -{ - if (!strcmp(pAPI->major_name, SHADERS_MAJOR)) - { - _QERShadersTable* pTable= static_cast<_QERShadersTable*>(pAPI->mpTable); - - pTable->m_pfnFreeShaders = QERApp_FreeShaders; - pTable->m_pfnReloadShaders = QERApp_ReloadShaders; - pTable->m_pfnLoadShadersFromDir = QERApp_LoadShadersFromDir; - pTable->m_pfnReloadShaderFile = QERApp_ReloadShaderFile; - pTable->m_pfnLoadShaderFile = QERApp_LoadShaderFile; - pTable->m_pfnHasShader = QERApp_HasShader; - pTable->m_pfnTry_Shader_ForName = QERApp_Try_Shader_ForName; - pTable->m_pfnShader_ForName = QERApp_Shader_ForName; - pTable->m_pfnTry_Texture_ForName = QERApp_Try_Texture_ForName; - pTable->m_pfnTexture_ForName = QERApp_Texture_ForName2; - pTable->m_pfnGetActiveShaderCount = QERApp_GetActiveShaderCount; - pTable->m_pfnColorShader_ForName = QERApp_ColorShader_ForName; - pTable->m_pfnShader_ForName_NoLoad = QERApp_Shader_ForName_NoLoad; - pTable->m_pfnActiveShaders_SetInUse = QERApp_ActiveShaders_SetInUse; - pTable->m_pfnSortActiveShaders = QERApp_SortActiveShaders; - pTable->m_pfnActiveShader_ForTextureName = QERApp_ActiveShader_ForTextureName; - pTable->m_pfnCreateShader_ForTextureName = QERApp_CreateShader_ForTextureName; - pTable->m_pfnActiveShaders_SetDisplayed = QERApp_ActiveShaders_SetDisplayed; - pTable->m_pfnActiveShader_ForIndex = QERApp_ActiveShader_ForIndex; - pTable->m_pfnCleanTextureName = QERApp_CleanTextureName; - - return true; - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// +// Shaders Manager Plugin +// +// Leonardo Zide (leo@lokigames.com) +// + +// standard headers +#include +#include +#include "plugin.h" +#include "mathlib.h" +#include "missing.h" //++timo FIXME: this one is intended to go away some day, it's MFC compatibility classes +#include "shaders.h" + +// some forward declarations +IShader *WINAPI QERApp_Shader_ForName (const char *name); +qtexture_t *WINAPI QERApp_Try_Texture_ForName (const char *name); +qtexture_t *WINAPI QERApp_Texture_ForName2 (const char *filename); +IShader *WINAPI QERApp_ColorShader_ForName (const char *name); +void WINAPI QERApp_LoadShaderFile (const char *filename); + +//++timo TODO: use stl::map !! (I tried having a look to CMap but it obviously sucks) +CShaderArray g_Shaders; +// whenever a shader gets activated / deactivated this list is updated +// NOTE: make sure you don't add a shader that's already in +// NOTE: all shaders in this array are in the main g_Shaders +CShaderArray g_ActiveShaders; + +// clean a texture name to the qtexture_t name format we use internally +// NOTE: there are so many cases .. this may need to get updated to cover all of them +// we expect a "textures/" path on top, except if bAddTexture is set to true .. in case we add in needed +// NOTE: case sensitivity: the engine is case sensitive. we store the shader name with case information and save with case +// information as well. but we assume there won't be any case conflict and so when doing lookups based on shader name, +// we compare as case insensitive. That is Radiant is case insensitive, but knows that the engine is case sensitive. +//++timo FIXME: we need to put code somewhere to detect when two shaders that are case insensitive equal are present +const char *WINAPI QERApp_CleanTextureName (const char *name, bool bAddTexture = false) +{ + static char stdName[QER_MAX_NAMELEN]; +#ifdef _DEBUG + if (strlen(name)>QER_MAX_NAMELEN) + g_FuncTable.m_pfnSysFPrintf(SYS_WRN, "WARNING: name exceeds QER_MAX_NAMELEN in CleanTextureName\n"); +#endif + + strcpy (stdName, name); + g_FuncTable.m_pfnQE_ConvertDOSToUnixName (stdName, stdName); + if (stdName[strlen (name) - 4] == '.') + // strip extension + stdName[strlen (stdName) - 4] = '\0'; + + if (bAddTexture) + { + char aux[QER_MAX_NAMELEN]; + sprintf (aux, "textures/%s", stdName); + strcpy (stdName, aux); + } + return stdName; +} + +int WINAPI QERApp_GetActiveShaderCount () +{ + return g_ActiveShaders.GetSize (); +} + +IShader *WINAPI QERApp_ActiveShader_ForIndex (int i) +{ + return static_cast < CShader * >(g_ActiveShaders.GetAt (i)); +} + +void CShaderArray::SortShaders () +{ + CPtrArray aux; + int i, icount; + int j, jcount; + CShader *pSort; + const char *sSort; + // dumb sort .. would it ever grow big enough so we would have to do something clever? noooo + icount = CPtrArray::GetSize (); + for (i = 0; i < icount; i++) + { + pSort = static_cast < CShader * >(GetAt (i)); + sSort = pSort->getName (); + jcount = aux.GetSize (); + for (j = 0; j < jcount; j++) + { + if (strcmp (sSort, static_cast < CShader * >(aux.GetAt (j))->getName ()) < 0) + break; + } + aux.InsertAt (j, pSort); + } + CPtrArray::RemoveAll (); + CPtrArray::InsertAt (0, &aux); +} + +// will sort the active shaders list by name +// NOTE: it would be easier if the thing would stay sorted by using a map thing +//++timo FIXME: would need to export that to allow external override? +void WINAPI QERApp_SortActiveShaders () +{ + g_ActiveShaders.SortShaders (); +} + +// NOTE: case sensitivity +// although we store shader names with case information, Radiant does case insensitive searches +// (we assume there's no case conflict with the names) +CShader *CShaderArray::Shader_ForName (const char *name) const +{ + int i; + for (i = 0; i < CPtrArray::GetSize (); i++) + { + CShader *pShader = static_cast < CShader * >(CPtrArray::GetAt (i)); + if (stricmp (pShader->getName (), name) == 0) + return pShader; + } + return NULL; +} + +void CShader::CreateDefault (const char *name) +{ + const char *stdName = QERApp_CleanTextureName (name); + m_strTextureName = stdName; + setName (name); +} + +CShader *CShaderArray::Shader_ForTextureName (const char *name) const +{ +#ifdef _DEBUG + // check we were given a texture name that fits the qtexture_t naming conventions + if (strcmp (name, QERApp_CleanTextureName (name)) != 0) + Sys_Printf + ("WARNING: texture name %s doesn't fit qtexture_t conventions in CShaderArray::Shader_ForTextureName\n", + name); +#endif + int i; + for (i = 0; i < CPtrArray::GetSize (); i++) + { + CShader *pShader = static_cast < CShader * >(CPtrArray::GetAt (i)); + if (strcmp (name, QERApp_CleanTextureName (pShader->getTextureName ())) == 0) + return pShader; + } + return NULL; +} + +IShader *WINAPI QERApp_ActiveShader_ForTextureName (char *name) +{ + return g_ActiveShaders.Shader_ForTextureName (name); +} + +void CShaderArray::AddSingle (void *lp) +{ + int i; + for (i = 0; i < CPtrArray::GetSize (); i++) + { + if (CPtrArray::GetAt (i) == lp) + return; + } + CPtrArray::Add (lp); + static_cast < CShader * >(CPtrArray::GetAt (i))->IncRef(); +} + +void CShaderArray::operator = (const class CShaderArray & src) +{ + int i; + +#ifdef _DEBUG + if (CPtrArray::GetSize () != 0) + Sys_Printf ("WARNING: CShaderArray::operator = expects an empty array\n"); +#endif + Copy (src); + // now go through and IncRef + for (i = 0; i < CPtrArray::GetSize (); i++) + static_cast < IShader * >(CPtrArray::GetAt (i))->IncRef (); +} + +//++timo NOTE: for debugging we may need to keep track and tell wether everything has been properly unloaded +void CShaderArray::ReleaseAll () +{ + int i; + int count = CPtrArray::GetSize (); + // decref + for (i = 0; i < count; i++) + static_cast < IShader * >(CPtrArray::GetAt (i))->DecRef (); + // get rid + CPtrArray::RemoveAll (); +} + +// NOTE TTimo: +// this was hacked to work a long time ago +// in Loki's fenris tracker as bug #104655 +// since that info is no longer available, and the hack has been there for so long, it's part of the code now +// don't remember the details, but basically across a flush and reload for the shaders +// we have to keep track of the patches texture names in a seperate entry +// not sure why anymore, but I know that doesn't happen with brushes +typedef struct patchEntry_s +{ + char name[QER_MAX_NAMELEN]; + patchMesh_t *p; +} patchEntry_t; + +CPtrArray PatchShaders; + +void PushPatch (patchMesh_t * patch) +{ + patchEntry_t *pEntry = new patchEntry_s; + pEntry->p = patch; + strcpy (pEntry->name, patch->pShader->getName ()); + PatchShaders.Add (pEntry); +} + +char *ShaderNameLookup (patchMesh_t * patch) +{ + int i; + int count = PatchShaders.GetSize (); + for (i = 0; i < count; i++) + { + if (static_cast < patchEntry_t * >(PatchShaders.GetAt (i))->p == patch) + return static_cast < patchEntry_t * >(PatchShaders.GetAt (i))->name; + } + Sys_Printf ("ERROR: failed to lookup name in ShaderNameLookup??\n"); + return SHADER_NOT_FOUND; +} +//++timo end clean + +// will free all GL binded qtextures and shaders +// NOTE: doesn't make much sense out of Radiant exit or called during a reload +void WINAPI QERApp_FreeShaders () +{ + int i; + brush_t *b; + brush_t *active_brushes; + brush_t *selected_brushes; + brush_t *filtered_brushes; + qtexture_t **d_qtextures; + + active_brushes = g_DataTable.m_pfnActiveBrushes (); + selected_brushes = g_DataTable.m_pfnSelectedBrushes (); + filtered_brushes = g_DataTable.m_pfnFilteredBrushes (); + d_qtextures = g_ShadersTable.m_pfnQTextures (); + + // store the shader names used by the patches + for (i = 0; i < PatchShaders.GetSize (); i++) + delete static_cast < patchMesh_t * >(PatchShaders.GetAt (i)); + PatchShaders.RemoveAll (); + + for (b = active_brushes->next; b != NULL && b != active_brushes; b = b->next) + { + if (b->patchBrush) + PushPatch (b->pPatch); + } + for (b = selected_brushes->next; b != NULL && b != selected_brushes; b = b->next) + { + if (b->patchBrush) + PushPatch (b->pPatch); + } + for (b = filtered_brushes->next; b != NULL && b != filtered_brushes; b = b->next) + { + if (b->patchBrush) + PushPatch (b->pPatch); + } + + // reload shaders + // empty the actives shaders list + g_ActiveShaders.ReleaseAll (); + g_Shaders.ReleaseAll (); + // empty the main g_qeglobals.d_qtextures list + // FIXME: when we reload later on, we need to have the shader names + // for brushes it's stored in the texdef + // but patches don't have texdef + // see bug 104655 for details + // so the solution, build an array of patchMesh_t* and their shader names +#ifdef _DEBUG + Sys_Printf ("FIXME: patch shader reload workaround (old fenris? bug 104655)\n"); +#endif + + //GtkWidget *widget = g_QglTable.m_pfn_GetQeglobalsGLWidget (); + GHashTable *texmap = g_ShadersTable.m_pfnQTexmap (); + + // NOTE: maybe before we'd like to set all qtexture_t in the shaders list to notex? + // NOTE: maybe there are some qtexture_t we don't want to erase? For plain color faces maybe? + while (*d_qtextures) + { + qtexture_t *pTex = *d_qtextures; + qtexture_t *pNextTex = pTex->next; + + //if (widget != NULL) + g_QglTable.m_pfn_qglDeleteTextures (1, &pTex->texture_number); + + g_hash_table_remove (texmap, pTex->name); + + // all qtexture_t should be manipulated with the glib alloc handlers for now + g_free (pTex); + *d_qtextures = pNextTex; + } + + g_QglTable.m_pfn_QE_CheckOpenGLForErrors (); +} + +// those functions are only used during a shader reload phase +// the patch one relies on ShaderNameLookup, a table that is being built only when a flush is performed +// so it's not something we want to expose publicly + +void SetShader (patchMesh_t * patch) +{ + // unhook current shader + patch->pShader->DecRef(); + // don't access this one! it has been deleted .. it's DEAD + patch->d_texture = NULL; + // hook the new one, increment the refcount + // NOTE TTimo this function increments the refcount, don't incref ourselves + patch->pShader = QERApp_Shader_ForName (ShaderNameLookup (patch)); + patch->d_texture = patch->pShader->getTexture (); +} + +void SetShader (face_t * f) +{ + // unhook current shader + f->pShader->DecRef(); + // don't access the texdef! it's DEAD + f->d_texture = NULL; + // hook + // NOTE TTimo this function increments the refcount, don't incref ourselves + f->pShader = QERApp_Shader_ForName (f->texdef.GetName()); + f->d_texture = f->pShader->getTexture (); +} + +void Brush_RefreshShader(brush_t *b) +{ + if (b->patchBrush) + SetShader(b->pPatch); + else if (b->owner->eclass->fixedsize) + { + /*eclass_t *eclass = HasModel(b); + if (eclass) + { + for(entitymodel *model = eclass->model; model!=NULL; model=model->pNext) + if(model && model->strSkin) + model->nTextureBind = g_FuncTable.m_pfnTexture_LoadSkin(((GString *)model->strSkin)->str, &model->nSkinWidth, &model->nSkinHeight); + }*/ + } + else + for (face_t *f=b->brush_faces ; f ; f=f->next) + SetShader(f); +} + +void WINAPI QERApp_ReloadShaders () +{ + brush_t *b; + brush_t *active_brushes; + brush_t *selected_brushes; + brush_t *filtered_brushes; + + QERApp_FreeShaders (); + + g_DataTable.m_pfnLstSkinCache()->RemoveAll(); //md3 skins + + active_brushes = g_DataTable.m_pfnActiveBrushes (); + selected_brushes = g_DataTable.m_pfnSelectedBrushes (); + filtered_brushes = g_DataTable.m_pfnFilteredBrushes (); + + // now we must reload the shader information from shaderfiles + g_ShadersTable.m_pfnBuildShaderList(); + g_ShadersTable.m_pfnPreloadShaders(); + + // refresh the map visuals: replace our old shader objects by the new ones + // on brush faces we have the shader name in texdef.name + // on patches we have the shader name in PatchShaders + // while we walk through the map data, we DecRef the old shaders and push the new ones in + // if all goes well, most of our old shaders will get deleted on the way + + // FIXME: bug 104655, when we come accross a patch, we use the above array since the d_texture is lost + // NOTE: both face_t and patchMesh_t store pointers to the shader and qtexture_t + // in an ideal world they would only store shader and access the qtexture_t through it + // reassign all current shaders + for (b = active_brushes->next; b != NULL && b != active_brushes; b = b->next) + Brush_RefreshShader(b); + for (b = selected_brushes->next; b != NULL && b != selected_brushes; b = b->next) + Brush_RefreshShader(b); + // do that to the filtered brushes as well (we might have some region compiling going on) + for (b = filtered_brushes->next; b != NULL && b != filtered_brushes; b = b->next) + Brush_RefreshShader(b); +} + +int WINAPI QERApp_LoadShadersFromDir (const char *path) +{ + int count = 0; + // scan g_Shaders, and call QERApp_Shader_ForName for each in the given path + // this will load the texture if needed and will set it in use.. + int nSize = g_Shaders.GetSize (); + for (int i = 0; i < nSize; i++) + { + CShader *pShader = reinterpret_cast < CShader * >(g_Shaders[i]); + if (strstr (pShader->getShaderFileName (), path) || strstr (pShader->getName (), path)) + { + count++; + // request the shader, this will load the texture if needed and set "inuse" + //++timo FIXME: should we put an Activate member on CShader? + // this QERApp_Shader_ForName call is a kind of hack + IShader *pFoo = QERApp_Shader_ForName (pShader->getName ()); +#ifdef _DEBUG + // check we activated the right shader + // NOTE: if there was something else loaded, the size of g_Shaders may have changed and strange behaviours are to be expected + if (pFoo != pShader) + Sys_Printf ("WARNING: unexpected pFoo != pShader in QERApp_LoadShadersFromDir\n"); +#else + pFoo = NULL; // leo: shut up the compiler +#endif + } + } + return count; +} + +bool CShader::Parse () +{ + char *token = g_ScripLibTable.m_pfnToken (); + + // the parsing needs to be taken out in another module +// Sys_Printf("TODO: CShader::Parse\n"); + + // token is shader name (full path with a "textures\") + // we remove the "textures\" part + //setName ((char *) &token[9])); + // no we don't + setName (token); + // name of the qtexture_t we'll use to represent this shader (this one has the "textures\" before) + const char *stdName = QERApp_CleanTextureName (token); + m_strTextureName = stdName; // FIXME: BC reports stdName is uninitialised? + g_ScripLibTable.m_pfnGetToken (true); + if (strcmp (token, "{")) + return false; + else + { + // we need to read until we hit a balanced } + int nMatch = 1; + while (nMatch > 0 && g_ScripLibTable.m_pfnGetToken (true)) + { + if (strcmp (token, "{") == 0) + { + nMatch++; + continue; + } + else if (strcmp (token, "}") == 0) + { + nMatch--; + continue; + } + if (nMatch > 1) continue; // ignore layers for now + if (strcmpi (token, "qer_nocarve") == 0) + { + m_nFlags |= QER_NOCARVE; + } + else if (strcmpi (token, "qer_trans") == 0) + { + if (g_ScripLibTable.m_pfnGetToken (true)) + { + m_fTrans = (float) atof (token); + } + m_nFlags |= QER_TRANS; + } + else if (strcmpi (token, "qer_editorimage") == 0) + { + if (g_ScripLibTable.m_pfnGetToken (true)) + { + // bAddTexture changed to false to allow editorimages in other locations than "textures/" + m_strTextureName = QERApp_CleanTextureName (token, false); + } + } + else if (strcmpi (token, "qer_alphafunc") == 0) + { + if (g_ScripLibTable.m_pfnGetToken (true)) + { + + if(stricmp( token, "greater" ) == 0 ) + { + m_nAlphaFunc = GL_GREATER; + } + else if(stricmp( token, "less" ) == 0 ) + { + m_nAlphaFunc = GL_LESS; + } + else if(stricmp( token, "gequal" ) == 0 ) + { + m_nAlphaFunc = GL_GEQUAL; + } + + if( m_nAlphaFunc ) + m_nFlags |= QER_ALPHAFUNC; + } + if (g_ScripLibTable.m_pfnGetToken (true)) + { + m_fAlphaRef = (float) atof (token); + } + } + else if (strcmpi (token, "cull") == 0) + { + if (g_ScripLibTable.m_pfnGetToken (true)) + { + if( stricmp( token, "none" ) == 0 || stricmp( token, "twosided" ) == 0 || stricmp( token, "disable" ) == 0 ) + { + m_nCull = 2; + } + else if( stricmp( token, "back" ) == 0 || stricmp( token, "backside" ) == 0 || stricmp( token, "backsided" ) == 0 ) + { + m_nCull = 1; + } + + if( m_nCull ) + m_nFlags |= QER_CULL; + } + } + else if (strcmpi (token, "surfaceparm") == 0) + { + if (g_ScripLibTable.m_pfnGetToken (true)) + { + if (strcmpi (token, "fog") == 0) + { + m_nFlags |= QER_FOG; + if (m_fTrans == 1.0f) // has not been explicitly set by qer_trans + { + m_fTrans = 0.35f; + } + } + else if (strcmpi (token, "nodraw") == 0) + { + m_nFlags |= QER_NODRAW; + } + else if (strcmpi (token, "nonsolid") == 0) + { + m_nFlags |= QER_NONSOLID; + } + else if (strcmpi (token, "water") == 0) + { + m_nFlags |= QER_WATER; + } + else if (strcmpi (token, "lava") == 0) + { + m_nFlags |= QER_LAVA; + } + } + } + } + if (nMatch != 0) + return false; + } + return true; +} + +void CShader::RegisterActivate () +{ + // fill the qtexture_t with shader information + //++timo FIXME: a lot of that won't be necessary, will be stored at IShader* level +// strcpy (m_pTexture->shadername, m_Name); + // this flag is set only if we have a shaderfile name +// if (m_ShaderFileName[0] != '\0') +// m_pTexture->bFromShader = true; +// else +// m_pTexture->bFromShader = false; + //++timo FIXME: what do we do with that? + //m_pTexture->fTrans = pInfo->m_fTransValue; +// m_pTexture->fTrans = 1.0f; // if != 1.0 it's ot getting drawn in Cam_Draw +// m_pTexture->nShaderFlags = m_nFlags; + // store in the active shaders list (if necessary) + g_ActiveShaders.AddSingle (this); + // when you activate a shader, it gets displayed in the texture browser + m_bDisplayed = true; + IncRef (); +} + +void CShader::Try_Activate () +{ + m_pTexture = QERApp_Try_Texture_ForName (m_strTextureName.GetBuffer()); + if (m_pTexture) + RegisterActivate (); +} + +// Hydra: now returns false if the ORIGINAL shader could not be activated +// (missing texture, or incorrect shader script), true otherwise +// the shader is still activated in all cases. +bool CShader::Activate () +{ + Try_Activate (); + if (!m_pTexture) + { + m_pTexture = QERApp_Texture_ForName2 (SHADER_NOTEX); + RegisterActivate (); + return false; + } + return true; +} + +void WINAPI QERApp_LoadShaderFile (const char *filename) +{ + char *pBuff; + int nSize = vfsLoadFile (filename, reinterpret_cast < void **>(&pBuff), 0); + if (nSize > 0) + { + Sys_Printf ("Parsing shaderfile %s\n", filename); + g_ScripLibTable.m_pfnStartTokenParsing (pBuff); + while (g_ScripLibTable.m_pfnGetToken (true)) + { + // first token should be the path + name.. (from base) + CShader *pShader = new CShader (); + // we want the relative filename only, it's easier for later lookup .. see QERApp_ReloadShaderFile + char cTmp[1024]; + g_FuncTable.m_pfnQE_ConvertDOSToUnixName (cTmp, filename); + // given the vfs, we should not store the full path + //pShader->setShaderFileName( filename + strlen(ValueForKey(g_qeglobals.d_project_entity, "basepath"))); + pShader->setShaderFileName (filename); + if (pShader->Parse ()) + { + // do we already have this shader? + //++timo NOTE: this may a bit slow, we may need to use a map instead of a dumb list + if (g_Shaders.Shader_ForName (pShader->getName ()) != NULL) + { +#ifdef _DEBUG + Sys_Printf ("WARNING: shader %s is already in memory, definition in %s ignored.\n", + pShader->getName (), filename); +#endif + delete pShader; + } + else + { + pShader->IncRef (); + + g_Shaders.Add ((void *) pShader); + } + } + else + { + Sys_Printf ("Error parsing shader %s\n", pShader->getName ()); + delete pShader; + } + } + vfsFreeFile (pBuff); + } + else + { + Sys_Printf ("Unable to read shaderfile %s\n", filename); + } +} + +IShader *WINAPI QERApp_Try_Shader_ForName (const char *name) +{ + // look for the shader + CShader *pShader = g_Shaders.Shader_ForName (name); + if (!pShader) + // not found + return NULL; + // we may need to load the texture or use the "shader without texture" one + pShader->Activate (); + pShader->SetDisplayed (true); + return pShader; +} + +IShader *WINAPI QERApp_CreateShader_ForTextureName (const char *name) +{ + CShader *pShader; + pShader = new CShader; + // CreateDefault expects a texture / shader name relative to the "textures" directory + // (cause shader names are reletive to "textures/") + pShader->CreateDefault (name); + // hook it into the shader list + g_Shaders.Add ((void *) pShader); + pShader->IncRef (); + // if it can't find the texture, SHADER_NOT_FOUND will be used + // Hydra: display an error message, so the user can quickly find a list of missing + // textures by looking at the console. + if (!pShader->Activate ()) + { + Sys_Printf ("WARNING: Activate shader failed for %s\n",pShader->getName()); + } + pShader->SetDisplayed (true); + + return pShader; +} + +IShader *WINAPI QERApp_Shader_ForName (const char *name) +{ + if (name == NULL || strlen (name) == 0) + { + // Hydra: This error can occur if the user loaded a map with/dropped an entity that + // did not set a texture name "(r g b)" - check the entity definition loader + + g_FuncTable.m_pfnSysFPrintf (SYS_ERR, "FIXME: name == NULL || strlen(name) == 0 in QERApp_Shader_ForName\n"); + return QERApp_Shader_ForName (SHADER_NOT_FOUND); + } + // entities that should be represented with plain colors instead of textures + // request a texture name with (r g b) (it's stored in their class_t) + if (name[0] == '(') + { + return QERApp_ColorShader_ForName (name); + } + + CShader *pShader = static_cast < CShader * >(QERApp_Try_Shader_ForName (name)); + if (pShader) + { + pShader->SetDisplayed (true); + return pShader; + } + return QERApp_CreateShader_ForTextureName (name); +} + +qtexture_t *WINAPI QERApp_Try_Texture_ForName (const char *name) +{ + qtexture_t *q; +// char f1[1024], f2[1024]; + unsigned char *pPixels = NULL; + int nWidth, nHeight; + + // convert the texture name to the standard format we use in qtexture_t + const char *stdName = QERApp_CleanTextureName (name); + + // use the hash table + q = (qtexture_t*)g_hash_table_lookup (g_ShadersTable.m_pfnQTexmap (), stdName); + if (q) + return q; + +#ifdef QTEXMAP_DEBUG + for (q = g_qeglobals.d_qtextures; q; q = q->next) + { + if (!strcmp (stdName, q->name)) + { + Sys_Printf ("ERROR: %s is not in texture map, but was found in texture list\n"); + return q; + } + } +#endif + + g_FuncTable.m_pfnLoadImage (name, &pPixels, &nWidth, &nHeight); + + if (!pPixels) + return NULL; // we failed + else + Sys_Printf ("LOADED: %s\n", name); + + // instanciate a new qtexture_t + // NOTE: when called by a plugin we must make sure we have set Radiant's GL context before binding the texture + + // we'll be binding the GL texture now + // need to check we are using a right GL context + // with GL plugins that have their own window, the GL context may be the plugin's, in which case loading textures will bug + // g_QglTable.m_pfn_glwidget_make_current (g_QglTable.m_pfn_GetQeglobalsGLWidget ()); + q = g_FuncTable.m_pfnLoadTextureRGBA (pPixels, nWidth, nHeight); + if (!q) + return NULL; + g_free (pPixels); + + strcpy (q->name, name); + // only strip extension if extension there is! + if (q->name[strlen (q->name) - 4] == '.') + q->name[strlen (q->name) - 4] = '\0'; + // hook into the main qtexture_t list + qtexture_t **d_qtextures = g_ShadersTable.m_pfnQTextures (); + q->next = *d_qtextures; + *d_qtextures = q; + // push it in the map + g_hash_table_insert (g_ShadersTable.m_pfnQTexmap (), q->name, q); + return q; +} + +int WINAPI QERApp_HasShader (const char *pName) +{ + // mickey check the global shader array for existense of pName + CShader *pShader = g_Shaders.Shader_ForName (pName); + if (pShader) + return 1; + return 0; +} + +IShader *WINAPI QERApp_Shader_ForName_NoLoad (const char *pName) +{ + CShader *pShader = g_Shaders.Shader_ForName (pName); + return pShader; +} + +/*! +This should NEVER return NULL, it is the last-chance call in the load cascade +*/ +qtexture_t *WINAPI QERApp_Texture_ForName2 (const char *filename) +{ + qtexture_t *q; + q = QERApp_Try_Texture_ForName (filename); + if (q) + return q; + // not found? use "texture not found" + q = QERApp_Try_Texture_ForName (SHADER_NOT_FOUND); + if (q) + return q; + + // still not found? this is a fatal error + g_FuncTable.m_pfnError("Failed to load " SHADER_NOT_FOUND ". Looks like your installation is broken / missing some essential elements."); + return NULL; +} + +void CShader::CreateColor (const char *name) +{ + // parse + sscanf (name, "(%g %g %g)", m_vColor, m_vColor + 1, m_vColor + 2); + m_strTextureName = name; + setName ("color"); + // create the qtexture_t + qtexture_t *q1 = QERApp_Texture_ForName2 (SHADER_NOT_FOUND); + // copy this one + qtexture_t *q2 = new qtexture_t; + memcpy (q2, q1, sizeof (qtexture_t)); + strcpy (q2->name, m_strTextureName.GetBuffer ()); + VectorCopy (m_vColor, q2->color); + m_pTexture = q2; +} + +IShader *WINAPI QERApp_ColorShader_ForName (const char *name) +{ + CShader *pShader = new CShader (); + pShader->CreateColor (name); + // hook it into the shader list + pShader->IncRef (); + g_Shaders.Add ((void *) pShader); + return pShader; +} + +void CShaderArray::ReleaseForShaderFile (const char *name) +{ + int i; + // decref + for (i = 0; i < CPtrArray::GetSize (); i++) + { + IShader *pShader = static_cast < IShader * >(CPtrArray::GetAt (i)); + if (!strcmp (name, pShader->getShaderFileName ())) + { + pShader->DecRef (); + CPtrArray::RemoveAt (i); + i--; // get ready for next loop + } + } +} + +void WINAPI QERApp_ReloadShaderFile (const char *name) +{ + brush_t *b; + face_t *f; + brush_t *active_brushes; + brush_t *selected_brushes; + brush_t *filtered_brushes; + +// Sys_Printf("TODO: QERApp_ReloadShaderFile\n"); + + active_brushes = g_DataTable.m_pfnActiveBrushes (); + selected_brushes = g_DataTable.m_pfnSelectedBrushes (); + filtered_brushes = g_DataTable.m_pfnFilteredBrushes (); + +#ifdef _DEBUG + // check the shader name is a reletive path + // I hacked together a few quick tests to make sure :-) + if (strstr (name, ":\\") || !strstr (name, "scripts")) + Sys_Printf ("WARNING: is %s a reletive path to a shader file? (QERApp_ReloadShaderFile\n"); +#endif + + // in the actives and global shaders lists, decref and unhook the shaders + //++timo NOTE: maybe we'd like to keep track of the shaders we are unhooking? + g_ActiveShaders.ReleaseForShaderFile (name); + g_Shaders.ReleaseForShaderFile (name); + // go through a reload of the shader file + QERApp_LoadShaderFile (name); + // scan all the brushes, replace all the old ones by refs to their new equivalents + for (b = active_brushes->next; b != NULL && b != active_brushes; b = b->next) + { + if (b->patchBrush && !strcmp (b->pPatch->pShader->getShaderFileName (), name)) + SetShader (b->pPatch); + else + for (f = b->brush_faces; f; f = f->next) + if (!strcmp (f->pShader->getShaderFileName (), name)) + SetShader (f); + } + for (b = selected_brushes->next; b != NULL && b != selected_brushes; b = b->next) + { + if (b->patchBrush && !strcmp (b->pPatch->pShader->getShaderFileName (), name)) + SetShader (b->pPatch); + else + for (f = b->brush_faces; f; f = f->next) + if (!strcmp (f->pShader->getShaderFileName (), name)) + SetShader (f); + } + // do that to the filtered brushes as well (we might have some region compiling going on) + for (b = filtered_brushes->next; b != NULL && b != filtered_brushes; b = b->next) + { + if (b->patchBrush && !strcmp (b->pPatch->pShader->getShaderFileName (), name)) + SetShader (b->pPatch); + else + for (f = b->brush_faces; f; f = f->next) + if (!strcmp (f->pShader->getShaderFileName (), name)) + SetShader (f); + } + // call Texture_ShowInUse to clean and display only what's required + g_ShadersTable.m_pfnTexture_ShowInuse (); + QERApp_SortActiveShaders (); + g_FuncTable.m_pfnSysUpdateWindows (W_TEXTURE); +} + +void CShaderArray::SetDisplayed (bool b) +{ + int i, count; + count = CPtrArray::GetSize (); + for (i = 0; i < count; i++) + static_cast < IShader * >(CPtrArray::GetAt (i))->SetDisplayed (b); +} + +void CShaderArray::SetInUse (bool b) +{ + int i, count; + count = CPtrArray::GetSize (); + for (i = 0; i < count; i++) + static_cast < IShader * >(CPtrArray::GetAt (i))->SetInUse (b); +} + +// Set the IsDisplayed flag on all active shaders +void WINAPI QERApp_ActiveShaders_SetDisplayed (bool b) +{ + g_ActiveShaders.SetDisplayed (b); +} + +void WINAPI QERApp_ActiveShaders_SetInUse (bool b) +{ + g_ActiveShaders.SetInUse (b); +} + +// ============================================================================= +// SYNAPSE + +bool CSynapseClientShaders::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, SHADERS_MAJOR)) + { + _QERShadersTable* pTable= static_cast<_QERShadersTable*>(pAPI->mpTable); + + pTable->m_pfnFreeShaders = QERApp_FreeShaders; + pTable->m_pfnReloadShaders = QERApp_ReloadShaders; + pTable->m_pfnLoadShadersFromDir = QERApp_LoadShadersFromDir; + pTable->m_pfnReloadShaderFile = QERApp_ReloadShaderFile; + pTable->m_pfnLoadShaderFile = QERApp_LoadShaderFile; + pTable->m_pfnHasShader = QERApp_HasShader; + pTable->m_pfnTry_Shader_ForName = QERApp_Try_Shader_ForName; + pTable->m_pfnShader_ForName = QERApp_Shader_ForName; + pTable->m_pfnTry_Texture_ForName = QERApp_Try_Texture_ForName; + pTable->m_pfnTexture_ForName = QERApp_Texture_ForName2; + pTable->m_pfnGetActiveShaderCount = QERApp_GetActiveShaderCount; + pTable->m_pfnColorShader_ForName = QERApp_ColorShader_ForName; + pTable->m_pfnShader_ForName_NoLoad = QERApp_Shader_ForName_NoLoad; + pTable->m_pfnActiveShaders_SetInUse = QERApp_ActiveShaders_SetInUse; + pTable->m_pfnSortActiveShaders = QERApp_SortActiveShaders; + pTable->m_pfnActiveShader_ForTextureName = QERApp_ActiveShader_ForTextureName; + pTable->m_pfnCreateShader_ForTextureName = QERApp_CreateShader_ForTextureName; + pTable->m_pfnActiveShaders_SetDisplayed = QERApp_ActiveShaders_SetDisplayed; + pTable->m_pfnActiveShader_ForIndex = QERApp_ActiveShader_ForIndex; + pTable->m_pfnCleanTextureName = QERApp_CleanTextureName; + + return true; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} diff --git a/plugins/spritemodel/plugin.cpp b/plugins/spritemodel/plugin.cpp index a4d94390..4e51e551 100644 --- a/plugins/spritemodel/plugin.cpp +++ b/plugins/spritemodel/plugin.cpp @@ -1,279 +1,279 @@ -/* -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 -*/ - -// -// Sprite Model Plugin -// -// Code by Hydra aka Dominic Clifton -// -// Based on MD3Model source code by SPoG -// - -/* - Overview - ======== - - - Why ? - ----- - - It allows the user to see a graphical representation of the entity in the 3D view (maybe 2D views later) where the entity would just otherwise be a non-descriptive coloured box. - - It is designed to be used with the entity view set to WireFrame (as the sprite images are rendered in the middle of the entity's bbox). - - How ? - ----- - - Implemented as a model module, without any ISelect stuff. - - For an entity to use an image (instead of a model) you just update the entity defintion file so that the eclass_t's modelpath is filled in with a relative path and filename of an image file. - - e.g: - - baseq3/scripts/entities.def - =========================== - - \/\*QUAKED ammo_bfg (.3 .3 1) (-16 -16 -16) (16 16 16) SUSPENDED - ... - -------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- - model="sprites/powerups/ammo/bfgam.bmp"\*\/ - - - valve/scripts/halflife.fgd - ========================== - - @PointClass iconsprite("sprites/lightbulb.spr") base(Target, Targetname, Light) = light : "Invisible lightsource" - [ - ... - ] - - What image formats are supported ? - ---------------------------------- - - This module can load any image format that there is an active image module for. For q3 this would be bmp, tga and jpg. For Half-Life this would be hlw and spr. - - Version History - =============== - - v0.1 - 27/May/2002 - - Created an inital implementation of a sprite model plugin. - According to the powers that be, it seems creating a model - plugin is hackish. - It works ok, but there is no way to attach models (sprites if you will) - to non-fixedsize entities (like func_bombtarget) - Also, I can't get the alpha map stuff right so I had to invert the alpha - mask in the spr loader so that 0xff = not drawn pixel. - - v0.2 - 10/March/2003 - - Updated to coincide with Radiant 1.3.5 test builds. Also, I made sure it worked - under quake3 and it does. - - v0.3 - 10/March/2003 - - Added about box. - - ToDo - ==== - - * make sprites always face the camera (is this done in camwindow.cpp ?) - but only if the entity model doesn't have "angle" keys. At the moment - it's better to rotate the model with the angles. - - * maybe add an option to scale the sprites in the prefs ? - - * maybe convert to a new kind of class not based on model. - - * allow sprites on non-fixedsize ents - - * fix reversed alpha map in spr loader - -> is this actually broken? - - * allow an entity to have multiple models (e.g .md3 and a sprite model) - and allow the user to toggle either models on or off. - - * dynamically add the api's depending on what image loading modules are - supported by radiant. - Currently, we hard code to the list in "supportedmodelformats" (see below) - but, all these extensions are stripped when the actual image is loaded. - current the bit of code that decided what model api to use needs reworking - as it decides by looking at the extension of the model name, when in fact - we don't even need an extension. - - Previously the code fell though to use this model as the default model - plugin, but that also has issues. - - what it means is, in the .def files you must specify an image filename - that has one of the extensions listed below, but in actual fact radiant - will use any available image module to load the image. - - - e.g. you could use a model name of "sprites/target_speaker.tga" and have - a file called sprites/target_speaker.png and it would be correctly loaded - even if it not listed below in "supportedmodelformats". - - So, currently in the .def files you can just use the name - "sprites/target_speaker.spr" and it will load the file - from "sprites/target_speaker.*" which is what I propose anyone creating image sets for Q3/Wolf/etc does. -*/ - -#include "plugin.h" - -// ============================================================================= -// Globals - -// function tables -_QERFuncTable_1 g_FuncTable; -_QERQglTable g_QglTable; -_QERShadersTable g_ShadersTable; - -// ============================================================================= -// plugin implementation - -static const char *PLUGIN_NAME = "Sprite Model loading module"; - -static const char *PLUGIN_COMMANDS = "About..."; - -static const char *PLUGIN_ABOUT = "Sprite Model loading module v0.2 for GTKRadiant\n\n" - "By Hydra!"; - -char *supportedmodelformats[] = {"spr","bmp","tga","jpg","hlw",NULL}; // NULL is list delimiter - -static void add_model_apis(CSynapseClient& client) -{ - char **ext; - for (ext = supportedmodelformats; *ext != NULL; ext++) - { - client.AddAPI(MODEL_MAJOR, *ext, sizeof(_QERPlugModelTable)); - } -} - -static bool model_is_supported(const char* extension) -{ - char **ext; - for (ext = supportedmodelformats; *ext != NULL; ext++) - { - if (stricmp(extension,*ext)==0) - return true; - } - return false; -} - -void init_filetypes() -{ - char **ext; - for (ext = supportedmodelformats; *ext != NULL; ext++) - { - GetFileTypeRegistry()->addType(MODEL_MAJOR, filetype_t("sprite", *ext)); - } -} - -extern "C" const char* QERPlug_Init (void *hApp, void* pMainWidget) -{ - init_filetypes(); // see todo list above. - 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) -{ - // NOTE: this never happens in a module - if(!strcmp(p, "About...")) - g_FuncTable.m_pfnMessageBox(NULL, PLUGIN_ABOUT, "About", MB_OK, NULL); -} - -// ============================================================================= -// SYNAPSE - -CSynapseServer* g_pSynapseServer = NULL; -CSynapseClientModel 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()); - - add_model_apis(g_SynapseClient); // see todo list above. - - g_SynapseClient.AddAPI( PLUGIN_MAJOR, "sprite", 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 ); - g_SynapseClient.AddAPI( SHADERS_MAJOR, "*", sizeof( g_ShadersTable ), SYN_REQUIRE, &g_ShadersTable ); - - return &g_SynapseClient; -} - -bool CSynapseClientModel::RequestAPI(APIDescriptor_t *pAPI) -{ - if (!strcmp(pAPI->major_name, MODEL_MAJOR)) - { - _QERPlugModelTable* pTable= static_cast<_QERPlugModelTable*>(pAPI->mpTable); - - if (model_is_supported(pAPI->minor_name)) // see todo list above. - { - pTable->m_pfnLoadModel = &LoadSpriteModel; - return true; - } - } - else 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; - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -#include "version.h" - -const char* CSynapseClientModel::GetInfo() -{ - return "Sprite Model module built " __DATE__ " " RADIANT_VERSION; -} - -const char* CSynapseClientModel::GetName() -{ - return "sprite"; -} +/* +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 +*/ + +// +// Sprite Model Plugin +// +// Code by Hydra aka Dominic Clifton +// +// Based on MD3Model source code by SPoG +// + +/* + Overview + ======== + + + Why ? + ----- + + It allows the user to see a graphical representation of the entity in the 3D view (maybe 2D views later) where the entity would just otherwise be a non-descriptive coloured box. + + It is designed to be used with the entity view set to WireFrame (as the sprite images are rendered in the middle of the entity's bbox). + + How ? + ----- + + Implemented as a model module, without any ISelect stuff. + + For an entity to use an image (instead of a model) you just update the entity defintion file so that the eclass_t's modelpath is filled in with a relative path and filename of an image file. + + e.g: + + baseq3/scripts/entities.def + =========================== + + \/\*QUAKED ammo_bfg (.3 .3 1) (-16 -16 -16) (16 16 16) SUSPENDED + ... + -------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- + model="sprites/powerups/ammo/bfgam.bmp"\*\/ + + + valve/scripts/halflife.fgd + ========================== + + @PointClass iconsprite("sprites/lightbulb.spr") base(Target, Targetname, Light) = light : "Invisible lightsource" + [ + ... + ] + + What image formats are supported ? + ---------------------------------- + + This module can load any image format that there is an active image module for. For q3 this would be bmp, tga and jpg. For Half-Life this would be hlw and spr. + + Version History + =============== + + v0.1 - 27/May/2002 + - Created an inital implementation of a sprite model plugin. + According to the powers that be, it seems creating a model + plugin is hackish. + It works ok, but there is no way to attach models (sprites if you will) + to non-fixedsize entities (like func_bombtarget) + Also, I can't get the alpha map stuff right so I had to invert the alpha + mask in the spr loader so that 0xff = not drawn pixel. + + v0.2 - 10/March/2003 + - Updated to coincide with Radiant 1.3.5 test builds. Also, I made sure it worked + under quake3 and it does. + + v0.3 - 10/March/2003 + - Added about box. + + ToDo + ==== + + * make sprites always face the camera (is this done in camwindow.cpp ?) + but only if the entity model doesn't have "angle" keys. At the moment + it's better to rotate the model with the angles. + + * maybe add an option to scale the sprites in the prefs ? + + * maybe convert to a new kind of class not based on model. + + * allow sprites on non-fixedsize ents + + * fix reversed alpha map in spr loader + -> is this actually broken? + + * allow an entity to have multiple models (e.g .md3 and a sprite model) + and allow the user to toggle either models on or off. + + * dynamically add the api's depending on what image loading modules are + supported by radiant. + Currently, we hard code to the list in "supportedmodelformats" (see below) + but, all these extensions are stripped when the actual image is loaded. + current the bit of code that decided what model api to use needs reworking + as it decides by looking at the extension of the model name, when in fact + we don't even need an extension. + + Previously the code fell though to use this model as the default model + plugin, but that also has issues. + + what it means is, in the .def files you must specify an image filename + that has one of the extensions listed below, but in actual fact radiant + will use any available image module to load the image. + + + e.g. you could use a model name of "sprites/target_speaker.tga" and have + a file called sprites/target_speaker.png and it would be correctly loaded + even if it not listed below in "supportedmodelformats". + + So, currently in the .def files you can just use the name + "sprites/target_speaker.spr" and it will load the file + from "sprites/target_speaker.*" which is what I propose anyone creating image sets for Q3/Wolf/etc does. +*/ + +#include "plugin.h" + +// ============================================================================= +// Globals + +// function tables +_QERFuncTable_1 g_FuncTable; +_QERQglTable g_QglTable; +_QERShadersTable g_ShadersTable; + +// ============================================================================= +// plugin implementation + +static const char *PLUGIN_NAME = "Sprite Model loading module"; + +static const char *PLUGIN_COMMANDS = "About..."; + +static const char *PLUGIN_ABOUT = "Sprite Model loading module v0.2 for GTKRadiant\n\n" + "By Hydra!"; + +char *supportedmodelformats[] = {"spr","bmp","tga","jpg","hlw",NULL}; // NULL is list delimiter + +static void add_model_apis(CSynapseClient& client) +{ + char **ext; + for (ext = supportedmodelformats; *ext != NULL; ext++) + { + client.AddAPI(MODEL_MAJOR, *ext, sizeof(_QERPlugModelTable)); + } +} + +static bool model_is_supported(const char* extension) +{ + char **ext; + for (ext = supportedmodelformats; *ext != NULL; ext++) + { + if (stricmp(extension,*ext)==0) + return true; + } + return false; +} + +void init_filetypes() +{ + char **ext; + for (ext = supportedmodelformats; *ext != NULL; ext++) + { + GetFileTypeRegistry()->addType(MODEL_MAJOR, filetype_t("sprite", *ext)); + } +} + +extern "C" const char* QERPlug_Init (void *hApp, void* pMainWidget) +{ + init_filetypes(); // see todo list above. + 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) +{ + // NOTE: this never happens in a module + if(!strcmp(p, "About...")) + g_FuncTable.m_pfnMessageBox(NULL, PLUGIN_ABOUT, "About", MB_OK, NULL); +} + +// ============================================================================= +// SYNAPSE + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientModel 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()); + + add_model_apis(g_SynapseClient); // see todo list above. + + g_SynapseClient.AddAPI( PLUGIN_MAJOR, "sprite", 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 ); + g_SynapseClient.AddAPI( SHADERS_MAJOR, "*", sizeof( g_ShadersTable ), SYN_REQUIRE, &g_ShadersTable ); + + return &g_SynapseClient; +} + +bool CSynapseClientModel::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, MODEL_MAJOR)) + { + _QERPlugModelTable* pTable= static_cast<_QERPlugModelTable*>(pAPI->mpTable); + + if (model_is_supported(pAPI->minor_name)) // see todo list above. + { + pTable->m_pfnLoadModel = &LoadSpriteModel; + return true; + } + } + else 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; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientModel::GetInfo() +{ + return "Sprite Model module built " __DATE__ " " RADIANT_VERSION; +} + +const char* CSynapseClientModel::GetName() +{ + return "sprite"; +} diff --git a/plugins/spritemodel/spritemodel.cpp b/plugins/spritemodel/spritemodel.cpp index 42487134..411f377d 100644 --- a/plugins/spritemodel/spritemodel.cpp +++ b/plugins/spritemodel/spritemodel.cpp @@ -1,178 +1,178 @@ -/* -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 -*/ - -// -// Sprite Model Plugin -// -// Code by Hydra aka Dominic Clifton -// -// Based on MD3Model source code by SPoG -// - -#include "spritemodel.h" - -void LoadSpriteModel(entity_interfaces_t *interfaces, const char *name) -{ - IShader *pShader; - - pShader = QERApp_Shader_ForName(name); - - if (!pShader) - { - Sys_Printf("ERROR: can't find shader (or image) for: %s\n", name ); - return; - } - - CSpriteModel *model = new CSpriteModel(); - model->Construct(pShader); - interfaces->pRender = (IRender*)model; - interfaces->pRender->IncRef(); - //interfaces->pSelect = (ISelect*)model; - //interfaces->pSelect->IncRef(); - interfaces->pSelect = NULL; - interfaces->pEdit = NULL; - model->DecRef(); - -} - -void CSpriteModel::Construct(IShader *pShader) -{ - m_pShader = pShader; - aabb_clear(&m_BBox); - /* - md3Surface_t *pSurface = (md3Surface_t *)(((unsigned char *)pHeader) + pHeader->ofsSurfaces); - m_nSurfaces = pHeader->numSurfaces; - CMD3Surface* surfaces = new CMD3Surface[m_nSurfaces]; - for (int i = 0; i < m_nSurfaces; i++ ) - { - surfaces[i].Construct(pSurface); - pSurface = (md3Surface_t *) ((( char * ) pSurface) + pSurface->ofsEnd); - } - m_children = surfaces; - AccumulateBBox(); - */ -} - -CSpriteModel::CSpriteModel() -{ - refCount = 1; - //m_nSurfaces = 0; - //m_children = NULL; - m_pShader = NULL; -} - -CSpriteModel::~CSpriteModel() -{ - // if(m_children) delete[] m_children; - if (m_pShader) - m_pShader->DecRef(); -} - -void CSpriteModel::Draw(int state, int rflags) const -{ - -/* - // Draw a point in the middle of the bbox - vec3_t middle = {0,0,0}; - g_QglTable.m_pfn_qglPointSize (4); - g_QglTable.m_pfn_qglColor3f (0,1,0); - g_QglTable.m_pfn_qglBegin (GL_POINTS); - g_QglTable.m_pfn_qglVertex3fv (middle); - g_QglTable.m_pfn_qglEnd (); -*/ - - qtexture_t *q = m_pShader->getTexture(); - - // convert pixels to units and divide in half again so we draw in the middle - // of the bbox. - int h = q->height / 8; - int w = q->width / 8; - - // setup opengl stuff - - g_QglTable.m_pfn_qglPushAttrib (GL_ALL_ATTRIB_BITS); // GL_ENABLE_BIT - //g_QglTable.m_pfn_qglColor3f (1,1,1); //testing - //g_QglTable.m_pfn_qglColor4f (1,1,1,1); //testing - g_QglTable.m_pfn_qglBindTexture (GL_TEXTURE_2D, q->texture_number); - - //g_QglTable.m_pfn_qglEnable (GL_TEXTURE_2D); // FIXME: ? this forces textures, even in wireframe mode, bad... ? - - g_QglTable.m_pfn_qglAlphaFunc (GL_LESS, 1); - g_QglTable.m_pfn_qglEnable (GL_ALPHA_TEST); - - // get rid of this when sprite always faces camera - g_QglTable.m_pfn_qglDisable(GL_CULL_FACE); - g_QglTable.m_pfn_qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); - - // draw the sprite - -#if 0 - // using x/y axis, it appears FLAT without the proper transform and rotation. - - g_QglTable.m_pfn_qglBegin(GL_QUADS); - g_QglTable.m_pfn_qglTexCoord2f (0,0); - g_QglTable.m_pfn_qglVertex3f (0-w,0-h, 0); - g_QglTable.m_pfn_qglTexCoord2f (1,0); - g_QglTable.m_pfn_qglVertex3f ( w,0-h, 0); - g_QglTable.m_pfn_qglTexCoord2f (1,1); - g_QglTable.m_pfn_qglVertex3f ( w, h, 0); - g_QglTable.m_pfn_qglTexCoord2f (0,1); - g_QglTable.m_pfn_qglVertex3f (0-w, h, 0); - g_QglTable.m_pfn_qglEnd (); -#else - - // so draw it using y/z instead. - g_QglTable.m_pfn_qglBegin(GL_QUADS); - g_QglTable.m_pfn_qglTexCoord2f (0,0); - g_QglTable.m_pfn_qglVertex3f (0,w,h); - g_QglTable.m_pfn_qglTexCoord2f (1,0); - g_QglTable.m_pfn_qglVertex3f (0,0-w,h); - g_QglTable.m_pfn_qglTexCoord2f (1,1); - g_QglTable.m_pfn_qglVertex3f (0,0-w,0-h); - g_QglTable.m_pfn_qglTexCoord2f (0,1); - g_QglTable.m_pfn_qglVertex3f (0,w,0-h); - g_QglTable.m_pfn_qglEnd (); -#endif - - g_QglTable.m_pfn_qglBindTexture (GL_TEXTURE_2D, 0); - g_QglTable.m_pfn_qglPopAttrib(); -} - -/* -bool CSpriteModel::TestRay(const ray_t *ray, vec_t *dist) const -{ - vec_t depth_start = *dist; - vec_t depth_local = *dist; - - if (aabb_test_ray(&m_BBox, ray) == 0) - return false; - - for(int i=0; iConstruct(pShader); + interfaces->pRender = (IRender*)model; + interfaces->pRender->IncRef(); + //interfaces->pSelect = (ISelect*)model; + //interfaces->pSelect->IncRef(); + interfaces->pSelect = NULL; + interfaces->pEdit = NULL; + model->DecRef(); + +} + +void CSpriteModel::Construct(IShader *pShader) +{ + m_pShader = pShader; + aabb_clear(&m_BBox); + /* + md3Surface_t *pSurface = (md3Surface_t *)(((unsigned char *)pHeader) + pHeader->ofsSurfaces); + m_nSurfaces = pHeader->numSurfaces; + CMD3Surface* surfaces = new CMD3Surface[m_nSurfaces]; + for (int i = 0; i < m_nSurfaces; i++ ) + { + surfaces[i].Construct(pSurface); + pSurface = (md3Surface_t *) ((( char * ) pSurface) + pSurface->ofsEnd); + } + m_children = surfaces; + AccumulateBBox(); + */ +} + +CSpriteModel::CSpriteModel() +{ + refCount = 1; + //m_nSurfaces = 0; + //m_children = NULL; + m_pShader = NULL; +} + +CSpriteModel::~CSpriteModel() +{ + // if(m_children) delete[] m_children; + if (m_pShader) + m_pShader->DecRef(); +} + +void CSpriteModel::Draw(int state, int rflags) const +{ + +/* + // Draw a point in the middle of the bbox + vec3_t middle = {0,0,0}; + g_QglTable.m_pfn_qglPointSize (4); + g_QglTable.m_pfn_qglColor3f (0,1,0); + g_QglTable.m_pfn_qglBegin (GL_POINTS); + g_QglTable.m_pfn_qglVertex3fv (middle); + g_QglTable.m_pfn_qglEnd (); +*/ + + qtexture_t *q = m_pShader->getTexture(); + + // convert pixels to units and divide in half again so we draw in the middle + // of the bbox. + int h = q->height / 8; + int w = q->width / 8; + + // setup opengl stuff + + g_QglTable.m_pfn_qglPushAttrib (GL_ALL_ATTRIB_BITS); // GL_ENABLE_BIT + //g_QglTable.m_pfn_qglColor3f (1,1,1); //testing + //g_QglTable.m_pfn_qglColor4f (1,1,1,1); //testing + g_QglTable.m_pfn_qglBindTexture (GL_TEXTURE_2D, q->texture_number); + + //g_QglTable.m_pfn_qglEnable (GL_TEXTURE_2D); // FIXME: ? this forces textures, even in wireframe mode, bad... ? + + g_QglTable.m_pfn_qglAlphaFunc (GL_LESS, 1); + g_QglTable.m_pfn_qglEnable (GL_ALPHA_TEST); + + // get rid of this when sprite always faces camera + g_QglTable.m_pfn_qglDisable(GL_CULL_FACE); + g_QglTable.m_pfn_qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + + // draw the sprite + +#if 0 + // using x/y axis, it appears FLAT without the proper transform and rotation. + + g_QglTable.m_pfn_qglBegin(GL_QUADS); + g_QglTable.m_pfn_qglTexCoord2f (0,0); + g_QglTable.m_pfn_qglVertex3f (0-w,0-h, 0); + g_QglTable.m_pfn_qglTexCoord2f (1,0); + g_QglTable.m_pfn_qglVertex3f ( w,0-h, 0); + g_QglTable.m_pfn_qglTexCoord2f (1,1); + g_QglTable.m_pfn_qglVertex3f ( w, h, 0); + g_QglTable.m_pfn_qglTexCoord2f (0,1); + g_QglTable.m_pfn_qglVertex3f (0-w, h, 0); + g_QglTable.m_pfn_qglEnd (); +#else + + // so draw it using y/z instead. + g_QglTable.m_pfn_qglBegin(GL_QUADS); + g_QglTable.m_pfn_qglTexCoord2f (0,0); + g_QglTable.m_pfn_qglVertex3f (0,w,h); + g_QglTable.m_pfn_qglTexCoord2f (1,0); + g_QglTable.m_pfn_qglVertex3f (0,0-w,h); + g_QglTable.m_pfn_qglTexCoord2f (1,1); + g_QglTable.m_pfn_qglVertex3f (0,0-w,0-h); + g_QglTable.m_pfn_qglTexCoord2f (0,1); + g_QglTable.m_pfn_qglVertex3f (0,w,0-h); + g_QglTable.m_pfn_qglEnd (); +#endif + + g_QglTable.m_pfn_qglBindTexture (GL_TEXTURE_2D, 0); + g_QglTable.m_pfn_qglPopAttrib(); +} + +/* +bool CSpriteModel::TestRay(const ray_t *ray, vec_t *dist) const +{ + vec_t depth_start = *dist; + vec_t depth_local = *dist; + + if (aabb_test_ray(&m_BBox, ray) == 0) + return false; + + for(int i=0; i -#include - -#include "surfdlg_plugin.h" - - - -#ifdef _DEBUG -//#define DBG_SI 1 -#endif - -#include "gtkr_vector.h" - -vector g_texdef_face_vector; - -inline texdef_to_face_t* get_texdef_face_list() -{ - return &(*g_texdef_face_vector.begin()); -} - -inline unsigned int texdef_face_list_empty() -{ - return g_texdef_face_vector.empty(); -} - -inline unsigned int texdef_face_list_size() -{ - return g_texdef_face_vector.size(); -} - -// For different faces having different values -bool is_HShift_conflicting; -bool is_VShift_conflicting; -bool is_HScale_conflicting; -bool is_VScale_conflicting; -bool is_Rotate_conflicting; -bool is_TextureName_conflicting; - -void ShowDlg(); -void HideDlg(); -void SetTexMods(); -void GetTexMods(bool b_SetUndoPoint = FALSE); -void BuildDialog(); -void FitAll(); -void InitDefaultIncrement(texdef_t *); -void DoSnapTToGrid(float hscale, float vscale); -// called to perform a fitting from the outside (shortcut key) -void SurfaceDialogFitAll(); - - -// Dialog Data -int m_nHeight; -int m_nWidth; - -// 0 is invalid, otherwise it's the Id of the last 'do' we are responsible for -int m_nUndoId; - - -texturewin_t *texturewin; -texdef_t *l_pIncrement; -texdef_t texdef_offset; -texdef_t texdef_SI_values; - -// For Texture Entry, activate only on entry change -char old_texture_entry[128]; - -// the texdef to switch back to when the OnCancel is called -texdef_t g_old_texdef; - -// when TRUE, this thing means the surface inspector is currently being displayed -bool g_surfwin = FALSE; -// turn on/off processing of the "changed" "value_changed" messages -// (need to turn off when we are feeding data in) -bool g_bListenChanged = true; -// turn on/off listening of the update messages -bool g_bListenUpdate = true; - -GtkWidget* create_SurfaceInspector (void); -GtkWidget *SurfaceInspector = NULL; - -GtkWidget *m_pWidget; -GtkWidget *GetWidget () { return SurfaceInspector; } -GtkWidget *Get_SI_Module_Widget () { return SurfaceInspector; } -void SetWidget(GtkWidget *new_widget) { m_pWidget = new_widget; } -GtkWidget *GetDlgWidget (const char* name) - { return GTK_WIDGET (g_object_get_data (G_OBJECT (SurfaceInspector), name)); } - -// Spins for FitTexture -GtkWidget *spin_width; -GtkWidget *spin_height; - - -GtkWidget *texture_combo; -GtkWidget *texture_combo_entry; - -GtkWidget *match_grid_button; -GtkWidget *lock_valuechange_togglebutton; - -GtkObject *hshift_value_spinbutton_adj; -GtkWidget *hshift_value_spinbutton; -GtkObject *vshift_value_spinbutton_adj; -GtkWidget *vshift_value_spinbutton; -GtkObject *hscale_value_spinbutton_adj; -GtkWidget *hscale_value_spinbutton; -GtkObject *vscale_value_spinbutton_adj; -GtkWidget *vscale_value_spinbutton; -GtkObject *rotate_value_spinbutton_adj; -GtkWidget *rotate_value_spinbutton; - -GtkObject *hshift_offset_spinbutton_adj; -GtkWidget *hshift_offset_spinbutton; -GtkObject *vshift_offset_spinbutton_adj; -GtkWidget *vshift_offset_spinbutton; -GtkObject *hscale_offset_spinbutton_adj; -GtkWidget *hscale_offset_spinbutton; -GtkObject *vscale_offset_spinbutton_adj; -GtkWidget *vscale_offset_spinbutton; -GtkObject *rotate_offset_spinbutton_adj; -GtkWidget *rotate_offset_spinbutton; - -GtkObject *hshift_step_spinbutton_adj; -GtkWidget *hshift_step_spinbutton; -GtkObject *vshift_step_spinbutton_adj; -GtkWidget *vshift_step_spinbutton; -GtkObject *hscale_step_spinbutton_adj; -GtkWidget *hscale_step_spinbutton; -GtkObject *vscale_step_spinbutton_adj; -GtkWidget *vscale_step_spinbutton; -GtkObject *rotate_step_spinbutton_adj; -GtkWidget *rotate_step_spinbutton; - -GtkObject *fit_width_spinbutton_adj; -GtkWidget *fit_width_spinbutton; -GtkObject *fit_height_spinbutton_adj; -GtkWidget *fit_height_spinbutton; -GtkWidget *fit_button; -GtkWidget *axial_button; - -GtkWidget *done_button; -GtkWidget *apply_button; -GtkWidget *cancel_button; - -// Callbacks -gboolean on_texture_combo_entry_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data); -void on_texture_combo_entry_activate (GtkEntry *entry, gpointer user_data); - -static void on_match_grid_button_clicked (GtkButton *button, gpointer user_data); -static void on_lock_valuechange_togglebutton_toggled (GtkToggleButton *togglebutton, gpointer user_data); - -static void on_hshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_vshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_hscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_vscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_rotate_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); - -static void on_hshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_vshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_hscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_vscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_rotate_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); - -static void on_hshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_vshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_hscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_vscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_rotate_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); - -static void on_fit_width_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_fit_height_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_fit_button_clicked (GtkButton *button, gpointer user_data); -static void on_axial_button_clicked (GtkButton *button, gpointer user_data); - -static void on_done_button_clicked (GtkButton *button, gpointer user_data); -static void on_apply_button_clicked (GtkButton *button, gpointer user_data); -static void on_cancel_button_clicked (GtkButton *button, gpointer user_data); - - -/* -=================================================== - - SURFACE INSPECTOR - -=================================================== -*/ - - -void IsFaceConflicting() -{ - texdef_t* tmp_texdef; - texdef_to_face_t* temp_texdef_face_list; - char buf[12]; - char texture_name[128]; - - if (texdef_face_list_empty()) - { - gtk_entry_set_text( GTK_ENTRY (hshift_value_spinbutton), ""); - gtk_entry_set_text( GTK_ENTRY (vshift_value_spinbutton), ""); - gtk_entry_set_text( GTK_ENTRY (hscale_value_spinbutton), ""); - gtk_entry_set_text( GTK_ENTRY (vscale_value_spinbutton), ""); - gtk_entry_set_text( GTK_ENTRY (rotate_value_spinbutton), ""); - gtk_entry_set_text( GTK_ENTRY (texture_combo_entry), ""); - return; - } - - g_bListenChanged = FALSE; - - tmp_texdef = &get_texdef_face_list()->texdef; - - strcpy(texture_name, tmp_texdef->GetName() ); - - texdef_SI_values.shift[0] = tmp_texdef->shift[0]; - texdef_SI_values.shift[1] = tmp_texdef->shift[1]; - texdef_SI_values.scale[0] = tmp_texdef->scale[0]; - texdef_SI_values.scale[1] = tmp_texdef->scale[1]; - texdef_SI_values.rotate = tmp_texdef->rotate; - texdef_SI_values.SetName( texture_name ); - - is_HShift_conflicting = FALSE; - is_VShift_conflicting = FALSE; - is_HScale_conflicting = FALSE; - is_VScale_conflicting = FALSE; - is_Rotate_conflicting = FALSE; - is_TextureName_conflicting = FALSE; - - if (texdef_face_list_size() > 1) - { - temp_texdef_face_list = get_texdef_face_list()->next; - - for (temp_texdef_face_list; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = &temp_texdef_face_list->texdef; - if ( texdef_SI_values.shift[0] != tmp_texdef->shift[0] ) - is_HShift_conflicting = TRUE; - - if ( texdef_SI_values.shift[1] != tmp_texdef->shift[1] ) - is_VShift_conflicting = TRUE; - - if ( texdef_SI_values.scale[0] != tmp_texdef->scale[0] ) - is_HScale_conflicting = TRUE; - - if ( texdef_SI_values.scale[1] != tmp_texdef->scale[1] ) - is_VScale_conflicting = TRUE; - - if ( texdef_SI_values.rotate != tmp_texdef->rotate ) - is_Rotate_conflicting = TRUE; - - if ( strcmp( texture_name, tmp_texdef->GetName() ) ) - is_TextureName_conflicting = TRUE; - } - } - - if(is_HShift_conflicting) - gtk_entry_set_text( GTK_ENTRY (hshift_value_spinbutton), ""); - else - gtk_spin_button_set_value( GTK_SPIN_BUTTON(hshift_value_spinbutton) , texdef_SI_values.shift[0] ); - - if(is_VShift_conflicting) - gtk_entry_set_text( GTK_ENTRY (vshift_value_spinbutton), ""); - else - gtk_spin_button_set_value( GTK_SPIN_BUTTON(vshift_value_spinbutton) , texdef_SI_values.shift[1] ); - - if(is_HScale_conflicting) - gtk_entry_set_text( GTK_ENTRY (hscale_value_spinbutton), ""); - else - gtk_spin_button_set_value( GTK_SPIN_BUTTON(hscale_value_spinbutton) , texdef_SI_values.scale[0] ); - - if(is_VScale_conflicting) - gtk_entry_set_text( GTK_ENTRY (vscale_value_spinbutton), ""); - else - gtk_spin_button_set_value( GTK_SPIN_BUTTON(vscale_value_spinbutton) , texdef_SI_values.scale[1] ); - - if(is_Rotate_conflicting) - gtk_entry_set_text( GTK_ENTRY (rotate_value_spinbutton), ""); - else - gtk_spin_button_set_value( GTK_SPIN_BUTTON(rotate_value_spinbutton) , texdef_SI_values.rotate ); - - g_bListenChanged = TRUE; -} - -#define MAX_NUM_LIST_ITEMS 15 -static void PopulateTextureComboList() -{ - texdef_t* tmp_texdef; - texdef_to_face_t* temp_texdef_face_list; - char blank[1]; - GList *items = NULL; - GList *tmp_item; - int num_of_list_items = 0; - - blank[0] = 0; - - if (texdef_face_list_empty()) - { - items = g_list_append (items, (gpointer) blank); - // For Texture Entry, activate only on entry change - strcpy (old_texture_entry, blank); - } - else if ( !is_TextureName_conflicting ) - { - temp_texdef_face_list = get_texdef_face_list(); - tmp_texdef = (texdef_t *) &get_texdef_face_list()->texdef; - items = g_list_append( items, (gpointer) tmp_texdef->GetName() ); - // For Texture Entry, activate only on entry change - strcpy (old_texture_entry, tmp_texdef->GetName()); - } - else - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - // Need to do a string compare, hence the custom search - if (!( g_list_find_custom (items, tmp_texdef->GetName(), (GCompareFunc) strcmp ) )) - { - items = g_list_append( items, (gpointer) tmp_texdef->GetName() ); - num_of_list_items++; - } - // Make sure the combo list isn't too long - if (num_of_list_items >= MAX_NUM_LIST_ITEMS) - break; - } - // If this isn't added last (to the top of the list), g_list_find freaks. - items = g_list_prepend (items, (gpointer) blank); - // For Texture Entry, activate only on entry change - strcpy (old_texture_entry, blank); - } - - gtk_combo_set_popdown_strings (GTK_COMBO (texture_combo), items); - g_list_free(items); - -} - -static void ZeroOffsetValues() -{ - texdef_offset.shift[0] = 0.0; - texdef_offset.shift[1] = 0.0; - texdef_offset.scale[0] = 0.0; - texdef_offset.scale[1] = 0.0; - texdef_offset.rotate = 0.0; -} - -static void GetTexdefInfo_from_Radiant() -{ - g_texdef_face_vector.clear(); - - unsigned int count = GetSelectedFaceCountfromBrushes(); - if(count == 0) - count = GetSelectedFaceCount(); - - g_texdef_face_vector.resize(count); - - if (!texdef_face_list_empty()) - { - texdef_to_face_t* p = get_texdef_face_list(); - GetSelFacesTexdef( get_texdef_face_list() ); - } - - IsFaceConflicting(); - PopulateTextureComboList(); - ZeroOffsetValues(); -} - -static gint delete_event_callback(GtkWidget *widget, GdkEvent* event, gpointer data) -{ - HideDlg(); - return TRUE; -} - -// make the shift increments match the grid settings -// the objective being that the shift+arrows shortcuts move the texture by the corresponding grid size -// this depends on a scale value if you have selected a particular texture on which you want it to work: -// we move the textures in pixels, not world units. (i.e. increment values are in pixel) -// depending on the texture scale it doesn't take the same amount of pixels to move of g_qeglobals.d_gridsize -// increment * scale = gridsize -// hscale and vscale are optional parameters, if they are zero they will be set to the default scale -// NOTE: the default scale depends if you are using BP mode or regular. -// For regular it's 0.5f (128 pixels cover 64 world units), for BP it's simply 1.0f -// see fenris #2810 -void DoSnapTToGrid(float hscale, float vscale) -{ - l_pIncrement = Get_SI_Inc(); - - if (hscale == 0.0f) - { - hscale = 0.5f; - } - if (vscale == 0.0f) - { - vscale = 0.5f; - } -#ifdef _DEBUG - Sys_Printf ("DoSnapTToGrid: hscale %g vscale %g\n", hscale, vscale); -#endif - l_pIncrement->shift[0] = GridSize() / hscale; - l_pIncrement->shift[1] = GridSize() / vscale; - // now some update work - // FIXME: doesn't look good here, seems to be called several times - SetTexMods(); -} - -void UpdateSurfaceDialog() -{ - if (!g_bListenUpdate) - return; - - if (!SurfaceInspector) - return; - - // avoid long delays on slow computers - while (gtk_events_pending ()) - gtk_main_iteration (); - - if (g_surfwin) - { -#ifdef DBG_SI - Sys_Printf("UpdateSurfaceDialog\n"); -#endif - GetTexdefInfo_from_Radiant(); - SetTexMods(); - } - -} - -// DoSurface will always try to show the surface inspector -// or update it because something new has been selected -void DoSurface (void) -{ -#ifdef DBG_SI - Sys_Printf("DoSurface\n"); -#endif - if (!SurfaceInspector) - create_SurfaceInspector (); - - ShowDlg(); - SetTexMods (); -} - -void ToggleSurface() -{ -#ifdef DBG_SI - Sys_Printf("ToggleSurface Module\n"); -#endif - if (!g_surfwin) - DoSurface (); - else - on_cancel_button_clicked(NULL, NULL); -} - -// NOTE: will raise and show the Surface inspector and exec fit for patches and brushes -void SurfaceDlgFitAll() -{ - DoSurface(); - FitAll(); -} - -// ============================================================================= -// SurfaceDialog class - -void ShowDlg() -{ - - if(!SurfaceInspector) - create_SurfaceInspector(); - else - gtk_widget_show (SurfaceInspector); - - GetTexdefInfo_from_Radiant(); - GetTexMods(TRUE); // Set Initial Undo Point - g_surfwin = TRUE; -} - -void HideDlg() -{ - g_surfwin = FALSE; - gtk_widget_hide (SurfaceInspector); -} - - -// set default values for increments (shift scale and rot) -// this is called by the prefs code if can't find the values -void InitDefaultIncrement(texdef_t *tex) -{ - tex->SetName("foo"); - tex->shift[0] = 8; - tex->shift[1] = 8; - tex->scale[0] = 0.25; - tex->scale[1] = 0.25; - tex->rotate = 10; -} - -void BuildDialog () -{ - if ( !SurfaceInspector ) - create_SurfaceInspector(); -} - -/* -============== -SetTexMods - -Set the fields to the current texdef (i.e. map/texdef -> dialog widgets) -=============== -*/ - -void SetTexMods() -{ - texdef_t *pt; - GtkSpinButton *spin; - GtkAdjustment *adjust; - - texturewin = Texturewin (); - l_pIncrement = Get_SI_Inc(); - -#ifdef DBG_SI - Sys_Printf("SurfaceDlg SetTexMods\n"); -#endif - - if (!g_surfwin) - return; - - pt = &texturewin->texdef; - - g_bListenChanged = false; - - if(strncmp(pt->GetName(), "textures/", 9) != 0) - texdef_offset.SetName(SHADER_NOT_FOUND); - - - spin = GTK_SPIN_BUTTON (hshift_offset_spinbutton); - gtk_spin_button_set_value (spin, texdef_offset.shift[0]); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->shift[0]; - gtk_spin_button_set_value (GTK_SPIN_BUTTON(hshift_step_spinbutton), l_pIncrement->shift[0]); - - spin = GTK_SPIN_BUTTON (hshift_value_spinbutton); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->shift[0]; - - - spin = GTK_SPIN_BUTTON (vshift_offset_spinbutton); - gtk_spin_button_set_value (spin, texdef_offset.shift[1]); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->shift[1]; - gtk_spin_button_set_value (GTK_SPIN_BUTTON(vshift_step_spinbutton), l_pIncrement->shift[1]); - - spin = GTK_SPIN_BUTTON (vshift_value_spinbutton); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->shift[1]; - - - spin = GTK_SPIN_BUTTON (hscale_offset_spinbutton); - gtk_spin_button_set_value (spin, texdef_offset.scale[0]); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->scale[0]; - gtk_spin_button_set_value (GTK_SPIN_BUTTON(hscale_step_spinbutton), l_pIncrement->scale[0]); - - spin = GTK_SPIN_BUTTON (hscale_value_spinbutton); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->scale[0]; - - - spin = GTK_SPIN_BUTTON (vscale_offset_spinbutton); - gtk_spin_button_set_value (spin, texdef_offset.scale[1]); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->scale[1]; - gtk_spin_button_set_value (GTK_SPIN_BUTTON(vscale_step_spinbutton), l_pIncrement->scale[1]); - - spin = GTK_SPIN_BUTTON (vscale_value_spinbutton); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->scale[1]; - - - spin = GTK_SPIN_BUTTON (rotate_offset_spinbutton); - gtk_spin_button_set_value (spin, texdef_offset.rotate); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->rotate; - gtk_spin_button_set_value (GTK_SPIN_BUTTON(rotate_step_spinbutton), l_pIncrement->rotate); - - spin = GTK_SPIN_BUTTON (rotate_value_spinbutton); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->rotate; - - - g_bListenChanged = true; - - // store the current texdef as our escape route if user hits OnCancel - g_old_texdef = texturewin->texdef; -} - -/* -============== -GetTexMods - -Shows any changes to the main Radiant windows -=============== -*/ -void GetTexMods(bool b_SetUndoPoint) -{ - -#ifdef DBG_SI - Sys_Printf("SurfaceDlg GetTexMods\n"); -#endif - - if ( !texdef_face_list_empty() ) - { - g_bListenUpdate=FALSE; - SetTexdef_FaceList( get_texdef_face_list(), b_SetUndoPoint, false ); - g_bListenUpdate=TRUE; - - if (b_SetUndoPoint) - m_nUndoId = Undo_GetUndoId(); - } -} - -void FitAll() -{ - on_fit_button_clicked(NULL, NULL); -} - - -//////////////////////////////////////////////////////////////////// -// -// GUI Section -// -//////////////////////////////////////////////////////////////////// - -GtkWidget* create_SurfaceInspector (void) -{ - - GtkWidget *label; - GtkWidget *hseparator; - GtkWidget *eventbox; - - GtkWidget *viewport8; - GtkWidget *viewport9; - GtkWidget *viewport2; - GtkWidget *viewport7; - GtkWidget *viewport5; - GtkWidget *viewport6; - GtkWidget *viewport10; - - GtkWidget *table1; - GtkWidget *table4; - GtkWidget *table5; - GtkWidget *table7; - - GtkWidget *alignment1; - GtkWidget *alignment2; - GtkWidget *alignment3; - - GtkWidget *vbox7; - - GtkWidget *hbox1; - GtkWidget *hbox2; - GtkWidget *hbox3; - GtkWidget *hbox4; - - GtkWidget *image1; - GtkWidget *image2; - GtkWidget *image3; - - GtkWidget *hbuttonbox1; - - SurfaceInspector = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_container_set_border_width (GTK_CONTAINER (SurfaceInspector), 4); - gtk_window_set_title (GTK_WINDOW (SurfaceInspector), "Surface Inspector"); - - SetWinPos_from_Prefs(SurfaceInspector); - - viewport8 = gtk_viewport_new (NULL, NULL); - gtk_widget_show (viewport8); - gtk_container_add (GTK_CONTAINER (SurfaceInspector), viewport8); - gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport8), GTK_SHADOW_NONE); - - vbox7 = gtk_vbox_new (FALSE, 0); - gtk_widget_show (vbox7); - gtk_container_add (GTK_CONTAINER (viewport8), vbox7); - - viewport9 = gtk_viewport_new (NULL, NULL); - gtk_widget_show (viewport9); - gtk_box_pack_start (GTK_BOX (vbox7), viewport9, FALSE, FALSE, 0); - gtk_container_set_border_width (GTK_CONTAINER (viewport9), 2); - gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport9), GTK_SHADOW_ETCHED_IN); - - hbox1 = gtk_hbox_new (FALSE, 0); - gtk_widget_show (hbox1); - gtk_container_add (GTK_CONTAINER (viewport9), hbox1); - gtk_container_set_border_width (GTK_CONTAINER (hbox1), 4); - - label = gtk_label_new ("Texture: "); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox1), label, FALSE, FALSE, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - texture_combo = gtk_combo_new (); - g_object_set_data (G_OBJECT (GTK_COMBO (texture_combo)->popwin), - "KeepMeAround", texture_combo); - gtk_combo_disable_activate ( (GtkCombo*) texture_combo); - gtk_widget_show (texture_combo); - gtk_box_pack_start (GTK_BOX (hbox1), texture_combo, TRUE, TRUE, 0); - - texture_combo_entry = GTK_COMBO (texture_combo)->entry; - gtk_widget_show (texture_combo_entry); - gtk_entry_set_max_length (GTK_ENTRY (texture_combo_entry), 128); - - viewport2 = gtk_viewport_new (NULL, NULL); - gtk_widget_show (viewport2); - gtk_box_pack_start (GTK_BOX (vbox7), viewport2, FALSE, TRUE, 0); - gtk_container_set_border_width (GTK_CONTAINER (viewport2), 2); - gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport2), GTK_SHADOW_ETCHED_IN); - - table1 = gtk_table_new (13, 4, FALSE); - gtk_widget_show (table1); - gtk_container_add (GTK_CONTAINER (viewport2), table1); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 3, 4, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 3, 4, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 3, 4, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 5, 6, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 5, 6, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 5, 6, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 7, 8, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 7, 8, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 7, 8, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 9, 10, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 9, 10, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 9, 10, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 11, 12, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 11, 12, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 11, 12, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label = gtk_label_new ("Offset"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table1), label, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - label = gtk_label_new ("Step"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table1), label, 3, 4, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 3, 4, 12, 13, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - match_grid_button = gtk_button_new_with_mnemonic ("Match Grid"); - gtk_widget_show (match_grid_button); - gtk_container_add (GTK_CONTAINER (eventbox), match_grid_button); - - label = gtk_label_new ("Value"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table1), label, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 3, 4, - (GtkAttachOptions) (GTK_SHRINK | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 5, 6, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 7, 8, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 9, 10, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 11, 12, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 4, 5, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label = gtk_label_new ("V Shift: "); - gtk_widget_show (label); - gtk_container_add (GTK_CONTAINER (eventbox), label); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 6, 7, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label = gtk_label_new (" H Scale: "); - gtk_widget_show (label); - gtk_container_add (GTK_CONTAINER (eventbox), label); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 8, 9, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label = gtk_label_new ("V Scale: "); - gtk_widget_show (label); - gtk_container_add (GTK_CONTAINER (eventbox), label); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 10, 11, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label = gtk_label_new ("Rotate: "); - gtk_widget_show (label); - gtk_container_add (GTK_CONTAINER (eventbox), label); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label = gtk_label_new ("H Shift: "); - gtk_widget_show (label); - gtk_container_add (GTK_CONTAINER (eventbox), label); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 1, 2, 12, 13, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - lock_valuechange_togglebutton = gtk_toggle_button_new_with_mnemonic ("UNLOCK"); - gtk_widget_show (lock_valuechange_togglebutton); - gtk_container_add (GTK_CONTAINER (eventbox), lock_valuechange_togglebutton); - - // Value Spins - hshift_value_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); - hshift_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_value_spinbutton_adj), 1, 2); - gtk_widget_show (hshift_value_spinbutton); - gtk_table_attach (GTK_TABLE (table1), hshift_value_spinbutton, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_value_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hshift_value_spinbutton), TRUE); - gtk_widget_set_sensitive( GTK_WIDGET( hshift_value_spinbutton ), FALSE ); - - vshift_value_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); - vshift_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_value_spinbutton_adj), 1, 2); - gtk_widget_show (vshift_value_spinbutton); - gtk_table_attach (GTK_TABLE (table1), vshift_value_spinbutton, 1, 2, 4, 5, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_value_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vshift_value_spinbutton), TRUE); - gtk_widget_set_sensitive( GTK_WIDGET( vshift_value_spinbutton ), FALSE ); - - hscale_value_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); - hscale_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_value_spinbutton_adj), 1, 4); - gtk_widget_show (hscale_value_spinbutton); - gtk_table_attach (GTK_TABLE (table1), hscale_value_spinbutton, 1, 2, 6, 7, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_value_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hscale_value_spinbutton), TRUE); - gtk_widget_set_sensitive( GTK_WIDGET( hscale_value_spinbutton ), FALSE ); - - vscale_value_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); - vscale_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_value_spinbutton_adj), 1, 4); - gtk_widget_show (vscale_value_spinbutton); - gtk_table_attach (GTK_TABLE (table1), vscale_value_spinbutton, 1, 2, 8, 9, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_value_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vscale_value_spinbutton), TRUE); - gtk_widget_set_sensitive( GTK_WIDGET( vscale_value_spinbutton ), FALSE ); - - rotate_value_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); - rotate_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_value_spinbutton_adj), 1, 0); - gtk_widget_show (rotate_value_spinbutton); - gtk_table_attach (GTK_TABLE (table1), rotate_value_spinbutton, 1, 2, 10, 11, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_value_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (rotate_value_spinbutton), TRUE); - gtk_widget_set_sensitive( GTK_WIDGET( rotate_value_spinbutton ), FALSE ); - - // Offset Spins - hshift_offset_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); - hshift_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_offset_spinbutton_adj), 0, 2); - gtk_widget_show (hshift_offset_spinbutton); - gtk_table_attach (GTK_TABLE (table1), hshift_offset_spinbutton, 2, 3, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 4, 0); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (hshift_offset_spinbutton), TRUE); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_offset_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hshift_offset_spinbutton), TRUE); - - vshift_offset_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); - vshift_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_offset_spinbutton_adj), 0, 2); - gtk_widget_show (vshift_offset_spinbutton); - gtk_table_attach (GTK_TABLE (table1), vshift_offset_spinbutton, 2, 3, 4, 5, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 4, 0); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (vshift_offset_spinbutton), TRUE); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_offset_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vshift_offset_spinbutton), TRUE); - - hscale_offset_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); - hscale_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_offset_spinbutton_adj), 0, 4); - gtk_widget_show (hscale_offset_spinbutton); - gtk_table_attach (GTK_TABLE (table1), hscale_offset_spinbutton, 2, 3, 6, 7, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 4, 0); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (hscale_offset_spinbutton), TRUE); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_offset_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hscale_offset_spinbutton), TRUE); - - vscale_offset_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); - vscale_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_offset_spinbutton_adj), 0, 4); - gtk_widget_show (vscale_offset_spinbutton); - gtk_table_attach (GTK_TABLE (table1), vscale_offset_spinbutton, 2, 3, 8, 9, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 4, 0); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (vscale_offset_spinbutton), TRUE); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_offset_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vscale_offset_spinbutton), TRUE); - - rotate_offset_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); - rotate_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_offset_spinbutton_adj), 0, 2); - gtk_widget_show (rotate_offset_spinbutton); - gtk_table_attach (GTK_TABLE (table1), rotate_offset_spinbutton, 2, 3, 10, 11, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 4, 0); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (rotate_offset_spinbutton), TRUE); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_offset_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (rotate_offset_spinbutton), TRUE); - - // Step Spins - hshift_step_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); - hshift_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_step_spinbutton_adj), 1, 2); - gtk_widget_show (hshift_step_spinbutton); - gtk_table_attach (GTK_TABLE (table1), hshift_step_spinbutton, 3, 4, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_step_spinbutton), GTK_UPDATE_IF_VALID); - - vshift_step_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); - vshift_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_step_spinbutton_adj), 1, 2); - gtk_widget_show (vshift_step_spinbutton); - gtk_table_attach (GTK_TABLE (table1), vshift_step_spinbutton, 3, 4, 4, 5, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_step_spinbutton), GTK_UPDATE_IF_VALID); - - hscale_step_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); - hscale_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_step_spinbutton_adj), 1, 4); - gtk_widget_show (hscale_step_spinbutton); - gtk_table_attach (GTK_TABLE (table1), hscale_step_spinbutton, 3, 4, 6, 7, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_step_spinbutton), GTK_UPDATE_IF_VALID); - - vscale_step_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); - vscale_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_step_spinbutton_adj), 1, 4); - gtk_widget_show (vscale_step_spinbutton); - gtk_table_attach (GTK_TABLE (table1), vscale_step_spinbutton, 3, 4, 8, 9, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_step_spinbutton), GTK_UPDATE_IF_VALID); - - rotate_step_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); - rotate_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_step_spinbutton_adj), 1, 2); - gtk_widget_show (rotate_step_spinbutton); - gtk_table_attach (GTK_TABLE (table1), rotate_step_spinbutton, 3, 4, 10, 11, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_step_spinbutton), GTK_UPDATE_IF_VALID); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 2, 3, 12, 13, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 12, 13, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - viewport7 = gtk_viewport_new (NULL, NULL); - gtk_widget_show (viewport7); - gtk_box_pack_start (GTK_BOX (vbox7), viewport7, FALSE, TRUE, 0); - gtk_container_set_border_width (GTK_CONTAINER (viewport7), 2); - gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport7), GTK_SHADOW_ETCHED_IN); - - table4 = gtk_table_new (4, 7, FALSE); - gtk_widget_show (table4); - gtk_container_add (GTK_CONTAINER (viewport7), table4); - - viewport5 = gtk_viewport_new (NULL, NULL); - gtk_widget_show (viewport5); - gtk_table_attach (GTK_TABLE (table4), viewport5, 1, 7, 0, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (viewport5), 6); - gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport5), GTK_SHADOW_ETCHED_OUT); - - table5 = gtk_table_new (2, 3, FALSE); - gtk_widget_show (table5); - gtk_container_add (GTK_CONTAINER (viewport5), table5); - gtk_container_set_border_width (GTK_CONTAINER (table5), 5); - gtk_table_set_col_spacings (GTK_TABLE (table5), 2); - - label = gtk_label_new ("Height"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table5), label, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); - - label = gtk_label_new ("Width"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table5), label, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); - - fit_width_spinbutton_adj = gtk_adjustment_new (1, 1, 32, 1, 10, 10); - fit_width_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (fit_width_spinbutton_adj), 1, 0); - gtk_widget_show (fit_width_spinbutton); - gtk_table_attach (GTK_TABLE (table5), fit_width_spinbutton, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (fit_width_spinbutton), TRUE); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (fit_width_spinbutton), GTK_UPDATE_IF_VALID); - - fit_height_spinbutton_adj = gtk_adjustment_new (1, 1, 32, 1, 10, 10); - fit_height_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (fit_height_spinbutton_adj), 1, 0); - gtk_widget_show (fit_height_spinbutton); - gtk_table_attach (GTK_TABLE (table5), fit_height_spinbutton, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 3, 0); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (fit_height_spinbutton), TRUE); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (fit_height_spinbutton), GTK_UPDATE_IF_VALID); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table5), eventbox, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table5), eventbox, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 4, 0); - - fit_button = gtk_button_new_with_mnemonic (" Fit "); - gtk_widget_show (fit_button); - gtk_container_add (GTK_CONTAINER (eventbox), fit_button); - - viewport6 = gtk_viewport_new (NULL, NULL); - gtk_widget_show (viewport6); - gtk_table_attach (GTK_TABLE (table4), viewport6, 0, 1, 0, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (viewport6), 4); - gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport6), GTK_SHADOW_NONE); - - table7 = gtk_table_new (2, 1, FALSE); - gtk_widget_show (table7); - gtk_container_add (GTK_CONTAINER (viewport6), table7); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table7), eventbox, 0, 1, 0, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - axial_button = gtk_button_new_with_mnemonic ("Axial"); - gtk_widget_show (axial_button); - gtk_container_add (GTK_CONTAINER (eventbox), axial_button); - gtk_widget_set_size_request (axial_button, 56, 29); - gtk_container_set_border_width (GTK_CONTAINER (axial_button), 4); - - viewport10 = gtk_viewport_new (NULL, NULL); - gtk_widget_show (viewport10); - gtk_box_pack_start (GTK_BOX (vbox7), viewport10, FALSE, TRUE, 0); - gtk_container_set_border_width (GTK_CONTAINER (viewport10), 2); - gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport10), GTK_SHADOW_ETCHED_IN); - - hbuttonbox1 = gtk_hbutton_box_new (); - gtk_widget_show (hbuttonbox1); - gtk_container_add (GTK_CONTAINER (viewport10), hbuttonbox1); - gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox1), 4); - gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_SPREAD); - - done_button = gtk_button_new (); - gtk_widget_show (done_button); - gtk_container_add (GTK_CONTAINER (hbuttonbox1), done_button); - GTK_WIDGET_SET_FLAGS (done_button, GTK_CAN_DEFAULT); - - alignment1 = gtk_alignment_new (0.5, 0.5, 0, 0); - gtk_widget_show (alignment1); - gtk_container_add (GTK_CONTAINER (done_button), alignment1); - - hbox2 = gtk_hbox_new (FALSE, 2); - gtk_widget_show (hbox2); - gtk_container_add (GTK_CONTAINER (alignment1), hbox2); - - image1 = gtk_image_new_from_stock ("gtk-yes", GTK_ICON_SIZE_BUTTON); - gtk_widget_show (image1); - gtk_box_pack_start (GTK_BOX (hbox2), image1, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic ("Done"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - - apply_button = gtk_button_new (); - gtk_widget_show (apply_button); - gtk_container_add (GTK_CONTAINER (hbuttonbox1), apply_button); - GTK_WIDGET_SET_FLAGS (apply_button, GTK_CAN_DEFAULT); - - alignment3 = gtk_alignment_new (0.5, 0.5, 0, 0); - gtk_widget_show (alignment3); - gtk_container_add (GTK_CONTAINER (apply_button), alignment3); - - hbox4 = gtk_hbox_new (FALSE, 2); - gtk_widget_show (hbox4); - gtk_container_add (GTK_CONTAINER (alignment3), hbox4); - - image3 = gtk_image_new_from_stock ("gtk-apply", GTK_ICON_SIZE_BUTTON); - gtk_widget_show (image3); - gtk_box_pack_start (GTK_BOX (hbox4), image3, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic ("Apply"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox4), label, FALSE, FALSE, 0); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - - cancel_button = gtk_button_new (); - gtk_widget_show (cancel_button); - gtk_container_add (GTK_CONTAINER (hbuttonbox1), cancel_button); - GTK_WIDGET_SET_FLAGS (cancel_button, GTK_CAN_DEFAULT); - - alignment2 = gtk_alignment_new (0.5, 0.5, 0, 0); - gtk_widget_show (alignment2); - gtk_container_add (GTK_CONTAINER (cancel_button), alignment2); - - hbox3 = gtk_hbox_new (FALSE, 2); - gtk_widget_show (hbox3); - gtk_container_add (GTK_CONTAINER (alignment2), hbox3); - - image2 = gtk_image_new_from_stock ("gtk-no", GTK_ICON_SIZE_BUTTON); - gtk_widget_show (image2); - gtk_box_pack_start (GTK_BOX (hbox3), image2, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic ("Cancel"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox3), label, FALSE, FALSE, 0); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - - - g_signal_connect ( (gpointer) SurfaceInspector, - "delete_event", - G_CALLBACK (delete_event_callback), - NULL ); - g_signal_connect ((gpointer) SurfaceInspector, "destroy", - G_CALLBACK (gtk_widget_destroy), - NULL); - - g_signal_connect ((gpointer) texture_combo_entry, "key_press_event", - G_CALLBACK (on_texture_combo_entry_key_press_event), - NULL); - g_signal_connect ((gpointer) texture_combo_entry, "activate", - G_CALLBACK (on_texture_combo_entry_activate), - NULL); - - - g_signal_connect ((gpointer) hshift_offset_spinbutton, "value_changed", - G_CALLBACK (on_hshift_offset_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) vshift_offset_spinbutton, "value_changed", - G_CALLBACK (on_vshift_offset_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) hscale_offset_spinbutton, "value_changed", - G_CALLBACK (on_hscale_offset_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) vscale_offset_spinbutton, "value_changed", - G_CALLBACK (on_vscale_offset_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) rotate_offset_spinbutton, "value_changed", - G_CALLBACK (on_rotate_offset_spinbutton_value_changed), - NULL); - - g_signal_connect ((gpointer) hshift_value_spinbutton, "value_changed", - G_CALLBACK (on_hshift_value_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) vshift_value_spinbutton, "value_changed", - G_CALLBACK (on_vshift_value_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) hscale_value_spinbutton, "value_changed", - G_CALLBACK (on_hscale_value_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) vscale_value_spinbutton, "value_changed", - G_CALLBACK (on_vscale_value_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) rotate_value_spinbutton, "value_changed", - G_CALLBACK (on_rotate_value_spinbutton_value_changed), - NULL); - - g_signal_connect ((gpointer) hshift_step_spinbutton, "value_changed", - G_CALLBACK (on_hshift_step_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) vshift_step_spinbutton, "value_changed", - G_CALLBACK (on_vshift_step_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) hscale_step_spinbutton, "value_changed", - G_CALLBACK (on_hscale_step_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) vscale_step_spinbutton, "value_changed", - G_CALLBACK (on_vscale_step_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) rotate_step_spinbutton, "value_changed", - G_CALLBACK (on_rotate_step_spinbutton_value_changed), - NULL); - - g_signal_connect ((gpointer) match_grid_button, "clicked", - G_CALLBACK (on_match_grid_button_clicked), - NULL); - g_signal_connect ((gpointer) lock_valuechange_togglebutton, "toggled", - G_CALLBACK (on_lock_valuechange_togglebutton_toggled), - NULL); - - g_signal_connect ((gpointer) fit_width_spinbutton, "value_changed", - G_CALLBACK (on_fit_width_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) fit_height_spinbutton, "value_changed", - G_CALLBACK (on_fit_height_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) fit_button, "clicked", - G_CALLBACK (on_fit_button_clicked), - NULL); - - g_signal_connect ((gpointer) axial_button, "clicked", - G_CALLBACK (on_axial_button_clicked), - NULL); - - g_signal_connect ((gpointer) done_button, "clicked", - G_CALLBACK (on_done_button_clicked), - NULL); - g_signal_connect ((gpointer) apply_button, "clicked", - G_CALLBACK (on_apply_button_clicked), - NULL); - g_signal_connect ((gpointer) cancel_button, "clicked", - G_CALLBACK (on_cancel_button_clicked), - NULL); - - - return SurfaceInspector; -} - - -// Texture Combo -gboolean on_texture_combo_entry_key_press_event (GtkWidget *widget, GdkEventKey *event, - gpointer user_data) -{ - // Have Tab activate selection as well as Return - if (event->keyval == GDK_Tab) - g_signal_emit_by_name ( texture_combo_entry, "activate" ); - - return FALSE; -} - -void on_texture_combo_entry_activate (GtkEntry *entry, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - char text[128] = { 0 }; - - if (!texdef_face_list_empty() && g_bListenChanged) - { - // activate only on entry change - strcpy( text, gtk_entry_get_text(entry)); - if ( strcmp( old_texture_entry, text )) - { - // Check for spaces in shader name - if (text[0] <= ' ' || strchr(text, ' ')) - Sys_FPrintf(SYS_WRN, "WARNING: spaces in shader names are not allowed, ignoring '%s'\n", text); - else - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - strcpy( old_texture_entry, text ); - tmp_texdef->SetName( text ); - } - GetTexMods(); - } - } - } -} - -// Offset Spins -static void on_hshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_offset.shift[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_offset_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - if (is_HShift_conflicting) - tmp_texdef->shift[0] = tmp_orig_texdef->shift[0] + texdef_offset.shift[0]; - else - tmp_texdef->shift[0] = texdef_SI_values.shift[0] + texdef_offset.shift[0]; - } - GetTexMods(); - } -} - -static void on_vshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_offset.shift[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_offset_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - if (is_VShift_conflicting) - tmp_texdef->shift[1] = tmp_orig_texdef->shift[1] + texdef_offset.shift[1]; - else - tmp_texdef->shift[1] = texdef_SI_values.shift[1] + texdef_offset.shift[1]; - } - GetTexMods(); - } - -} - -static void on_hscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_offset.scale[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_offset_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - if (is_HScale_conflicting) - tmp_texdef->scale[0] = tmp_orig_texdef->scale[0] + texdef_offset.scale[0]; - else - tmp_texdef->scale[0] = texdef_SI_values.scale[0] + texdef_offset.scale[0]; - } - GetTexMods(); - } - - -} - -static void on_vscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_offset.scale[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_offset_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - if (is_VScale_conflicting) - tmp_texdef->scale[1] = tmp_orig_texdef->scale[1] + texdef_offset.scale[1]; - else - tmp_texdef->scale[1] = texdef_SI_values.scale[1] + texdef_offset.scale[1]; - } - GetTexMods(); - } - -} - -static void on_rotate_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_offset.rotate = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_offset_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - if (is_Rotate_conflicting) - tmp_texdef->rotate = tmp_orig_texdef->rotate + texdef_offset.rotate; - else - tmp_texdef->rotate = texdef_SI_values.rotate + texdef_offset.rotate; - } - GetTexMods(); - } - -} - - -// Match Grid -static void on_match_grid_button_clicked (GtkButton *button, gpointer user_data) -{ - float hscale, vscale; - - if( !strcmp(gtk_entry_get_text (GTK_ENTRY (hscale_value_spinbutton)), "") ) - hscale = 0.0; - else - hscale = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_value_spinbutton) ); - - if( !strcmp( gtk_entry_get_text (GTK_ENTRY (vscale_value_spinbutton)), "") ) - vscale = 0.0; - else - vscale = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_value_spinbutton) ); - DoSnapTToGrid (hscale, vscale); -} - - -// Lock out changes to Value -static void on_lock_valuechange_togglebutton_toggled (GtkToggleButton *togglebutton, gpointer user_data) -{ - bool is_Locked; - - is_Locked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lock_valuechange_togglebutton)); - - gtk_widget_set_sensitive( GTK_WIDGET( hscale_value_spinbutton ), is_Locked ); - gtk_widget_set_sensitive( GTK_WIDGET( vscale_value_spinbutton ), is_Locked ); - gtk_widget_set_sensitive( GTK_WIDGET( hshift_value_spinbutton ), is_Locked ); - gtk_widget_set_sensitive( GTK_WIDGET( vshift_value_spinbutton ), is_Locked ); - gtk_widget_set_sensitive( GTK_WIDGET( rotate_value_spinbutton ), is_Locked ); -} - - -// Value Spins -static void on_hshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_SI_values.shift[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_value_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - tmp_texdef->shift[0] = texdef_SI_values.shift[0] + texdef_offset.shift[0]; - is_HShift_conflicting = FALSE; - } - GetTexMods(); - } -} - -static void on_vshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_SI_values.shift[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_value_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - tmp_texdef->shift[1] = texdef_SI_values.shift[1] + texdef_offset.shift[1]; - is_VShift_conflicting = FALSE; - } - GetTexMods(); - } -} - -static void on_hscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_SI_values.scale[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_value_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - tmp_texdef->scale[0] = texdef_SI_values.scale[0] + texdef_offset.scale[0]; - is_HScale_conflicting = FALSE; - } - GetTexMods(); - } -} - -static void on_vscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_SI_values.scale[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_value_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - tmp_texdef->scale[1] = texdef_SI_values.scale[1] + texdef_offset.scale[1]; - is_VScale_conflicting = FALSE; - } - GetTexMods(); - } -} - -static void on_rotate_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_SI_values.rotate = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_value_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - tmp_texdef->rotate = texdef_SI_values.rotate + texdef_offset.rotate; - is_Rotate_conflicting = FALSE; - } - GetTexMods(); - } -} - - -// Step Spins -static void on_hshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - gfloat val; - GtkAdjustment * adjust; - - if (!g_bListenChanged) - return; - - l_pIncrement = Get_SI_Inc(); - -#ifdef DBG_SI - Sys_Printf("OnIncrementChanged HShift\n"); -#endif - - val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_step_spinbutton) ) ; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hshift_offset_spinbutton )); - adjust->step_increment = val; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hshift_value_spinbutton )); - adjust->step_increment = val; - l_pIncrement->shift[0] = val; -} - -static void on_vshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - gfloat val; - GtkAdjustment * adjust; - - if (!g_bListenChanged) - return; - - l_pIncrement = Get_SI_Inc(); - -#ifdef DBG_SI - Sys_Printf("OnIncrementChanged VShift\n"); -#endif - - val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_step_spinbutton) ) ; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vshift_offset_spinbutton )); - adjust->step_increment = val; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vshift_value_spinbutton )); - adjust->step_increment = val; - l_pIncrement->shift[1] = val; -} - -static void on_hscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - gfloat val; - GtkAdjustment * adjust; - - if (!g_bListenChanged) - return; - - l_pIncrement = Get_SI_Inc(); - -#ifdef DBG_SI - Sys_Printf("OnIncrementChanged HShift\n"); -#endif - - val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_step_spinbutton) ) ; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hscale_offset_spinbutton )); - adjust->step_increment = val; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hscale_value_spinbutton )); - adjust->step_increment = val; - l_pIncrement->scale[0] = val; -} - -static void on_vscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - gfloat val; - GtkAdjustment * adjust; - - if (!g_bListenChanged) - return; - - l_pIncrement = Get_SI_Inc(); - -#ifdef DBG_SI - Sys_Printf("OnIncrementChanged HShift\n"); -#endif - - val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_step_spinbutton) ) ; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vscale_offset_spinbutton )); - adjust->step_increment = val; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vscale_value_spinbutton )); - adjust->step_increment = val; - l_pIncrement->scale[1] = val; -} - -static void on_rotate_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - gfloat val; - GtkAdjustment * adjust; - - if (!g_bListenChanged) - return; - - l_pIncrement = Get_SI_Inc(); - -#ifdef DBG_SI - Sys_Printf("OnIncrementChanged HShift\n"); -#endif - - val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_step_spinbutton) ) ; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( rotate_offset_spinbutton )); - adjust->step_increment = val; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( rotate_value_spinbutton )); - adjust->step_increment = val; - l_pIncrement->rotate = val; -} - - -// Fit Texture -static void on_fit_width_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - m_nWidth = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(fit_width_spinbutton) ); -} - -static void on_fit_height_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - m_nHeight = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(fit_height_spinbutton) ); -} - -static void on_fit_button_clicked (GtkButton *button, gpointer user_data) -{ - FaceList_FitTexture(get_texdef_face_list(), m_nHeight, m_nWidth); - Sys_UpdateWindows(W_ALL); -} - - -// Axial Button -static void on_axial_button_clicked (GtkButton *button, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_texdef->shift[0] = 0.0; - tmp_texdef->shift[1] = 0.0; - tmp_texdef->scale[0] = 0.5; - tmp_texdef->scale[1] = 0.5; - tmp_texdef->rotate = 0.0; - } - } - - SetTexdef_FaceList( get_texdef_face_list(), FALSE, TRUE ); - Sys_UpdateWindows(W_ALL); -} - - -// Action Buttons -static void on_done_button_clicked (GtkButton *button, gpointer user_data) -{ - if ( !texdef_face_list_empty() ) - GetTexMods(TRUE); - HideDlg(); - Sys_UpdateWindows(W_ALL); -} - -static void on_apply_button_clicked (GtkButton *button, gpointer user_data) -{ - if (!g_bListenChanged) - return; - if ( !texdef_face_list_empty() ) - { - GetTexMods (TRUE); - Sys_UpdateWindows(W_CAMERA); - GetTexdefInfo_from_Radiant(); - SetTexMods(); - } -} - -static void on_cancel_button_clicked (GtkButton *button, gpointer user_data) -{ - texturewin = Texturewin (); - texturewin->texdef = g_old_texdef; - // cancel the last do if we own it - if ( (m_nUndoId == Undo_GetUndoId()) && ( m_nUndoId != 0 )) - { -#ifdef DBG_SI - Sys_Printf("OnCancel calling Undo_Undo\n"); -#endif - g_bListenUpdate = false; - Undo_Undo(TRUE); - g_bListenUpdate = true; - m_nUndoId = 0; - } - HideDlg(); -} - - +/* +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 +*/ + +// +// Surface Dialog Module +// + +// +// Nurail: Implemented to Module from the main Radiant Surface Dialog code +// + + +#include +#include + +#include "surfdlg_plugin.h" + + + +#ifdef _DEBUG +//#define DBG_SI 1 +#endif + +#include "gtkr_vector.h" + +vector g_texdef_face_vector; + +inline texdef_to_face_t* get_texdef_face_list() +{ + return &(*g_texdef_face_vector.begin()); +} + +inline unsigned int texdef_face_list_empty() +{ + return g_texdef_face_vector.empty(); +} + +inline unsigned int texdef_face_list_size() +{ + return g_texdef_face_vector.size(); +} + +// For different faces having different values +bool is_HShift_conflicting; +bool is_VShift_conflicting; +bool is_HScale_conflicting; +bool is_VScale_conflicting; +bool is_Rotate_conflicting; +bool is_TextureName_conflicting; + +void ShowDlg(); +void HideDlg(); +void SetTexMods(); +void GetTexMods(bool b_SetUndoPoint = FALSE); +void BuildDialog(); +void FitAll(); +void InitDefaultIncrement(texdef_t *); +void DoSnapTToGrid(float hscale, float vscale); +// called to perform a fitting from the outside (shortcut key) +void SurfaceDialogFitAll(); + + +// Dialog Data +int m_nHeight; +int m_nWidth; + +// 0 is invalid, otherwise it's the Id of the last 'do' we are responsible for +int m_nUndoId; + + +texturewin_t *texturewin; +texdef_t *l_pIncrement; +texdef_t texdef_offset; +texdef_t texdef_SI_values; + +// For Texture Entry, activate only on entry change +char old_texture_entry[128]; + +// the texdef to switch back to when the OnCancel is called +texdef_t g_old_texdef; + +// when TRUE, this thing means the surface inspector is currently being displayed +bool g_surfwin = FALSE; +// turn on/off processing of the "changed" "value_changed" messages +// (need to turn off when we are feeding data in) +bool g_bListenChanged = true; +// turn on/off listening of the update messages +bool g_bListenUpdate = true; + +GtkWidget* create_SurfaceInspector (void); +GtkWidget *SurfaceInspector = NULL; + +GtkWidget *m_pWidget; +GtkWidget *GetWidget () { return SurfaceInspector; } +GtkWidget *Get_SI_Module_Widget () { return SurfaceInspector; } +void SetWidget(GtkWidget *new_widget) { m_pWidget = new_widget; } +GtkWidget *GetDlgWidget (const char* name) + { return GTK_WIDGET (g_object_get_data (G_OBJECT (SurfaceInspector), name)); } + +// Spins for FitTexture +GtkWidget *spin_width; +GtkWidget *spin_height; + + +GtkWidget *texture_combo; +GtkWidget *texture_combo_entry; + +GtkWidget *match_grid_button; +GtkWidget *lock_valuechange_togglebutton; + +GtkObject *hshift_value_spinbutton_adj; +GtkWidget *hshift_value_spinbutton; +GtkObject *vshift_value_spinbutton_adj; +GtkWidget *vshift_value_spinbutton; +GtkObject *hscale_value_spinbutton_adj; +GtkWidget *hscale_value_spinbutton; +GtkObject *vscale_value_spinbutton_adj; +GtkWidget *vscale_value_spinbutton; +GtkObject *rotate_value_spinbutton_adj; +GtkWidget *rotate_value_spinbutton; + +GtkObject *hshift_offset_spinbutton_adj; +GtkWidget *hshift_offset_spinbutton; +GtkObject *vshift_offset_spinbutton_adj; +GtkWidget *vshift_offset_spinbutton; +GtkObject *hscale_offset_spinbutton_adj; +GtkWidget *hscale_offset_spinbutton; +GtkObject *vscale_offset_spinbutton_adj; +GtkWidget *vscale_offset_spinbutton; +GtkObject *rotate_offset_spinbutton_adj; +GtkWidget *rotate_offset_spinbutton; + +GtkObject *hshift_step_spinbutton_adj; +GtkWidget *hshift_step_spinbutton; +GtkObject *vshift_step_spinbutton_adj; +GtkWidget *vshift_step_spinbutton; +GtkObject *hscale_step_spinbutton_adj; +GtkWidget *hscale_step_spinbutton; +GtkObject *vscale_step_spinbutton_adj; +GtkWidget *vscale_step_spinbutton; +GtkObject *rotate_step_spinbutton_adj; +GtkWidget *rotate_step_spinbutton; + +GtkObject *fit_width_spinbutton_adj; +GtkWidget *fit_width_spinbutton; +GtkObject *fit_height_spinbutton_adj; +GtkWidget *fit_height_spinbutton; +GtkWidget *fit_button; +GtkWidget *axial_button; + +GtkWidget *done_button; +GtkWidget *apply_button; +GtkWidget *cancel_button; + +// Callbacks +gboolean on_texture_combo_entry_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data); +void on_texture_combo_entry_activate (GtkEntry *entry, gpointer user_data); + +static void on_match_grid_button_clicked (GtkButton *button, gpointer user_data); +static void on_lock_valuechange_togglebutton_toggled (GtkToggleButton *togglebutton, gpointer user_data); + +static void on_hshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_hscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_rotate_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); + +static void on_hshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_hscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_rotate_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); + +static void on_hshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_hscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_rotate_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); + +static void on_fit_width_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_fit_height_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_fit_button_clicked (GtkButton *button, gpointer user_data); +static void on_axial_button_clicked (GtkButton *button, gpointer user_data); + +static void on_done_button_clicked (GtkButton *button, gpointer user_data); +static void on_apply_button_clicked (GtkButton *button, gpointer user_data); +static void on_cancel_button_clicked (GtkButton *button, gpointer user_data); + + +/* +=================================================== + + SURFACE INSPECTOR + +=================================================== +*/ + + +void IsFaceConflicting() +{ + texdef_t* tmp_texdef; + texdef_to_face_t* temp_texdef_face_list; + char buf[12]; + char texture_name[128]; + + if (texdef_face_list_empty()) + { + gtk_entry_set_text( GTK_ENTRY (hshift_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (vshift_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (hscale_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (vscale_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (rotate_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (texture_combo_entry), ""); + return; + } + + g_bListenChanged = FALSE; + + tmp_texdef = &get_texdef_face_list()->texdef; + + strcpy(texture_name, tmp_texdef->GetName() ); + + texdef_SI_values.shift[0] = tmp_texdef->shift[0]; + texdef_SI_values.shift[1] = tmp_texdef->shift[1]; + texdef_SI_values.scale[0] = tmp_texdef->scale[0]; + texdef_SI_values.scale[1] = tmp_texdef->scale[1]; + texdef_SI_values.rotate = tmp_texdef->rotate; + texdef_SI_values.SetName( texture_name ); + + is_HShift_conflicting = FALSE; + is_VShift_conflicting = FALSE; + is_HScale_conflicting = FALSE; + is_VScale_conflicting = FALSE; + is_Rotate_conflicting = FALSE; + is_TextureName_conflicting = FALSE; + + if (texdef_face_list_size() > 1) + { + temp_texdef_face_list = get_texdef_face_list()->next; + + for (temp_texdef_face_list; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = &temp_texdef_face_list->texdef; + if ( texdef_SI_values.shift[0] != tmp_texdef->shift[0] ) + is_HShift_conflicting = TRUE; + + if ( texdef_SI_values.shift[1] != tmp_texdef->shift[1] ) + is_VShift_conflicting = TRUE; + + if ( texdef_SI_values.scale[0] != tmp_texdef->scale[0] ) + is_HScale_conflicting = TRUE; + + if ( texdef_SI_values.scale[1] != tmp_texdef->scale[1] ) + is_VScale_conflicting = TRUE; + + if ( texdef_SI_values.rotate != tmp_texdef->rotate ) + is_Rotate_conflicting = TRUE; + + if ( strcmp( texture_name, tmp_texdef->GetName() ) ) + is_TextureName_conflicting = TRUE; + } + } + + if(is_HShift_conflicting) + gtk_entry_set_text( GTK_ENTRY (hshift_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(hshift_value_spinbutton) , texdef_SI_values.shift[0] ); + + if(is_VShift_conflicting) + gtk_entry_set_text( GTK_ENTRY (vshift_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(vshift_value_spinbutton) , texdef_SI_values.shift[1] ); + + if(is_HScale_conflicting) + gtk_entry_set_text( GTK_ENTRY (hscale_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(hscale_value_spinbutton) , texdef_SI_values.scale[0] ); + + if(is_VScale_conflicting) + gtk_entry_set_text( GTK_ENTRY (vscale_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(vscale_value_spinbutton) , texdef_SI_values.scale[1] ); + + if(is_Rotate_conflicting) + gtk_entry_set_text( GTK_ENTRY (rotate_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(rotate_value_spinbutton) , texdef_SI_values.rotate ); + + g_bListenChanged = TRUE; +} + +#define MAX_NUM_LIST_ITEMS 15 +static void PopulateTextureComboList() +{ + texdef_t* tmp_texdef; + texdef_to_face_t* temp_texdef_face_list; + char blank[1]; + GList *items = NULL; + GList *tmp_item; + int num_of_list_items = 0; + + blank[0] = 0; + + if (texdef_face_list_empty()) + { + items = g_list_append (items, (gpointer) blank); + // For Texture Entry, activate only on entry change + strcpy (old_texture_entry, blank); + } + else if ( !is_TextureName_conflicting ) + { + temp_texdef_face_list = get_texdef_face_list(); + tmp_texdef = (texdef_t *) &get_texdef_face_list()->texdef; + items = g_list_append( items, (gpointer) tmp_texdef->GetName() ); + // For Texture Entry, activate only on entry change + strcpy (old_texture_entry, tmp_texdef->GetName()); + } + else + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + // Need to do a string compare, hence the custom search + if (!( g_list_find_custom (items, tmp_texdef->GetName(), (GCompareFunc) strcmp ) )) + { + items = g_list_append( items, (gpointer) tmp_texdef->GetName() ); + num_of_list_items++; + } + // Make sure the combo list isn't too long + if (num_of_list_items >= MAX_NUM_LIST_ITEMS) + break; + } + // If this isn't added last (to the top of the list), g_list_find freaks. + items = g_list_prepend (items, (gpointer) blank); + // For Texture Entry, activate only on entry change + strcpy (old_texture_entry, blank); + } + + gtk_combo_set_popdown_strings (GTK_COMBO (texture_combo), items); + g_list_free(items); + +} + +static void ZeroOffsetValues() +{ + texdef_offset.shift[0] = 0.0; + texdef_offset.shift[1] = 0.0; + texdef_offset.scale[0] = 0.0; + texdef_offset.scale[1] = 0.0; + texdef_offset.rotate = 0.0; +} + +static void GetTexdefInfo_from_Radiant() +{ + g_texdef_face_vector.clear(); + + unsigned int count = GetSelectedFaceCountfromBrushes(); + if(count == 0) + count = GetSelectedFaceCount(); + + g_texdef_face_vector.resize(count); + + if (!texdef_face_list_empty()) + { + texdef_to_face_t* p = get_texdef_face_list(); + GetSelFacesTexdef( get_texdef_face_list() ); + } + + IsFaceConflicting(); + PopulateTextureComboList(); + ZeroOffsetValues(); +} + +static gint delete_event_callback(GtkWidget *widget, GdkEvent* event, gpointer data) +{ + HideDlg(); + return TRUE; +} + +// make the shift increments match the grid settings +// the objective being that the shift+arrows shortcuts move the texture by the corresponding grid size +// this depends on a scale value if you have selected a particular texture on which you want it to work: +// we move the textures in pixels, not world units. (i.e. increment values are in pixel) +// depending on the texture scale it doesn't take the same amount of pixels to move of g_qeglobals.d_gridsize +// increment * scale = gridsize +// hscale and vscale are optional parameters, if they are zero they will be set to the default scale +// NOTE: the default scale depends if you are using BP mode or regular. +// For regular it's 0.5f (128 pixels cover 64 world units), for BP it's simply 1.0f +// see fenris #2810 +void DoSnapTToGrid(float hscale, float vscale) +{ + l_pIncrement = Get_SI_Inc(); + + if (hscale == 0.0f) + { + hscale = 0.5f; + } + if (vscale == 0.0f) + { + vscale = 0.5f; + } +#ifdef _DEBUG + Sys_Printf ("DoSnapTToGrid: hscale %g vscale %g\n", hscale, vscale); +#endif + l_pIncrement->shift[0] = GridSize() / hscale; + l_pIncrement->shift[1] = GridSize() / vscale; + // now some update work + // FIXME: doesn't look good here, seems to be called several times + SetTexMods(); +} + +void UpdateSurfaceDialog() +{ + if (!g_bListenUpdate) + return; + + if (!SurfaceInspector) + return; + + // avoid long delays on slow computers + while (gtk_events_pending ()) + gtk_main_iteration (); + + if (g_surfwin) + { +#ifdef DBG_SI + Sys_Printf("UpdateSurfaceDialog\n"); +#endif + GetTexdefInfo_from_Radiant(); + SetTexMods(); + } + +} + +// DoSurface will always try to show the surface inspector +// or update it because something new has been selected +void DoSurface (void) +{ +#ifdef DBG_SI + Sys_Printf("DoSurface\n"); +#endif + if (!SurfaceInspector) + create_SurfaceInspector (); + + ShowDlg(); + SetTexMods (); +} + +void ToggleSurface() +{ +#ifdef DBG_SI + Sys_Printf("ToggleSurface Module\n"); +#endif + if (!g_surfwin) + DoSurface (); + else + on_cancel_button_clicked(NULL, NULL); +} + +// NOTE: will raise and show the Surface inspector and exec fit for patches and brushes +void SurfaceDlgFitAll() +{ + DoSurface(); + FitAll(); +} + +// ============================================================================= +// SurfaceDialog class + +void ShowDlg() +{ + + if(!SurfaceInspector) + create_SurfaceInspector(); + else + gtk_widget_show (SurfaceInspector); + + GetTexdefInfo_from_Radiant(); + GetTexMods(TRUE); // Set Initial Undo Point + g_surfwin = TRUE; +} + +void HideDlg() +{ + g_surfwin = FALSE; + gtk_widget_hide (SurfaceInspector); +} + + +// set default values for increments (shift scale and rot) +// this is called by the prefs code if can't find the values +void InitDefaultIncrement(texdef_t *tex) +{ + tex->SetName("foo"); + tex->shift[0] = 8; + tex->shift[1] = 8; + tex->scale[0] = 0.25; + tex->scale[1] = 0.25; + tex->rotate = 10; +} + +void BuildDialog () +{ + if ( !SurfaceInspector ) + create_SurfaceInspector(); +} + +/* +============== +SetTexMods + +Set the fields to the current texdef (i.e. map/texdef -> dialog widgets) +=============== +*/ + +void SetTexMods() +{ + texdef_t *pt; + GtkSpinButton *spin; + GtkAdjustment *adjust; + + texturewin = Texturewin (); + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("SurfaceDlg SetTexMods\n"); +#endif + + if (!g_surfwin) + return; + + pt = &texturewin->texdef; + + g_bListenChanged = false; + + if(strncmp(pt->GetName(), "textures/", 9) != 0) + texdef_offset.SetName(SHADER_NOT_FOUND); + + + spin = GTK_SPIN_BUTTON (hshift_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.shift[0]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[0]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(hshift_step_spinbutton), l_pIncrement->shift[0]); + + spin = GTK_SPIN_BUTTON (hshift_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[0]; + + + spin = GTK_SPIN_BUTTON (vshift_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.shift[1]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[1]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(vshift_step_spinbutton), l_pIncrement->shift[1]); + + spin = GTK_SPIN_BUTTON (vshift_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[1]; + + + spin = GTK_SPIN_BUTTON (hscale_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.scale[0]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[0]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(hscale_step_spinbutton), l_pIncrement->scale[0]); + + spin = GTK_SPIN_BUTTON (hscale_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[0]; + + + spin = GTK_SPIN_BUTTON (vscale_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.scale[1]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[1]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(vscale_step_spinbutton), l_pIncrement->scale[1]); + + spin = GTK_SPIN_BUTTON (vscale_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[1]; + + + spin = GTK_SPIN_BUTTON (rotate_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.rotate); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->rotate; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(rotate_step_spinbutton), l_pIncrement->rotate); + + spin = GTK_SPIN_BUTTON (rotate_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->rotate; + + + g_bListenChanged = true; + + // store the current texdef as our escape route if user hits OnCancel + g_old_texdef = texturewin->texdef; +} + +/* +============== +GetTexMods + +Shows any changes to the main Radiant windows +=============== +*/ +void GetTexMods(bool b_SetUndoPoint) +{ + +#ifdef DBG_SI + Sys_Printf("SurfaceDlg GetTexMods\n"); +#endif + + if ( !texdef_face_list_empty() ) + { + g_bListenUpdate=FALSE; + SetTexdef_FaceList( get_texdef_face_list(), b_SetUndoPoint, false ); + g_bListenUpdate=TRUE; + + if (b_SetUndoPoint) + m_nUndoId = Undo_GetUndoId(); + } +} + +void FitAll() +{ + on_fit_button_clicked(NULL, NULL); +} + + +//////////////////////////////////////////////////////////////////// +// +// GUI Section +// +//////////////////////////////////////////////////////////////////// + +GtkWidget* create_SurfaceInspector (void) +{ + + GtkWidget *label; + GtkWidget *hseparator; + GtkWidget *eventbox; + + GtkWidget *viewport8; + GtkWidget *viewport9; + GtkWidget *viewport2; + GtkWidget *viewport7; + GtkWidget *viewport5; + GtkWidget *viewport6; + GtkWidget *viewport10; + + GtkWidget *table1; + GtkWidget *table4; + GtkWidget *table5; + GtkWidget *table7; + + GtkWidget *alignment1; + GtkWidget *alignment2; + GtkWidget *alignment3; + + GtkWidget *vbox7; + + GtkWidget *hbox1; + GtkWidget *hbox2; + GtkWidget *hbox3; + GtkWidget *hbox4; + + GtkWidget *image1; + GtkWidget *image2; + GtkWidget *image3; + + GtkWidget *hbuttonbox1; + + SurfaceInspector = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (SurfaceInspector), 4); + gtk_window_set_title (GTK_WINDOW (SurfaceInspector), "Surface Inspector"); + + SetWinPos_from_Prefs(SurfaceInspector); + + viewport8 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport8); + gtk_container_add (GTK_CONTAINER (SurfaceInspector), viewport8); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport8), GTK_SHADOW_NONE); + + vbox7 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox7); + gtk_container_add (GTK_CONTAINER (viewport8), vbox7); + + viewport9 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport9); + gtk_box_pack_start (GTK_BOX (vbox7), viewport9, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport9), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport9), GTK_SHADOW_ETCHED_IN); + + hbox1 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox1); + gtk_container_add (GTK_CONTAINER (viewport9), hbox1); + gtk_container_set_border_width (GTK_CONTAINER (hbox1), 4); + + label = gtk_label_new ("Texture: "); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox1), label, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + texture_combo = gtk_combo_new (); + g_object_set_data (G_OBJECT (GTK_COMBO (texture_combo)->popwin), + "KeepMeAround", texture_combo); + gtk_combo_disable_activate ( (GtkCombo*) texture_combo); + gtk_widget_show (texture_combo); + gtk_box_pack_start (GTK_BOX (hbox1), texture_combo, TRUE, TRUE, 0); + + texture_combo_entry = GTK_COMBO (texture_combo)->entry; + gtk_widget_show (texture_combo_entry); + gtk_entry_set_max_length (GTK_ENTRY (texture_combo_entry), 128); + + viewport2 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport2); + gtk_box_pack_start (GTK_BOX (vbox7), viewport2, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport2), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport2), GTK_SHADOW_ETCHED_IN); + + table1 = gtk_table_new (13, 4, FALSE); + gtk_widget_show (table1); + gtk_container_add (GTK_CONTAINER (viewport2), table1); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Offset"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table1), label, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("Step"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table1), label, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 3, 4, 12, 13, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + match_grid_button = gtk_button_new_with_mnemonic ("Match Grid"); + gtk_widget_show (match_grid_button); + gtk_container_add (GTK_CONTAINER (eventbox), match_grid_button); + + label = gtk_label_new ("Value"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table1), label, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_SHRINK | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("V Shift: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 6, 7, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new (" H Scale: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 8, 9, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("V Scale: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 10, 11, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Rotate: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("H Shift: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 1, 2, 12, 13, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + lock_valuechange_togglebutton = gtk_toggle_button_new_with_mnemonic ("UNLOCK"); + gtk_widget_show (lock_valuechange_togglebutton); + gtk_container_add (GTK_CONTAINER (eventbox), lock_valuechange_togglebutton); + + // Value Spins + hshift_value_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + hshift_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_value_spinbutton_adj), 1, 2); + gtk_widget_show (hshift_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hshift_value_spinbutton, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hshift_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( hshift_value_spinbutton ), FALSE ); + + vshift_value_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + vshift_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_value_spinbutton_adj), 1, 2); + gtk_widget_show (vshift_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vshift_value_spinbutton, 1, 2, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vshift_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( vshift_value_spinbutton ), FALSE ); + + hscale_value_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + hscale_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_value_spinbutton_adj), 1, 4); + gtk_widget_show (hscale_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hscale_value_spinbutton, 1, 2, 6, 7, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hscale_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( hscale_value_spinbutton ), FALSE ); + + vscale_value_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + vscale_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_value_spinbutton_adj), 1, 4); + gtk_widget_show (vscale_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vscale_value_spinbutton, 1, 2, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vscale_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( vscale_value_spinbutton ), FALSE ); + + rotate_value_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); + rotate_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_value_spinbutton_adj), 1, 0); + gtk_widget_show (rotate_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), rotate_value_spinbutton, 1, 2, 10, 11, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (rotate_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( rotate_value_spinbutton ), FALSE ); + + // Offset Spins + hshift_offset_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + hshift_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_offset_spinbutton_adj), 0, 2); + gtk_widget_show (hshift_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hshift_offset_spinbutton, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (hshift_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hshift_offset_spinbutton), TRUE); + + vshift_offset_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + vshift_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_offset_spinbutton_adj), 0, 2); + gtk_widget_show (vshift_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vshift_offset_spinbutton, 2, 3, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (vshift_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vshift_offset_spinbutton), TRUE); + + hscale_offset_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + hscale_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_offset_spinbutton_adj), 0, 4); + gtk_widget_show (hscale_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hscale_offset_spinbutton, 2, 3, 6, 7, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (hscale_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hscale_offset_spinbutton), TRUE); + + vscale_offset_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + vscale_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_offset_spinbutton_adj), 0, 4); + gtk_widget_show (vscale_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vscale_offset_spinbutton, 2, 3, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (vscale_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vscale_offset_spinbutton), TRUE); + + rotate_offset_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); + rotate_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_offset_spinbutton_adj), 0, 2); + gtk_widget_show (rotate_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), rotate_offset_spinbutton, 2, 3, 10, 11, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (rotate_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (rotate_offset_spinbutton), TRUE); + + // Step Spins + hshift_step_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + hshift_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_step_spinbutton_adj), 1, 2); + gtk_widget_show (hshift_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hshift_step_spinbutton, 3, 4, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_step_spinbutton), GTK_UPDATE_IF_VALID); + + vshift_step_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + vshift_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_step_spinbutton_adj), 1, 2); + gtk_widget_show (vshift_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vshift_step_spinbutton, 3, 4, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_step_spinbutton), GTK_UPDATE_IF_VALID); + + hscale_step_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + hscale_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_step_spinbutton_adj), 1, 4); + gtk_widget_show (hscale_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hscale_step_spinbutton, 3, 4, 6, 7, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_step_spinbutton), GTK_UPDATE_IF_VALID); + + vscale_step_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + vscale_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_step_spinbutton_adj), 1, 4); + gtk_widget_show (vscale_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vscale_step_spinbutton, 3, 4, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_step_spinbutton), GTK_UPDATE_IF_VALID); + + rotate_step_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); + rotate_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_step_spinbutton_adj), 1, 2); + gtk_widget_show (rotate_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), rotate_step_spinbutton, 3, 4, 10, 11, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_step_spinbutton), GTK_UPDATE_IF_VALID); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 2, 3, 12, 13, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 12, 13, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + viewport7 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport7); + gtk_box_pack_start (GTK_BOX (vbox7), viewport7, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport7), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport7), GTK_SHADOW_ETCHED_IN); + + table4 = gtk_table_new (4, 7, FALSE); + gtk_widget_show (table4); + gtk_container_add (GTK_CONTAINER (viewport7), table4); + + viewport5 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport5); + gtk_table_attach (GTK_TABLE (table4), viewport5, 1, 7, 0, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport5), 6); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport5), GTK_SHADOW_ETCHED_OUT); + + table5 = gtk_table_new (2, 3, FALSE); + gtk_widget_show (table5); + gtk_container_add (GTK_CONTAINER (viewport5), table5); + gtk_container_set_border_width (GTK_CONTAINER (table5), 5); + gtk_table_set_col_spacings (GTK_TABLE (table5), 2); + + label = gtk_label_new ("Height"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table5), label, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); + + label = gtk_label_new ("Width"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table5), label, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); + + fit_width_spinbutton_adj = gtk_adjustment_new (1, 1, 32, 1, 10, 10); + fit_width_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (fit_width_spinbutton_adj), 1, 0); + gtk_widget_show (fit_width_spinbutton); + gtk_table_attach (GTK_TABLE (table5), fit_width_spinbutton, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (fit_width_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (fit_width_spinbutton), GTK_UPDATE_IF_VALID); + + fit_height_spinbutton_adj = gtk_adjustment_new (1, 1, 32, 1, 10, 10); + fit_height_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (fit_height_spinbutton_adj), 1, 0); + gtk_widget_show (fit_height_spinbutton); + gtk_table_attach (GTK_TABLE (table5), fit_height_spinbutton, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 3, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (fit_height_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (fit_height_spinbutton), GTK_UPDATE_IF_VALID); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table5), eventbox, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table5), eventbox, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 4, 0); + + fit_button = gtk_button_new_with_mnemonic (" Fit "); + gtk_widget_show (fit_button); + gtk_container_add (GTK_CONTAINER (eventbox), fit_button); + + viewport6 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport6); + gtk_table_attach (GTK_TABLE (table4), viewport6, 0, 1, 0, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport6), 4); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport6), GTK_SHADOW_NONE); + + table7 = gtk_table_new (2, 1, FALSE); + gtk_widget_show (table7); + gtk_container_add (GTK_CONTAINER (viewport6), table7); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table7), eventbox, 0, 1, 0, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + axial_button = gtk_button_new_with_mnemonic ("Axial"); + gtk_widget_show (axial_button); + gtk_container_add (GTK_CONTAINER (eventbox), axial_button); + gtk_widget_set_size_request (axial_button, 56, 29); + gtk_container_set_border_width (GTK_CONTAINER (axial_button), 4); + + viewport10 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport10); + gtk_box_pack_start (GTK_BOX (vbox7), viewport10, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport10), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport10), GTK_SHADOW_ETCHED_IN); + + hbuttonbox1 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox1); + gtk_container_add (GTK_CONTAINER (viewport10), hbuttonbox1); + gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox1), 4); + gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_SPREAD); + + done_button = gtk_button_new (); + gtk_widget_show (done_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), done_button); + GTK_WIDGET_SET_FLAGS (done_button, GTK_CAN_DEFAULT); + + alignment1 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment1); + gtk_container_add (GTK_CONTAINER (done_button), alignment1); + + hbox2 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox2); + gtk_container_add (GTK_CONTAINER (alignment1), hbox2); + + image1 = gtk_image_new_from_stock ("gtk-yes", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image1); + gtk_box_pack_start (GTK_BOX (hbox2), image1, FALSE, FALSE, 0); + + label = gtk_label_new_with_mnemonic ("Done"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + apply_button = gtk_button_new (); + gtk_widget_show (apply_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), apply_button); + GTK_WIDGET_SET_FLAGS (apply_button, GTK_CAN_DEFAULT); + + alignment3 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment3); + gtk_container_add (GTK_CONTAINER (apply_button), alignment3); + + hbox4 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox4); + gtk_container_add (GTK_CONTAINER (alignment3), hbox4); + + image3 = gtk_image_new_from_stock ("gtk-apply", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image3); + gtk_box_pack_start (GTK_BOX (hbox4), image3, FALSE, FALSE, 0); + + label = gtk_label_new_with_mnemonic ("Apply"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox4), label, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + cancel_button = gtk_button_new (); + gtk_widget_show (cancel_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), cancel_button); + GTK_WIDGET_SET_FLAGS (cancel_button, GTK_CAN_DEFAULT); + + alignment2 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment2); + gtk_container_add (GTK_CONTAINER (cancel_button), alignment2); + + hbox3 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox3); + gtk_container_add (GTK_CONTAINER (alignment2), hbox3); + + image2 = gtk_image_new_from_stock ("gtk-no", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image2); + gtk_box_pack_start (GTK_BOX (hbox3), image2, FALSE, FALSE, 0); + + label = gtk_label_new_with_mnemonic ("Cancel"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox3), label, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + + g_signal_connect ( (gpointer) SurfaceInspector, + "delete_event", + G_CALLBACK (delete_event_callback), + NULL ); + g_signal_connect ((gpointer) SurfaceInspector, "destroy", + G_CALLBACK (gtk_widget_destroy), + NULL); + + g_signal_connect ((gpointer) texture_combo_entry, "key_press_event", + G_CALLBACK (on_texture_combo_entry_key_press_event), + NULL); + g_signal_connect ((gpointer) texture_combo_entry, "activate", + G_CALLBACK (on_texture_combo_entry_activate), + NULL); + + + g_signal_connect ((gpointer) hshift_offset_spinbutton, "value_changed", + G_CALLBACK (on_hshift_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vshift_offset_spinbutton, "value_changed", + G_CALLBACK (on_vshift_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) hscale_offset_spinbutton, "value_changed", + G_CALLBACK (on_hscale_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vscale_offset_spinbutton, "value_changed", + G_CALLBACK (on_vscale_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) rotate_offset_spinbutton, "value_changed", + G_CALLBACK (on_rotate_offset_spinbutton_value_changed), + NULL); + + g_signal_connect ((gpointer) hshift_value_spinbutton, "value_changed", + G_CALLBACK (on_hshift_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vshift_value_spinbutton, "value_changed", + G_CALLBACK (on_vshift_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) hscale_value_spinbutton, "value_changed", + G_CALLBACK (on_hscale_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vscale_value_spinbutton, "value_changed", + G_CALLBACK (on_vscale_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) rotate_value_spinbutton, "value_changed", + G_CALLBACK (on_rotate_value_spinbutton_value_changed), + NULL); + + g_signal_connect ((gpointer) hshift_step_spinbutton, "value_changed", + G_CALLBACK (on_hshift_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vshift_step_spinbutton, "value_changed", + G_CALLBACK (on_vshift_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) hscale_step_spinbutton, "value_changed", + G_CALLBACK (on_hscale_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vscale_step_spinbutton, "value_changed", + G_CALLBACK (on_vscale_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) rotate_step_spinbutton, "value_changed", + G_CALLBACK (on_rotate_step_spinbutton_value_changed), + NULL); + + g_signal_connect ((gpointer) match_grid_button, "clicked", + G_CALLBACK (on_match_grid_button_clicked), + NULL); + g_signal_connect ((gpointer) lock_valuechange_togglebutton, "toggled", + G_CALLBACK (on_lock_valuechange_togglebutton_toggled), + NULL); + + g_signal_connect ((gpointer) fit_width_spinbutton, "value_changed", + G_CALLBACK (on_fit_width_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) fit_height_spinbutton, "value_changed", + G_CALLBACK (on_fit_height_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) fit_button, "clicked", + G_CALLBACK (on_fit_button_clicked), + NULL); + + g_signal_connect ((gpointer) axial_button, "clicked", + G_CALLBACK (on_axial_button_clicked), + NULL); + + g_signal_connect ((gpointer) done_button, "clicked", + G_CALLBACK (on_done_button_clicked), + NULL); + g_signal_connect ((gpointer) apply_button, "clicked", + G_CALLBACK (on_apply_button_clicked), + NULL); + g_signal_connect ((gpointer) cancel_button, "clicked", + G_CALLBACK (on_cancel_button_clicked), + NULL); + + + return SurfaceInspector; +} + + +// Texture Combo +gboolean on_texture_combo_entry_key_press_event (GtkWidget *widget, GdkEventKey *event, + gpointer user_data) +{ + // Have Tab activate selection as well as Return + if (event->keyval == GDK_Tab) + g_signal_emit_by_name ( texture_combo_entry, "activate" ); + + return FALSE; +} + +void on_texture_combo_entry_activate (GtkEntry *entry, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + char text[128] = { 0 }; + + if (!texdef_face_list_empty() && g_bListenChanged) + { + // activate only on entry change + strcpy( text, gtk_entry_get_text(entry)); + if ( strcmp( old_texture_entry, text )) + { + // Check for spaces in shader name + if (text[0] <= ' ' || strchr(text, ' ')) + Sys_FPrintf(SYS_WRN, "WARNING: spaces in shader names are not allowed, ignoring '%s'\n", text); + else + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + strcpy( old_texture_entry, text ); + tmp_texdef->SetName( text ); + } + GetTexMods(); + } + } + } +} + +// Offset Spins +static void on_hshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.shift[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_HShift_conflicting) + tmp_texdef->shift[0] = tmp_orig_texdef->shift[0] + texdef_offset.shift[0]; + else + tmp_texdef->shift[0] = texdef_SI_values.shift[0] + texdef_offset.shift[0]; + } + GetTexMods(); + } +} + +static void on_vshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.shift[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_VShift_conflicting) + tmp_texdef->shift[1] = tmp_orig_texdef->shift[1] + texdef_offset.shift[1]; + else + tmp_texdef->shift[1] = texdef_SI_values.shift[1] + texdef_offset.shift[1]; + } + GetTexMods(); + } + +} + +static void on_hscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.scale[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_HScale_conflicting) + tmp_texdef->scale[0] = tmp_orig_texdef->scale[0] + texdef_offset.scale[0]; + else + tmp_texdef->scale[0] = texdef_SI_values.scale[0] + texdef_offset.scale[0]; + } + GetTexMods(); + } + + +} + +static void on_vscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.scale[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_VScale_conflicting) + tmp_texdef->scale[1] = tmp_orig_texdef->scale[1] + texdef_offset.scale[1]; + else + tmp_texdef->scale[1] = texdef_SI_values.scale[1] + texdef_offset.scale[1]; + } + GetTexMods(); + } + +} + +static void on_rotate_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.rotate = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_Rotate_conflicting) + tmp_texdef->rotate = tmp_orig_texdef->rotate + texdef_offset.rotate; + else + tmp_texdef->rotate = texdef_SI_values.rotate + texdef_offset.rotate; + } + GetTexMods(); + } + +} + + +// Match Grid +static void on_match_grid_button_clicked (GtkButton *button, gpointer user_data) +{ + float hscale, vscale; + + if( !strcmp(gtk_entry_get_text (GTK_ENTRY (hscale_value_spinbutton)), "") ) + hscale = 0.0; + else + hscale = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_value_spinbutton) ); + + if( !strcmp( gtk_entry_get_text (GTK_ENTRY (vscale_value_spinbutton)), "") ) + vscale = 0.0; + else + vscale = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_value_spinbutton) ); + DoSnapTToGrid (hscale, vscale); +} + + +// Lock out changes to Value +static void on_lock_valuechange_togglebutton_toggled (GtkToggleButton *togglebutton, gpointer user_data) +{ + bool is_Locked; + + is_Locked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lock_valuechange_togglebutton)); + + gtk_widget_set_sensitive( GTK_WIDGET( hscale_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( vscale_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( hshift_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( vshift_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( rotate_value_spinbutton ), is_Locked ); +} + + +// Value Spins +static void on_hshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.shift[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->shift[0] = texdef_SI_values.shift[0] + texdef_offset.shift[0]; + is_HShift_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_vshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.shift[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->shift[1] = texdef_SI_values.shift[1] + texdef_offset.shift[1]; + is_VShift_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_hscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.scale[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->scale[0] = texdef_SI_values.scale[0] + texdef_offset.scale[0]; + is_HScale_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_vscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.scale[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->scale[1] = texdef_SI_values.scale[1] + texdef_offset.scale[1]; + is_VScale_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_rotate_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.rotate = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->rotate = texdef_SI_values.rotate + texdef_offset.rotate; + is_Rotate_conflicting = FALSE; + } + GetTexMods(); + } +} + + +// Step Spins +static void on_hshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hshift_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hshift_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->shift[0] = val; +} + +static void on_vshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged VShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vshift_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vshift_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->shift[1] = val; +} + +static void on_hscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hscale_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hscale_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->scale[0] = val; +} + +static void on_vscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vscale_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vscale_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->scale[1] = val; +} + +static void on_rotate_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( rotate_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( rotate_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->rotate = val; +} + + +// Fit Texture +static void on_fit_width_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + m_nWidth = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(fit_width_spinbutton) ); +} + +static void on_fit_height_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + m_nHeight = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(fit_height_spinbutton) ); +} + +static void on_fit_button_clicked (GtkButton *button, gpointer user_data) +{ + FaceList_FitTexture(get_texdef_face_list(), m_nHeight, m_nWidth); + Sys_UpdateWindows(W_ALL); +} + + +// Axial Button +static void on_axial_button_clicked (GtkButton *button, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_texdef->shift[0] = 0.0; + tmp_texdef->shift[1] = 0.0; + tmp_texdef->scale[0] = 0.5; + tmp_texdef->scale[1] = 0.5; + tmp_texdef->rotate = 0.0; + } + } + + SetTexdef_FaceList( get_texdef_face_list(), FALSE, TRUE ); + Sys_UpdateWindows(W_ALL); +} + + +// Action Buttons +static void on_done_button_clicked (GtkButton *button, gpointer user_data) +{ + if ( !texdef_face_list_empty() ) + GetTexMods(TRUE); + HideDlg(); + Sys_UpdateWindows(W_ALL); +} + +static void on_apply_button_clicked (GtkButton *button, gpointer user_data) +{ + if (!g_bListenChanged) + return; + if ( !texdef_face_list_empty() ) + { + GetTexMods (TRUE); + Sys_UpdateWindows(W_CAMERA); + GetTexdefInfo_from_Radiant(); + SetTexMods(); + } +} + +static void on_cancel_button_clicked (GtkButton *button, gpointer user_data) +{ + texturewin = Texturewin (); + texturewin->texdef = g_old_texdef; + // cancel the last do if we own it + if ( (m_nUndoId == Undo_GetUndoId()) && ( m_nUndoId != 0 )) + { +#ifdef DBG_SI + Sys_Printf("OnCancel calling Undo_Undo\n"); +#endif + g_bListenUpdate = false; + Undo_Undo(TRUE); + g_bListenUpdate = true; + m_nUndoId = 0; + } + HideDlg(); +} + + diff --git a/plugins/surface/surfdlg_plugin.cpp b/plugins/surface/surfdlg_plugin.cpp index b825377f..022f34d2 100644 --- a/plugins/surface/surfdlg_plugin.cpp +++ b/plugins/surface/surfdlg_plugin.cpp @@ -1,127 +1,127 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include -#include "surfdlg_plugin.h" -#include "surfacedialog.h" - -#include "synapse.h" - -class CSynapseClient_SurfDLG : public CSynapseClient -{ -public: - // CSynapseClient API - bool RequestAPI(APIDescriptor_t *pAPI); - const char* GetInfo(); - const char* GetName(); - bool OnActivate(); - - CSynapseClient_SurfDLG() { } - virtual ~CSynapseClient_SurfDLG() { } -}; - -// ============================================================================= -// SYNAPSE - -_QERFuncTable_1 g_FuncTable; -_QERUndoTable g_UndoTable; -_QERAppSurfaceTable g_AppSurfaceTable; -_QERSelectedFaceTable g_SelectedFaceTable; -_QERShadersTable g_ShadersTable; -_QERAppShadersTable g_AppShadersTable; -_QERAppDataTable g_AppDataTable; - -CSynapseServer* g_pSynapseServer = NULL; -CSynapseClient_SurfDLG 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(SURFACEDIALOG_MAJOR, "quake3", sizeof(_QERPlugSurfaceTable)); - g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); - g_SynapseClient.AddAPI(UNDO_MAJOR, NULL, sizeof(_QERUndoTable), SYN_REQUIRE, &g_UndoTable); - g_SynapseClient.AddAPI(APPSURFACEDIALOG_MAJOR, NULL, sizeof(_QERAppSurfaceTable), SYN_REQUIRE, &g_AppSurfaceTable); - g_SynapseClient.AddAPI(SELECTEDFACE_MAJOR, NULL, sizeof(_QERSelectedFaceTable), SYN_REQUIRE, &g_SelectedFaceTable); - g_SynapseClient.AddAPI(SHADERS_MAJOR, "*", sizeof(_QERShadersTable), SYN_REQUIRE, &g_ShadersTable); - g_SynapseClient.AddAPI(APPSHADERS_MAJOR, NULL, sizeof(_QERAppShadersTable), SYN_REQUIRE, &g_AppShadersTable); - g_SynapseClient.AddAPI(DATA_MAJOR, NULL, sizeof(_QERAppDataTable), SYN_REQUIRE, &g_AppDataTable); - - return &g_SynapseClient; -} - -bool CSynapseClient_SurfDLG::RequestAPI(APIDescriptor_t *pAPI) -{ - if (!strcmp(pAPI->major_name, SURFACEDIALOG_MAJOR)) - { - _QERPlugSurfaceTable* pSurfDialogTable= static_cast<_QERPlugSurfaceTable*>(pAPI->mpTable); - if (!strcmp(pAPI->minor_name, "quake3")) - { - pSurfDialogTable->m_pfnToggleSurface = &ToggleSurface; - pSurfDialogTable->m_pfnDoSurface = &DoSurface; - pSurfDialogTable->m_pfnUpdateSurfaceDialog = &UpdateSurfaceDialog; - pSurfDialogTable->m_pfnSurfaceDlgFitAll = &SurfaceDlgFitAll; - pSurfDialogTable->m_pfnGet_SI_Module_Widget = &Get_SI_Module_Widget; - return true; - } - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -#include "version.h" - -const char* CSynapseClient_SurfDLG::GetInfo() -{ - return "Surface Dialog (Quake 3) module built " __DATE__ " " RADIANT_VERSION; -} - -const char* CSynapseClient_SurfDLG::GetName() -{ - return "surface"; -} - -bool CSynapseClient_SurfDLG::OnActivate() -{ - return true; -} +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include "surfdlg_plugin.h" +#include "surfacedialog.h" + +#include "synapse.h" + +class CSynapseClient_SurfDLG : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + const char* GetName(); + bool OnActivate(); + + CSynapseClient_SurfDLG() { } + virtual ~CSynapseClient_SurfDLG() { } +}; + +// ============================================================================= +// SYNAPSE + +_QERFuncTable_1 g_FuncTable; +_QERUndoTable g_UndoTable; +_QERAppSurfaceTable g_AppSurfaceTable; +_QERSelectedFaceTable g_SelectedFaceTable; +_QERShadersTable g_ShadersTable; +_QERAppShadersTable g_AppShadersTable; +_QERAppDataTable g_AppDataTable; + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClient_SurfDLG 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(SURFACEDIALOG_MAJOR, "quake3", sizeof(_QERPlugSurfaceTable)); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(UNDO_MAJOR, NULL, sizeof(_QERUndoTable), SYN_REQUIRE, &g_UndoTable); + g_SynapseClient.AddAPI(APPSURFACEDIALOG_MAJOR, NULL, sizeof(_QERAppSurfaceTable), SYN_REQUIRE, &g_AppSurfaceTable); + g_SynapseClient.AddAPI(SELECTEDFACE_MAJOR, NULL, sizeof(_QERSelectedFaceTable), SYN_REQUIRE, &g_SelectedFaceTable); + g_SynapseClient.AddAPI(SHADERS_MAJOR, "*", sizeof(_QERShadersTable), SYN_REQUIRE, &g_ShadersTable); + g_SynapseClient.AddAPI(APPSHADERS_MAJOR, NULL, sizeof(_QERAppShadersTable), SYN_REQUIRE, &g_AppShadersTable); + g_SynapseClient.AddAPI(DATA_MAJOR, NULL, sizeof(_QERAppDataTable), SYN_REQUIRE, &g_AppDataTable); + + return &g_SynapseClient; +} + +bool CSynapseClient_SurfDLG::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, SURFACEDIALOG_MAJOR)) + { + _QERPlugSurfaceTable* pSurfDialogTable= static_cast<_QERPlugSurfaceTable*>(pAPI->mpTable); + if (!strcmp(pAPI->minor_name, "quake3")) + { + pSurfDialogTable->m_pfnToggleSurface = &ToggleSurface; + pSurfDialogTable->m_pfnDoSurface = &DoSurface; + pSurfDialogTable->m_pfnUpdateSurfaceDialog = &UpdateSurfaceDialog; + pSurfDialogTable->m_pfnSurfaceDlgFitAll = &SurfaceDlgFitAll; + pSurfDialogTable->m_pfnGet_SI_Module_Widget = &Get_SI_Module_Widget; + return true; + } + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClient_SurfDLG::GetInfo() +{ + return "Surface Dialog (Quake 3) module built " __DATE__ " " RADIANT_VERSION; +} + +const char* CSynapseClient_SurfDLG::GetName() +{ + return "surface"; +} + +bool CSynapseClient_SurfDLG::OnActivate() +{ + return true; +} diff --git a/plugins/surface_heretic2/surfacedialog.cpp b/plugins/surface_heretic2/surfacedialog.cpp index bd614564..ed627899 100644 --- a/plugins/surface_heretic2/surfacedialog.cpp +++ b/plugins/surface_heretic2/surfacedialog.cpp @@ -1,1940 +1,1940 @@ -/* -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 -*/ - -// -// Surface Dialog Module -// - -// -// Nurail: Implemented to Module from the main Radiant Surface Dialog code -// - - -#include -#include - -#include "surfdlg_plugin.h" - - - -#ifdef _DEBUG -//#define DBG_SI 1 -#endif - -#include "gtkr_vector.h" - -std::vector g_texdef_face_vector; - -inline texdef_to_face_t* get_texdef_face_list() -{ - return &(*g_texdef_face_vector.begin()); -} - -inline unsigned int texdef_face_list_empty() -{ - return g_texdef_face_vector.empty(); -} - -inline unsigned int texdef_face_list_size() -{ - return g_texdef_face_vector.size(); -} - -// For different faces having different values -bool is_HShift_conflicting; -bool is_VShift_conflicting; -bool is_HScale_conflicting; -bool is_VScale_conflicting; -bool is_Rotate_conflicting; -bool is_TextureName_conflicting; - -void ShowDlg(); -void HideDlg(); -void SetTexMods(); -void GetTexMods(bool b_SetUndoPoint = FALSE); -void BuildDialog(); -void FitAll(); -void InitDefaultIncrement(texdef_t *); -void DoSnapTToGrid(float hscale, float vscale); -// called to perform a fitting from the outside (shortcut key) -void SurfaceDialogFitAll(); - -// Heretic2 Flags Functions -void SetFlagButtons_Heretic2(texdef_to_face_t *texdef_face_list, bool b_isListEmpty); -void SetChangeInFlags_Face_Heretic2 (texdef_to_face_t *texdef_face_list); -GtkWidget* Create_Heretic2FlagsDialog (GtkWidget* surfacedialog_widget); - - -// Dialog Data -int m_nHeight; -int m_nWidth; - -// 0 is invalid, otherwise it's the Id of the last 'do' we are responsible for -int m_nUndoId; - - -texturewin_t *texturewin; -texdef_t *l_pIncrement; -texdef_t texdef_offset; -texdef_t texdef_SI_values; - -// For Texture Entry, activate only on entry change -char old_texture_entry[128]; - -// the texdef to switch back to when the OnCancel is called -texdef_t g_old_texdef; - -// when TRUE, this thing means the surface inspector is currently being displayed -bool g_surfwin = FALSE; -// turn on/off processing of the "changed" "value_changed" messages -// (need to turn off when we are feeding data in) -bool g_bListenChanged = true; -// turn on/off listening of the update messages -bool g_bListenUpdate = true; - -GtkWidget* create_SurfaceInspector (void); -GtkWidget *SurfaceInspector = NULL; - -GtkWidget *m_pWidget; -GtkWidget *GetWidget () { return SurfaceInspector; } -GtkWidget *Get_SI_Module_Widget () { return SurfaceInspector; } -void SetWidget(GtkWidget *new_widget) { m_pWidget = new_widget; } -GtkWidget *GetDlgWidget (const char* name) - { return GTK_WIDGET (g_object_get_data (G_OBJECT (SurfaceInspector), name)); } - -// Spins for FitTexture -GtkWidget *spin_width; -GtkWidget *spin_height; - - -GtkWidget *texture_combo; -GtkWidget *texture_combo_entry; - -GtkWidget *match_grid_button; -GtkWidget *lock_valuechange_togglebutton; - -GtkObject *hshift_value_spinbutton_adj; -GtkWidget *hshift_value_spinbutton; -GtkObject *vshift_value_spinbutton_adj; -GtkWidget *vshift_value_spinbutton; -GtkObject *hscale_value_spinbutton_adj; -GtkWidget *hscale_value_spinbutton; -GtkObject *vscale_value_spinbutton_adj; -GtkWidget *vscale_value_spinbutton; -GtkObject *rotate_value_spinbutton_adj; -GtkWidget *rotate_value_spinbutton; - -GtkObject *hshift_offset_spinbutton_adj; -GtkWidget *hshift_offset_spinbutton; -GtkObject *vshift_offset_spinbutton_adj; -GtkWidget *vshift_offset_spinbutton; -GtkObject *hscale_offset_spinbutton_adj; -GtkWidget *hscale_offset_spinbutton; -GtkObject *vscale_offset_spinbutton_adj; -GtkWidget *vscale_offset_spinbutton; -GtkObject *rotate_offset_spinbutton_adj; -GtkWidget *rotate_offset_spinbutton; - -GtkObject *hshift_step_spinbutton_adj; -GtkWidget *hshift_step_spinbutton; -GtkObject *vshift_step_spinbutton_adj; -GtkWidget *vshift_step_spinbutton; -GtkObject *hscale_step_spinbutton_adj; -GtkWidget *hscale_step_spinbutton; -GtkObject *vscale_step_spinbutton_adj; -GtkWidget *vscale_step_spinbutton; -GtkObject *rotate_step_spinbutton_adj; -GtkWidget *rotate_step_spinbutton; - -GtkObject *fit_width_spinbutton_adj; -GtkWidget *fit_width_spinbutton; -GtkObject *fit_height_spinbutton_adj; -GtkWidget *fit_height_spinbutton; -GtkWidget *fit_button; -GtkWidget *axial_button; - -GtkWidget *done_button; -GtkWidget *apply_button; -GtkWidget *cancel_button; - -// Callbacks -gboolean on_texture_combo_entry_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data); -void on_texture_combo_entry_activate (GtkEntry *entry, gpointer user_data); - -static void on_match_grid_button_clicked (GtkButton *button, gpointer user_data); -static void on_lock_valuechange_togglebutton_toggled (GtkToggleButton *togglebutton, gpointer user_data); - -static void on_hshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_vshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_hscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_vscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_rotate_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); - -static void on_hshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_vshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_hscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_vscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_rotate_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); - -static void on_hshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_vshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_hscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_vscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_rotate_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); - -static void on_fit_width_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_fit_height_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_fit_button_clicked (GtkButton *button, gpointer user_data); -static void on_axial_button_clicked (GtkButton *button, gpointer user_data); - -static void on_done_button_clicked (GtkButton *button, gpointer user_data); -static void on_apply_button_clicked (GtkButton *button, gpointer user_data); -static void on_cancel_button_clicked (GtkButton *button, gpointer user_data); - - -/* -=================================================== - - SURFACE INSPECTOR - -=================================================== -*/ - - -void IsFaceConflicting() -{ - texdef_t* tmp_texdef; - texdef_to_face_t* temp_texdef_face_list; - char buf[12]; - char texture_name[128]; - - if (texdef_face_list_empty()) - { - gtk_entry_set_text( GTK_ENTRY (hshift_value_spinbutton), ""); - gtk_entry_set_text( GTK_ENTRY (vshift_value_spinbutton), ""); - gtk_entry_set_text( GTK_ENTRY (hscale_value_spinbutton), ""); - gtk_entry_set_text( GTK_ENTRY (vscale_value_spinbutton), ""); - gtk_entry_set_text( GTK_ENTRY (rotate_value_spinbutton), ""); - gtk_entry_set_text( GTK_ENTRY (texture_combo_entry), ""); - return; - } - - g_bListenChanged = FALSE; - - tmp_texdef = &get_texdef_face_list()->texdef; - - strcpy(texture_name, tmp_texdef->GetName() ); - - texdef_SI_values.shift[0] = tmp_texdef->shift[0]; - texdef_SI_values.shift[1] = tmp_texdef->shift[1]; - texdef_SI_values.scale[0] = tmp_texdef->scale[0]; - texdef_SI_values.scale[1] = tmp_texdef->scale[1]; - texdef_SI_values.rotate = tmp_texdef->rotate; - texdef_SI_values.SetName( texture_name ); - - is_HShift_conflicting = FALSE; - is_VShift_conflicting = FALSE; - is_HScale_conflicting = FALSE; - is_VScale_conflicting = FALSE; - is_Rotate_conflicting = FALSE; - is_TextureName_conflicting = FALSE; - - if (texdef_face_list_size() > 1) - { - temp_texdef_face_list = get_texdef_face_list()->next; - - for (temp_texdef_face_list; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = &temp_texdef_face_list->texdef; - if ( texdef_SI_values.shift[0] != tmp_texdef->shift[0] ) - is_HShift_conflicting = TRUE; - - if ( texdef_SI_values.shift[1] != tmp_texdef->shift[1] ) - is_VShift_conflicting = TRUE; - - if ( texdef_SI_values.scale[0] != tmp_texdef->scale[0] ) - is_HScale_conflicting = TRUE; - - if ( texdef_SI_values.scale[1] != tmp_texdef->scale[1] ) - is_VScale_conflicting = TRUE; - - if ( texdef_SI_values.rotate != tmp_texdef->rotate ) - is_Rotate_conflicting = TRUE; - - if ( strcmp( texture_name, tmp_texdef->GetName() ) ) - is_TextureName_conflicting = TRUE; - } - } - - if(is_HShift_conflicting) - gtk_entry_set_text( GTK_ENTRY (hshift_value_spinbutton), ""); - else - gtk_spin_button_set_value( GTK_SPIN_BUTTON(hshift_value_spinbutton) , texdef_SI_values.shift[0] ); - - if(is_VShift_conflicting) - gtk_entry_set_text( GTK_ENTRY (vshift_value_spinbutton), ""); - else - gtk_spin_button_set_value( GTK_SPIN_BUTTON(vshift_value_spinbutton) , texdef_SI_values.shift[1] ); - - if(is_HScale_conflicting) - gtk_entry_set_text( GTK_ENTRY (hscale_value_spinbutton), ""); - else - gtk_spin_button_set_value( GTK_SPIN_BUTTON(hscale_value_spinbutton) , texdef_SI_values.scale[0] ); - - if(is_VScale_conflicting) - gtk_entry_set_text( GTK_ENTRY (vscale_value_spinbutton), ""); - else - gtk_spin_button_set_value( GTK_SPIN_BUTTON(vscale_value_spinbutton) , texdef_SI_values.scale[1] ); - - if(is_Rotate_conflicting) - gtk_entry_set_text( GTK_ENTRY (rotate_value_spinbutton), ""); - else - gtk_spin_button_set_value( GTK_SPIN_BUTTON(rotate_value_spinbutton) , texdef_SI_values.rotate ); - - g_bListenChanged = TRUE; -} - -#define MAX_NUM_LIST_ITEMS 15 -static void PopulateTextureComboList() -{ - texdef_t* tmp_texdef; - texdef_to_face_t* temp_texdef_face_list; - char blank[1]; - GList *items = NULL; - GList *tmp_item; - int num_of_list_items = 0; - - blank[0] = 0; - - if (texdef_face_list_empty()) - { - items = g_list_append (items, (gpointer) blank); - // For Texture Entry, activate only on entry change - strcpy (old_texture_entry, blank); - } - else if ( !is_TextureName_conflicting ) - { - temp_texdef_face_list = get_texdef_face_list(); - tmp_texdef = (texdef_t *) &get_texdef_face_list()->texdef; - items = g_list_append( items, (gpointer) tmp_texdef->GetName() ); - // For Texture Entry, activate only on entry change - strcpy (old_texture_entry, tmp_texdef->GetName()); - } - else - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - // Need to do a string compare, hence the custom search - if (!( g_list_find_custom (items, tmp_texdef->GetName(), (GCompareFunc) strcmp ) )) - { - items = g_list_append( items, (gpointer) tmp_texdef->GetName() ); - num_of_list_items++; - } - // Make sure the combo list isn't too long - if (num_of_list_items >= MAX_NUM_LIST_ITEMS) - break; - } - // If this isn't added last (to the top of the list), g_list_find freaks. - items = g_list_prepend (items, (gpointer) blank); - // For Texture Entry, activate only on entry change - strcpy (old_texture_entry, blank); - } - - gtk_combo_set_popdown_strings (GTK_COMBO (texture_combo), items); - g_list_free(items); - -} - -static void ZeroOffsetValues() -{ - texdef_offset.shift[0] = 0.0; - texdef_offset.shift[1] = 0.0; - texdef_offset.scale[0] = 0.0; - texdef_offset.scale[1] = 0.0; - texdef_offset.rotate = 0.0; -} - -static void GetTexdefInfo_from_Radiant() -{ - g_texdef_face_vector.clear(); - - unsigned int count = GetSelectedFaceCountfromBrushes(); - if(count == 0) - count = GetSelectedFaceCount(); - - g_texdef_face_vector.resize(count); - - if (!texdef_face_list_empty()) - { - texdef_to_face_t* p = get_texdef_face_list(); - GetSelFacesTexdef( get_texdef_face_list() ); - } - - IsFaceConflicting(); - PopulateTextureComboList(); - ZeroOffsetValues(); - if ( texdef_face_list_empty() ) - SetFlagButtons_Heretic2( get_texdef_face_list() , TRUE); - else - SetFlagButtons_Heretic2( get_texdef_face_list() , FALSE); - -} - -static gint delete_event_callback(GtkWidget *widget, GdkEvent* event, gpointer data) -{ - HideDlg(); - return TRUE; -} - -// make the shift increments match the grid settings -// the objective being that the shift+arrows shortcuts move the texture by the corresponding grid size -// this depends on a scale value if you have selected a particular texture on which you want it to work: -// we move the textures in pixels, not world units. (i.e. increment values are in pixel) -// depending on the texture scale it doesn't take the same amount of pixels to move of g_qeglobals.d_gridsize -// increment * scale = gridsize -// hscale and vscale are optional parameters, if they are zero they will be set to the default scale -// NOTE: the default scale depends if you are using BP mode or regular. -// For regular it's 0.5f (128 pixels cover 64 world units), for BP it's simply 1.0f -// see fenris #2810 -void DoSnapTToGrid(float hscale, float vscale) -{ - l_pIncrement = Get_SI_Inc(); - - if (hscale == 0.0f) - { - hscale = 0.5f; - } - if (vscale == 0.0f) - { - vscale = 0.5f; - } -#ifdef _DEBUG - Sys_Printf ("DoSnapTToGrid: hscale %g vscale %g\n", hscale, vscale); -#endif - l_pIncrement->shift[0] = GridSize() / hscale; - l_pIncrement->shift[1] = GridSize() / vscale; - // now some update work - // FIXME: doesn't look good here, seems to be called several times - SetTexMods(); -} - -void UpdateSurfaceDialog() -{ - if (!g_bListenUpdate) - return; - - if (!SurfaceInspector) - return; - - // avoid long delays on slow computers - while (gtk_events_pending ()) - gtk_main_iteration (); - - if (g_surfwin) - { -#ifdef DBG_SI - Sys_Printf("UpdateSurfaceDialog\n"); -#endif - GetTexdefInfo_from_Radiant(); - SetTexMods(); - } - -} - -// DoSurface will always try to show the surface inspector -// or update it because something new has been selected -void DoSurface (void) -{ -#ifdef DBG_SI - Sys_Printf("DoSurface\n"); -#endif - if (!SurfaceInspector) - create_SurfaceInspector (); - - ShowDlg(); - SetTexMods (); -} - -void ToggleSurface() -{ -#ifdef DBG_SI - Sys_Printf("ToggleSurface Module\n"); -#endif - if (!g_surfwin) - DoSurface (); - else - on_cancel_button_clicked(NULL, NULL); -} - -// NOTE: will raise and show the Surface inspector and exec fit for patches and brushes -void SurfaceDlgFitAll() -{ - DoSurface(); - FitAll(); -} - -// ============================================================================= -// SurfaceDialog class - -void ShowDlg() -{ - - if(!SurfaceInspector) - create_SurfaceInspector(); - else - gtk_widget_show (SurfaceInspector); - - GetTexdefInfo_from_Radiant(); - GetTexMods(TRUE); // Set Initial Undo Point - g_surfwin = TRUE; -} - -void HideDlg() -{ - g_surfwin = FALSE; - gtk_widget_hide (SurfaceInspector); -} - - -// set default values for increments (shift scale and rot) -// this is called by the prefs code if can't find the values -void InitDefaultIncrement(texdef_t *tex) -{ - tex->SetName("foo"); - tex->shift[0] = 8; - tex->shift[1] = 8; - tex->scale[0] = 0.25; - tex->scale[1] = 0.25; - tex->rotate = 10; -} - -void BuildDialog () -{ - if ( !SurfaceInspector ) - create_SurfaceInspector(); -} - -/* -============== -SetTexMods - -Set the fields to the current texdef (i.e. map/texdef -> dialog widgets) -=============== -*/ - -void SetTexMods() -{ - texdef_t *pt; - GtkSpinButton *spin; - GtkAdjustment *adjust; - - texturewin = Texturewin (); - l_pIncrement = Get_SI_Inc(); - -#ifdef DBG_SI - Sys_Printf("SurfaceDlg SetTexMods\n"); -#endif - - if (!g_surfwin) - return; - - pt = &texturewin->texdef; - - g_bListenChanged = false; - - if(strncmp(pt->GetName(), "textures/", 9) != 0) - texdef_offset.SetName(SHADER_NOT_FOUND); - - - spin = GTK_SPIN_BUTTON (hshift_offset_spinbutton); - gtk_spin_button_set_value (spin, texdef_offset.shift[0]); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->shift[0]; - gtk_spin_button_set_value (GTK_SPIN_BUTTON(hshift_step_spinbutton), l_pIncrement->shift[0]); - - spin = GTK_SPIN_BUTTON (hshift_value_spinbutton); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->shift[0]; - - - spin = GTK_SPIN_BUTTON (vshift_offset_spinbutton); - gtk_spin_button_set_value (spin, texdef_offset.shift[1]); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->shift[1]; - gtk_spin_button_set_value (GTK_SPIN_BUTTON(vshift_step_spinbutton), l_pIncrement->shift[1]); - - spin = GTK_SPIN_BUTTON (vshift_value_spinbutton); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->shift[1]; - - - spin = GTK_SPIN_BUTTON (hscale_offset_spinbutton); - gtk_spin_button_set_value (spin, texdef_offset.scale[0]); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->scale[0]; - gtk_spin_button_set_value (GTK_SPIN_BUTTON(hscale_step_spinbutton), l_pIncrement->scale[0]); - - spin = GTK_SPIN_BUTTON (hscale_value_spinbutton); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->scale[0]; - - - spin = GTK_SPIN_BUTTON (vscale_offset_spinbutton); - gtk_spin_button_set_value (spin, texdef_offset.scale[1]); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->scale[1]; - gtk_spin_button_set_value (GTK_SPIN_BUTTON(vscale_step_spinbutton), l_pIncrement->scale[1]); - - spin = GTK_SPIN_BUTTON (vscale_value_spinbutton); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->scale[1]; - - - spin = GTK_SPIN_BUTTON (rotate_offset_spinbutton); - gtk_spin_button_set_value (spin, texdef_offset.rotate); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->rotate; - gtk_spin_button_set_value (GTK_SPIN_BUTTON(rotate_step_spinbutton), l_pIncrement->rotate); - - spin = GTK_SPIN_BUTTON (rotate_value_spinbutton); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->rotate; - - - g_bListenChanged = true; - - // store the current texdef as our escape route if user hits OnCancel - g_old_texdef = texturewin->texdef; -} - -/* -============== -GetTexMods - -Shows any changes to the main Radiant windows -=============== -*/ -void GetTexMods(bool b_SetUndoPoint) -{ - -#ifdef DBG_SI - Sys_Printf("SurfaceDlg GetTexMods\n"); -#endif - - if ( !texdef_face_list_empty() ) - { - g_bListenUpdate=FALSE; - SetChangeInFlags_Face_Heretic2 ( get_texdef_face_list() ); - SetTexdef_FaceList( get_texdef_face_list(), b_SetUndoPoint ); - g_bListenUpdate=TRUE; - - if (b_SetUndoPoint) - m_nUndoId = Undo_GetUndoId(); - } -} - -void FitAll() -{ - on_fit_button_clicked(NULL, NULL); -} - - -//////////////////////////////////////////////////////////////////// -// -// GUI Section -// -//////////////////////////////////////////////////////////////////// - -GtkWidget* create_SurfaceInspector (void) -{ - - GtkWidget *label; - GtkWidget *hseparator; - GtkWidget *eventbox; - - GtkWidget *viewport8; - GtkWidget *viewport9; - GtkWidget *viewport2; - GtkWidget *viewport7; - GtkWidget *viewport5; - GtkWidget *viewport6; - GtkWidget *viewport10; - - GtkWidget *table1; - GtkWidget *table4; - GtkWidget *table5; - GtkWidget *table7; - - GtkWidget *alignment1; - GtkWidget *alignment2; - GtkWidget *alignment3; - - GtkWidget *vbox7; - - GtkWidget *hbox1; - GtkWidget *hbox2; - GtkWidget *hbox3; - GtkWidget *hbox4; - - GtkWidget *image1; - GtkWidget *image2; - GtkWidget *image3; - - GtkWidget *hbuttonbox1; - - SurfaceInspector = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_container_set_border_width (GTK_CONTAINER (SurfaceInspector), 4); - gtk_window_set_title (GTK_WINDOW (SurfaceInspector), "Surface Inspector"); - - SetWinPos_from_Prefs(SurfaceInspector); - - viewport8 = gtk_viewport_new (NULL, NULL); - gtk_widget_show (viewport8); - gtk_container_add (GTK_CONTAINER (SurfaceInspector), viewport8); - gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport8), GTK_SHADOW_NONE); - - vbox7 = gtk_vbox_new (FALSE, 0); - gtk_widget_show (vbox7); - gtk_container_add (GTK_CONTAINER (viewport8), vbox7); - - viewport9 = gtk_viewport_new (NULL, NULL); - gtk_widget_show (viewport9); - gtk_box_pack_start (GTK_BOX (vbox7), viewport9, FALSE, FALSE, 0); - gtk_container_set_border_width (GTK_CONTAINER (viewport9), 2); - gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport9), GTK_SHADOW_ETCHED_IN); - - hbox1 = gtk_hbox_new (FALSE, 0); - gtk_widget_show (hbox1); - gtk_container_add (GTK_CONTAINER (viewport9), hbox1); - gtk_container_set_border_width (GTK_CONTAINER (hbox1), 4); - - label = gtk_label_new ("Texture: "); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox1), label, FALSE, FALSE, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - texture_combo = gtk_combo_new (); - g_object_set_data (G_OBJECT (GTK_COMBO (texture_combo)->popwin), - "KeepMeAround", texture_combo); - gtk_combo_disable_activate ( (GtkCombo*) texture_combo); - gtk_widget_show (texture_combo); - gtk_box_pack_start (GTK_BOX (hbox1), texture_combo, TRUE, TRUE, 0); - - texture_combo_entry = GTK_COMBO (texture_combo)->entry; - gtk_widget_show (texture_combo_entry); - gtk_entry_set_max_length (GTK_ENTRY (texture_combo_entry), 128); - - viewport2 = gtk_viewport_new (NULL, NULL); - gtk_widget_show (viewport2); - gtk_box_pack_start (GTK_BOX (vbox7), viewport2, FALSE, TRUE, 0); - gtk_container_set_border_width (GTK_CONTAINER (viewport2), 2); - gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport2), GTK_SHADOW_ETCHED_IN); - - table1 = gtk_table_new (13, 4, FALSE); - gtk_widget_show (table1); - gtk_container_add (GTK_CONTAINER (viewport2), table1); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 3, 4, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 3, 4, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 3, 4, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 5, 6, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 5, 6, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 5, 6, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 7, 8, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 7, 8, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 7, 8, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 9, 10, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 9, 10, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 9, 10, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 11, 12, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 11, 12, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 11, 12, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label = gtk_label_new ("Offset"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table1), label, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - label = gtk_label_new ("Step"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table1), label, 3, 4, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 3, 4, 12, 13, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - match_grid_button = gtk_button_new_with_mnemonic ("Match Grid"); - gtk_widget_show (match_grid_button); - gtk_container_add (GTK_CONTAINER (eventbox), match_grid_button); - - label = gtk_label_new ("Value"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table1), label, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 3, 4, - (GtkAttachOptions) (GTK_SHRINK | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 5, 6, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 7, 8, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 9, 10, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 11, 12, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 4, 5, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label = gtk_label_new ("V Shift: "); - gtk_widget_show (label); - gtk_container_add (GTK_CONTAINER (eventbox), label); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 6, 7, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label = gtk_label_new (" H Scale: "); - gtk_widget_show (label); - gtk_container_add (GTK_CONTAINER (eventbox), label); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 8, 9, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label = gtk_label_new ("V Scale: "); - gtk_widget_show (label); - gtk_container_add (GTK_CONTAINER (eventbox), label); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 10, 11, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label = gtk_label_new ("Rotate: "); - gtk_widget_show (label); - gtk_container_add (GTK_CONTAINER (eventbox), label); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label = gtk_label_new ("H Shift: "); - gtk_widget_show (label); - gtk_container_add (GTK_CONTAINER (eventbox), label); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 1, 2, 12, 13, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - lock_valuechange_togglebutton = gtk_toggle_button_new_with_mnemonic ("UNLOCK"); - gtk_widget_show (lock_valuechange_togglebutton); - gtk_container_add (GTK_CONTAINER (eventbox), lock_valuechange_togglebutton); - - // Value Spins - hshift_value_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); - hshift_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_value_spinbutton_adj), 1, 2); - gtk_widget_show (hshift_value_spinbutton); - gtk_table_attach (GTK_TABLE (table1), hshift_value_spinbutton, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_value_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hshift_value_spinbutton), TRUE); - gtk_widget_set_sensitive( GTK_WIDGET( hshift_value_spinbutton ), FALSE ); - - vshift_value_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); - vshift_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_value_spinbutton_adj), 1, 2); - gtk_widget_show (vshift_value_spinbutton); - gtk_table_attach (GTK_TABLE (table1), vshift_value_spinbutton, 1, 2, 4, 5, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_value_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vshift_value_spinbutton), TRUE); - gtk_widget_set_sensitive( GTK_WIDGET( vshift_value_spinbutton ), FALSE ); - - hscale_value_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); - hscale_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_value_spinbutton_adj), 1, 4); - gtk_widget_show (hscale_value_spinbutton); - gtk_table_attach (GTK_TABLE (table1), hscale_value_spinbutton, 1, 2, 6, 7, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_value_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hscale_value_spinbutton), TRUE); - gtk_widget_set_sensitive( GTK_WIDGET( hscale_value_spinbutton ), FALSE ); - - vscale_value_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); - vscale_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_value_spinbutton_adj), 1, 4); - gtk_widget_show (vscale_value_spinbutton); - gtk_table_attach (GTK_TABLE (table1), vscale_value_spinbutton, 1, 2, 8, 9, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_value_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vscale_value_spinbutton), TRUE); - gtk_widget_set_sensitive( GTK_WIDGET( vscale_value_spinbutton ), FALSE ); - - rotate_value_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); - rotate_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_value_spinbutton_adj), 1, 0); - gtk_widget_show (rotate_value_spinbutton); - gtk_table_attach (GTK_TABLE (table1), rotate_value_spinbutton, 1, 2, 10, 11, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_value_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (rotate_value_spinbutton), TRUE); - gtk_widget_set_sensitive( GTK_WIDGET( rotate_value_spinbutton ), FALSE ); - - // Offset Spins - hshift_offset_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); - hshift_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_offset_spinbutton_adj), 0, 2); - gtk_widget_show (hshift_offset_spinbutton); - gtk_table_attach (GTK_TABLE (table1), hshift_offset_spinbutton, 2, 3, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 4, 0); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (hshift_offset_spinbutton), TRUE); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_offset_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hshift_offset_spinbutton), TRUE); - - vshift_offset_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); - vshift_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_offset_spinbutton_adj), 0, 2); - gtk_widget_show (vshift_offset_spinbutton); - gtk_table_attach (GTK_TABLE (table1), vshift_offset_spinbutton, 2, 3, 4, 5, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 4, 0); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (vshift_offset_spinbutton), TRUE); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_offset_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vshift_offset_spinbutton), TRUE); - - hscale_offset_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); - hscale_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_offset_spinbutton_adj), 0, 4); - gtk_widget_show (hscale_offset_spinbutton); - gtk_table_attach (GTK_TABLE (table1), hscale_offset_spinbutton, 2, 3, 6, 7, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 4, 0); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (hscale_offset_spinbutton), TRUE); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_offset_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hscale_offset_spinbutton), TRUE); - - vscale_offset_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); - vscale_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_offset_spinbutton_adj), 0, 4); - gtk_widget_show (vscale_offset_spinbutton); - gtk_table_attach (GTK_TABLE (table1), vscale_offset_spinbutton, 2, 3, 8, 9, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 4, 0); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (vscale_offset_spinbutton), TRUE); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_offset_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vscale_offset_spinbutton), TRUE); - - rotate_offset_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); - rotate_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_offset_spinbutton_adj), 0, 2); - gtk_widget_show (rotate_offset_spinbutton); - gtk_table_attach (GTK_TABLE (table1), rotate_offset_spinbutton, 2, 3, 10, 11, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 4, 0); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (rotate_offset_spinbutton), TRUE); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_offset_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (rotate_offset_spinbutton), TRUE); - - // Step Spins - hshift_step_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); - hshift_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_step_spinbutton_adj), 1, 2); - gtk_widget_show (hshift_step_spinbutton); - gtk_table_attach (GTK_TABLE (table1), hshift_step_spinbutton, 3, 4, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_step_spinbutton), GTK_UPDATE_IF_VALID); - - vshift_step_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); - vshift_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_step_spinbutton_adj), 1, 2); - gtk_widget_show (vshift_step_spinbutton); - gtk_table_attach (GTK_TABLE (table1), vshift_step_spinbutton, 3, 4, 4, 5, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_step_spinbutton), GTK_UPDATE_IF_VALID); - - hscale_step_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); - hscale_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_step_spinbutton_adj), 1, 4); - gtk_widget_show (hscale_step_spinbutton); - gtk_table_attach (GTK_TABLE (table1), hscale_step_spinbutton, 3, 4, 6, 7, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_step_spinbutton), GTK_UPDATE_IF_VALID); - - vscale_step_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); - vscale_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_step_spinbutton_adj), 1, 4); - gtk_widget_show (vscale_step_spinbutton); - gtk_table_attach (GTK_TABLE (table1), vscale_step_spinbutton, 3, 4, 8, 9, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_step_spinbutton), GTK_UPDATE_IF_VALID); - - rotate_step_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); - rotate_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_step_spinbutton_adj), 1, 2); - gtk_widget_show (rotate_step_spinbutton); - gtk_table_attach (GTK_TABLE (table1), rotate_step_spinbutton, 3, 4, 10, 11, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_step_spinbutton), GTK_UPDATE_IF_VALID); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 2, 3, 12, 13, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 12, 13, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - viewport7 = gtk_viewport_new (NULL, NULL); - gtk_widget_show (viewport7); - gtk_box_pack_start (GTK_BOX (vbox7), viewport7, FALSE, TRUE, 0); - gtk_container_set_border_width (GTK_CONTAINER (viewport7), 2); - gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport7), GTK_SHADOW_ETCHED_IN); - - table4 = gtk_table_new (4, 7, FALSE); - gtk_widget_show (table4); - gtk_container_add (GTK_CONTAINER (viewport7), table4); - - viewport5 = gtk_viewport_new (NULL, NULL); - gtk_widget_show (viewport5); - gtk_table_attach (GTK_TABLE (table4), viewport5, 1, 7, 0, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (viewport5), 6); - gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport5), GTK_SHADOW_ETCHED_OUT); - - table5 = gtk_table_new (2, 3, FALSE); - gtk_widget_show (table5); - gtk_container_add (GTK_CONTAINER (viewport5), table5); - gtk_container_set_border_width (GTK_CONTAINER (table5), 5); - gtk_table_set_col_spacings (GTK_TABLE (table5), 2); - - label = gtk_label_new ("Height"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table5), label, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); - - label = gtk_label_new ("Width"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table5), label, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); - - fit_width_spinbutton_adj = gtk_adjustment_new (1, 1, 32, 1, 10, 10); - fit_width_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (fit_width_spinbutton_adj), 1, 0); - gtk_widget_show (fit_width_spinbutton); - gtk_table_attach (GTK_TABLE (table5), fit_width_spinbutton, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (fit_width_spinbutton), TRUE); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (fit_width_spinbutton), GTK_UPDATE_IF_VALID); - - fit_height_spinbutton_adj = gtk_adjustment_new (1, 1, 32, 1, 10, 10); - fit_height_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (fit_height_spinbutton_adj), 1, 0); - gtk_widget_show (fit_height_spinbutton); - gtk_table_attach (GTK_TABLE (table5), fit_height_spinbutton, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 3, 0); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (fit_height_spinbutton), TRUE); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (fit_height_spinbutton), GTK_UPDATE_IF_VALID); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table5), eventbox, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table5), eventbox, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 4, 0); - - fit_button = gtk_button_new_with_mnemonic (" Fit "); - gtk_widget_show (fit_button); - gtk_container_add (GTK_CONTAINER (eventbox), fit_button); - - viewport6 = gtk_viewport_new (NULL, NULL); - gtk_widget_show (viewport6); - gtk_table_attach (GTK_TABLE (table4), viewport6, 0, 1, 0, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (viewport6), 4); - gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport6), GTK_SHADOW_NONE); - - table7 = gtk_table_new (2, 1, FALSE); - gtk_widget_show (table7); - gtk_container_add (GTK_CONTAINER (viewport6), table7); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table7), eventbox, 0, 1, 0, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - axial_button = gtk_button_new_with_mnemonic ("Axial"); - gtk_widget_show (axial_button); - gtk_container_add (GTK_CONTAINER (eventbox), axial_button); - gtk_widget_set_size_request (axial_button, 56, 29); - gtk_container_set_border_width (GTK_CONTAINER (axial_button), 4); - - // Fit in Flags sub-dialog - Create_Heretic2FlagsDialog(vbox7); - - viewport10 = gtk_viewport_new (NULL, NULL); - gtk_widget_show (viewport10); - gtk_box_pack_start (GTK_BOX (vbox7), viewport10, FALSE, TRUE, 0); - gtk_container_set_border_width (GTK_CONTAINER (viewport10), 2); - gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport10), GTK_SHADOW_ETCHED_IN); - - hbuttonbox1 = gtk_hbutton_box_new (); - gtk_widget_show (hbuttonbox1); - gtk_container_add (GTK_CONTAINER (viewport10), hbuttonbox1); - gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox1), 4); - gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_SPREAD); - - done_button = gtk_button_new (); - gtk_widget_show (done_button); - gtk_container_add (GTK_CONTAINER (hbuttonbox1), done_button); - GTK_WIDGET_SET_FLAGS (done_button, GTK_CAN_DEFAULT); - - alignment1 = gtk_alignment_new (0.5, 0.5, 0, 0); - gtk_widget_show (alignment1); - gtk_container_add (GTK_CONTAINER (done_button), alignment1); - - hbox2 = gtk_hbox_new (FALSE, 2); - gtk_widget_show (hbox2); - gtk_container_add (GTK_CONTAINER (alignment1), hbox2); - - image1 = gtk_image_new_from_stock ("gtk-yes", GTK_ICON_SIZE_BUTTON); - gtk_widget_show (image1); - gtk_box_pack_start (GTK_BOX (hbox2), image1, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic ("Done"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - - apply_button = gtk_button_new (); - gtk_widget_show (apply_button); - gtk_container_add (GTK_CONTAINER (hbuttonbox1), apply_button); - GTK_WIDGET_SET_FLAGS (apply_button, GTK_CAN_DEFAULT); - - alignment3 = gtk_alignment_new (0.5, 0.5, 0, 0); - gtk_widget_show (alignment3); - gtk_container_add (GTK_CONTAINER (apply_button), alignment3); - - hbox4 = gtk_hbox_new (FALSE, 2); - gtk_widget_show (hbox4); - gtk_container_add (GTK_CONTAINER (alignment3), hbox4); - - image3 = gtk_image_new_from_stock ("gtk-apply", GTK_ICON_SIZE_BUTTON); - gtk_widget_show (image3); - gtk_box_pack_start (GTK_BOX (hbox4), image3, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic ("Apply"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox4), label, FALSE, FALSE, 0); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - - cancel_button = gtk_button_new (); - gtk_widget_show (cancel_button); - gtk_container_add (GTK_CONTAINER (hbuttonbox1), cancel_button); - GTK_WIDGET_SET_FLAGS (cancel_button, GTK_CAN_DEFAULT); - - alignment2 = gtk_alignment_new (0.5, 0.5, 0, 0); - gtk_widget_show (alignment2); - gtk_container_add (GTK_CONTAINER (cancel_button), alignment2); - - hbox3 = gtk_hbox_new (FALSE, 2); - gtk_widget_show (hbox3); - gtk_container_add (GTK_CONTAINER (alignment2), hbox3); - - image2 = gtk_image_new_from_stock ("gtk-no", GTK_ICON_SIZE_BUTTON); - gtk_widget_show (image2); - gtk_box_pack_start (GTK_BOX (hbox3), image2, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic ("Cancel"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox3), label, FALSE, FALSE, 0); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - - - g_signal_connect ( (gpointer) SurfaceInspector, - "delete_event", - G_CALLBACK (delete_event_callback), - NULL ); - g_signal_connect ((gpointer) SurfaceInspector, "destroy", - G_CALLBACK (gtk_widget_destroy), - NULL); - - g_signal_connect ((gpointer) texture_combo_entry, "key_press_event", - G_CALLBACK (on_texture_combo_entry_key_press_event), - NULL); - g_signal_connect ((gpointer) texture_combo_entry, "activate", - G_CALLBACK (on_texture_combo_entry_activate), - NULL); - - - g_signal_connect ((gpointer) hshift_offset_spinbutton, "value_changed", - G_CALLBACK (on_hshift_offset_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) vshift_offset_spinbutton, "value_changed", - G_CALLBACK (on_vshift_offset_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) hscale_offset_spinbutton, "value_changed", - G_CALLBACK (on_hscale_offset_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) vscale_offset_spinbutton, "value_changed", - G_CALLBACK (on_vscale_offset_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) rotate_offset_spinbutton, "value_changed", - G_CALLBACK (on_rotate_offset_spinbutton_value_changed), - NULL); - - g_signal_connect ((gpointer) hshift_value_spinbutton, "value_changed", - G_CALLBACK (on_hshift_value_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) vshift_value_spinbutton, "value_changed", - G_CALLBACK (on_vshift_value_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) hscale_value_spinbutton, "value_changed", - G_CALLBACK (on_hscale_value_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) vscale_value_spinbutton, "value_changed", - G_CALLBACK (on_vscale_value_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) rotate_value_spinbutton, "value_changed", - G_CALLBACK (on_rotate_value_spinbutton_value_changed), - NULL); - - g_signal_connect ((gpointer) hshift_step_spinbutton, "value_changed", - G_CALLBACK (on_hshift_step_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) vshift_step_spinbutton, "value_changed", - G_CALLBACK (on_vshift_step_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) hscale_step_spinbutton, "value_changed", - G_CALLBACK (on_hscale_step_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) vscale_step_spinbutton, "value_changed", - G_CALLBACK (on_vscale_step_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) rotate_step_spinbutton, "value_changed", - G_CALLBACK (on_rotate_step_spinbutton_value_changed), - NULL); - - g_signal_connect ((gpointer) match_grid_button, "clicked", - G_CALLBACK (on_match_grid_button_clicked), - NULL); - g_signal_connect ((gpointer) lock_valuechange_togglebutton, "toggled", - G_CALLBACK (on_lock_valuechange_togglebutton_toggled), - NULL); - - g_signal_connect ((gpointer) fit_width_spinbutton, "value_changed", - G_CALLBACK (on_fit_width_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) fit_height_spinbutton, "value_changed", - G_CALLBACK (on_fit_height_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) fit_button, "clicked", - G_CALLBACK (on_fit_button_clicked), - NULL); - - g_signal_connect ((gpointer) axial_button, "clicked", - G_CALLBACK (on_axial_button_clicked), - NULL); - - g_signal_connect ((gpointer) done_button, "clicked", - G_CALLBACK (on_done_button_clicked), - NULL); - g_signal_connect ((gpointer) apply_button, "clicked", - G_CALLBACK (on_apply_button_clicked), - NULL); - g_signal_connect ((gpointer) cancel_button, "clicked", - G_CALLBACK (on_cancel_button_clicked), - NULL); - - - return SurfaceInspector; -} - - -// Texture Combo -gboolean on_texture_combo_entry_key_press_event (GtkWidget *widget, GdkEventKey *event, - gpointer user_data) -{ - // Have Tab activate selection as well as Return - if (event->keyval == GDK_Tab) - g_signal_emit_by_name ( texture_combo_entry, "activate" ); - - return FALSE; -} - -void on_texture_combo_entry_activate (GtkEntry *entry, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - char text[128] = { 0 }; - - if (!texdef_face_list_empty() && g_bListenChanged) - { - // activate only on entry change - strcpy( text, gtk_entry_get_text(entry)); - if ( strcmp( old_texture_entry, text )) - { - // Check for spaces in shader name - if (text[0] <= ' ' || strchr(text, ' ')) - Sys_FPrintf(SYS_WRN, "WARNING: spaces in shader names are not allowed, ignoring '%s'\n", text); - else - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - strcpy( old_texture_entry, text ); - tmp_texdef->SetName( text ); - } - GetTexMods(); - } - } - } -} - -// Offset Spins -static void on_hshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_offset.shift[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_offset_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - if (is_HShift_conflicting) - tmp_texdef->shift[0] = tmp_orig_texdef->shift[0] + texdef_offset.shift[0]; - else - tmp_texdef->shift[0] = texdef_SI_values.shift[0] + texdef_offset.shift[0]; - } - GetTexMods(); - } -} - -static void on_vshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_offset.shift[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_offset_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - if (is_VShift_conflicting) - tmp_texdef->shift[1] = tmp_orig_texdef->shift[1] + texdef_offset.shift[1]; - else - tmp_texdef->shift[1] = texdef_SI_values.shift[1] + texdef_offset.shift[1]; - } - GetTexMods(); - } - -} - -static void on_hscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_offset.scale[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_offset_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - if (is_HScale_conflicting) - tmp_texdef->scale[0] = tmp_orig_texdef->scale[0] + texdef_offset.scale[0]; - else - tmp_texdef->scale[0] = texdef_SI_values.scale[0] + texdef_offset.scale[0]; - } - GetTexMods(); - } - - -} - -static void on_vscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_offset.scale[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_offset_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - if (is_VScale_conflicting) - tmp_texdef->scale[1] = tmp_orig_texdef->scale[1] + texdef_offset.scale[1]; - else - tmp_texdef->scale[1] = texdef_SI_values.scale[1] + texdef_offset.scale[1]; - } - GetTexMods(); - } - -} - -static void on_rotate_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_offset.rotate = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_offset_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - if (is_Rotate_conflicting) - tmp_texdef->rotate = tmp_orig_texdef->rotate + texdef_offset.rotate; - else - tmp_texdef->rotate = texdef_SI_values.rotate + texdef_offset.rotate; - } - GetTexMods(); - } - -} - - -// Match Grid -static void on_match_grid_button_clicked (GtkButton *button, gpointer user_data) -{ - float hscale, vscale; - - if( !strcmp(gtk_entry_get_text (GTK_ENTRY (hscale_value_spinbutton)), "") ) - hscale = 0.0; - else - hscale = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_value_spinbutton) ); - - if( !strcmp( gtk_entry_get_text (GTK_ENTRY (vscale_value_spinbutton)), "") ) - vscale = 0.0; - else - vscale = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_value_spinbutton) ); - DoSnapTToGrid (hscale, vscale); -} - - -// Lock out changes to Value -static void on_lock_valuechange_togglebutton_toggled (GtkToggleButton *togglebutton, gpointer user_data) -{ - bool is_Locked; - - is_Locked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lock_valuechange_togglebutton)); - - gtk_widget_set_sensitive( GTK_WIDGET( hscale_value_spinbutton ), is_Locked ); - gtk_widget_set_sensitive( GTK_WIDGET( vscale_value_spinbutton ), is_Locked ); - gtk_widget_set_sensitive( GTK_WIDGET( hshift_value_spinbutton ), is_Locked ); - gtk_widget_set_sensitive( GTK_WIDGET( vshift_value_spinbutton ), is_Locked ); - gtk_widget_set_sensitive( GTK_WIDGET( rotate_value_spinbutton ), is_Locked ); -} - - -// Value Spins -static void on_hshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_SI_values.shift[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_value_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - tmp_texdef->shift[0] = texdef_SI_values.shift[0] + texdef_offset.shift[0]; - is_HShift_conflicting = FALSE; - } - GetTexMods(); - } -} - -static void on_vshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_SI_values.shift[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_value_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - tmp_texdef->shift[1] = texdef_SI_values.shift[1] + texdef_offset.shift[1]; - is_VShift_conflicting = FALSE; - } - GetTexMods(); - } -} - -static void on_hscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_SI_values.scale[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_value_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - tmp_texdef->scale[0] = texdef_SI_values.scale[0] + texdef_offset.scale[0]; - is_HScale_conflicting = FALSE; - } - GetTexMods(); - } -} - -static void on_vscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_SI_values.scale[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_value_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - tmp_texdef->scale[1] = texdef_SI_values.scale[1] + texdef_offset.scale[1]; - is_VScale_conflicting = FALSE; - } - GetTexMods(); - } -} - -static void on_rotate_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_SI_values.rotate = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_value_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - tmp_texdef->rotate = texdef_SI_values.rotate + texdef_offset.rotate; - is_Rotate_conflicting = FALSE; - } - GetTexMods(); - } -} - - -// Step Spins -static void on_hshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - gfloat val; - GtkAdjustment * adjust; - - if (!g_bListenChanged) - return; - - l_pIncrement = Get_SI_Inc(); - -#ifdef DBG_SI - Sys_Printf("OnIncrementChanged HShift\n"); -#endif - - val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_step_spinbutton) ) ; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hshift_offset_spinbutton )); - adjust->step_increment = val; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hshift_value_spinbutton )); - adjust->step_increment = val; - l_pIncrement->shift[0] = val; -} - -static void on_vshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - gfloat val; - GtkAdjustment * adjust; - - if (!g_bListenChanged) - return; - - l_pIncrement = Get_SI_Inc(); - -#ifdef DBG_SI - Sys_Printf("OnIncrementChanged VShift\n"); -#endif - - val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_step_spinbutton) ) ; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vshift_offset_spinbutton )); - adjust->step_increment = val; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vshift_value_spinbutton )); - adjust->step_increment = val; - l_pIncrement->shift[1] = val; -} - -static void on_hscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - gfloat val; - GtkAdjustment * adjust; - - if (!g_bListenChanged) - return; - - l_pIncrement = Get_SI_Inc(); - -#ifdef DBG_SI - Sys_Printf("OnIncrementChanged HShift\n"); -#endif - - val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_step_spinbutton) ) ; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hscale_offset_spinbutton )); - adjust->step_increment = val; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hscale_value_spinbutton )); - adjust->step_increment = val; - l_pIncrement->scale[0] = val; -} - -static void on_vscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - gfloat val; - GtkAdjustment * adjust; - - if (!g_bListenChanged) - return; - - l_pIncrement = Get_SI_Inc(); - -#ifdef DBG_SI - Sys_Printf("OnIncrementChanged HShift\n"); -#endif - - val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_step_spinbutton) ) ; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vscale_offset_spinbutton )); - adjust->step_increment = val; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vscale_value_spinbutton )); - adjust->step_increment = val; - l_pIncrement->scale[1] = val; -} - -static void on_rotate_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - gfloat val; - GtkAdjustment * adjust; - - if (!g_bListenChanged) - return; - - l_pIncrement = Get_SI_Inc(); - -#ifdef DBG_SI - Sys_Printf("OnIncrementChanged HShift\n"); -#endif - - val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_step_spinbutton) ) ; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( rotate_offset_spinbutton )); - adjust->step_increment = val; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( rotate_value_spinbutton )); - adjust->step_increment = val; - l_pIncrement->rotate = val; -} - - -// Fit Texture -static void on_fit_width_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - m_nWidth = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(fit_width_spinbutton) ); -} - -static void on_fit_height_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - m_nHeight = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(fit_height_spinbutton) ); -} - -static void on_fit_button_clicked (GtkButton *button, gpointer user_data) -{ - FaceList_FitTexture(get_texdef_face_list(), m_nHeight, m_nWidth); - Sys_UpdateWindows(W_ALL); -} - - -// Axial Button -static void on_axial_button_clicked (GtkButton *button, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_texdef->shift[0] = 0.0; - tmp_texdef->shift[1] = 0.0; - tmp_texdef->scale[0] = 0.5; - tmp_texdef->scale[1] = 0.5; - tmp_texdef->rotate = 0.0; - } - } - - SetTexdef_FaceList( get_texdef_face_list(), FALSE, TRUE ); - Sys_UpdateWindows(W_ALL); -} - - -// Action Buttons -static void on_done_button_clicked (GtkButton *button, gpointer user_data) -{ - if ( !texdef_face_list_empty() ) - GetTexMods(TRUE); - HideDlg(); - Sys_UpdateWindows(W_ALL); -} - -static void on_apply_button_clicked (GtkButton *button, gpointer user_data) -{ - if (!g_bListenChanged) - return; - - if ( !texdef_face_list_empty() ) - { - GetTexMods (TRUE); - Sys_UpdateWindows(W_CAMERA); - GetTexdefInfo_from_Radiant(); - SetTexMods(); - } -} - -static void on_cancel_button_clicked (GtkButton *button, gpointer user_data) -{ - texturewin = Texturewin (); - texturewin->texdef = g_old_texdef; - // cancel the last do if we own it - if ( (m_nUndoId == Undo_GetUndoId()) && ( m_nUndoId != 0 )) - { -#ifdef DBG_SI - Sys_Printf("OnCancel calling Undo_Undo\n"); -#endif - g_bListenUpdate = false; - Undo_Undo(TRUE); - g_bListenUpdate = true; - m_nUndoId = 0; - } - HideDlg(); -} - - +/* +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 +*/ + +// +// Surface Dialog Module +// + +// +// Nurail: Implemented to Module from the main Radiant Surface Dialog code +// + + +#include +#include + +#include "surfdlg_plugin.h" + + + +#ifdef _DEBUG +//#define DBG_SI 1 +#endif + +#include "gtkr_vector.h" + +std::vector g_texdef_face_vector; + +inline texdef_to_face_t* get_texdef_face_list() +{ + return &(*g_texdef_face_vector.begin()); +} + +inline unsigned int texdef_face_list_empty() +{ + return g_texdef_face_vector.empty(); +} + +inline unsigned int texdef_face_list_size() +{ + return g_texdef_face_vector.size(); +} + +// For different faces having different values +bool is_HShift_conflicting; +bool is_VShift_conflicting; +bool is_HScale_conflicting; +bool is_VScale_conflicting; +bool is_Rotate_conflicting; +bool is_TextureName_conflicting; + +void ShowDlg(); +void HideDlg(); +void SetTexMods(); +void GetTexMods(bool b_SetUndoPoint = FALSE); +void BuildDialog(); +void FitAll(); +void InitDefaultIncrement(texdef_t *); +void DoSnapTToGrid(float hscale, float vscale); +// called to perform a fitting from the outside (shortcut key) +void SurfaceDialogFitAll(); + +// Heretic2 Flags Functions +void SetFlagButtons_Heretic2(texdef_to_face_t *texdef_face_list, bool b_isListEmpty); +void SetChangeInFlags_Face_Heretic2 (texdef_to_face_t *texdef_face_list); +GtkWidget* Create_Heretic2FlagsDialog (GtkWidget* surfacedialog_widget); + + +// Dialog Data +int m_nHeight; +int m_nWidth; + +// 0 is invalid, otherwise it's the Id of the last 'do' we are responsible for +int m_nUndoId; + + +texturewin_t *texturewin; +texdef_t *l_pIncrement; +texdef_t texdef_offset; +texdef_t texdef_SI_values; + +// For Texture Entry, activate only on entry change +char old_texture_entry[128]; + +// the texdef to switch back to when the OnCancel is called +texdef_t g_old_texdef; + +// when TRUE, this thing means the surface inspector is currently being displayed +bool g_surfwin = FALSE; +// turn on/off processing of the "changed" "value_changed" messages +// (need to turn off when we are feeding data in) +bool g_bListenChanged = true; +// turn on/off listening of the update messages +bool g_bListenUpdate = true; + +GtkWidget* create_SurfaceInspector (void); +GtkWidget *SurfaceInspector = NULL; + +GtkWidget *m_pWidget; +GtkWidget *GetWidget () { return SurfaceInspector; } +GtkWidget *Get_SI_Module_Widget () { return SurfaceInspector; } +void SetWidget(GtkWidget *new_widget) { m_pWidget = new_widget; } +GtkWidget *GetDlgWidget (const char* name) + { return GTK_WIDGET (g_object_get_data (G_OBJECT (SurfaceInspector), name)); } + +// Spins for FitTexture +GtkWidget *spin_width; +GtkWidget *spin_height; + + +GtkWidget *texture_combo; +GtkWidget *texture_combo_entry; + +GtkWidget *match_grid_button; +GtkWidget *lock_valuechange_togglebutton; + +GtkObject *hshift_value_spinbutton_adj; +GtkWidget *hshift_value_spinbutton; +GtkObject *vshift_value_spinbutton_adj; +GtkWidget *vshift_value_spinbutton; +GtkObject *hscale_value_spinbutton_adj; +GtkWidget *hscale_value_spinbutton; +GtkObject *vscale_value_spinbutton_adj; +GtkWidget *vscale_value_spinbutton; +GtkObject *rotate_value_spinbutton_adj; +GtkWidget *rotate_value_spinbutton; + +GtkObject *hshift_offset_spinbutton_adj; +GtkWidget *hshift_offset_spinbutton; +GtkObject *vshift_offset_spinbutton_adj; +GtkWidget *vshift_offset_spinbutton; +GtkObject *hscale_offset_spinbutton_adj; +GtkWidget *hscale_offset_spinbutton; +GtkObject *vscale_offset_spinbutton_adj; +GtkWidget *vscale_offset_spinbutton; +GtkObject *rotate_offset_spinbutton_adj; +GtkWidget *rotate_offset_spinbutton; + +GtkObject *hshift_step_spinbutton_adj; +GtkWidget *hshift_step_spinbutton; +GtkObject *vshift_step_spinbutton_adj; +GtkWidget *vshift_step_spinbutton; +GtkObject *hscale_step_spinbutton_adj; +GtkWidget *hscale_step_spinbutton; +GtkObject *vscale_step_spinbutton_adj; +GtkWidget *vscale_step_spinbutton; +GtkObject *rotate_step_spinbutton_adj; +GtkWidget *rotate_step_spinbutton; + +GtkObject *fit_width_spinbutton_adj; +GtkWidget *fit_width_spinbutton; +GtkObject *fit_height_spinbutton_adj; +GtkWidget *fit_height_spinbutton; +GtkWidget *fit_button; +GtkWidget *axial_button; + +GtkWidget *done_button; +GtkWidget *apply_button; +GtkWidget *cancel_button; + +// Callbacks +gboolean on_texture_combo_entry_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data); +void on_texture_combo_entry_activate (GtkEntry *entry, gpointer user_data); + +static void on_match_grid_button_clicked (GtkButton *button, gpointer user_data); +static void on_lock_valuechange_togglebutton_toggled (GtkToggleButton *togglebutton, gpointer user_data); + +static void on_hshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_hscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_rotate_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); + +static void on_hshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_hscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_rotate_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); + +static void on_hshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_hscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_rotate_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); + +static void on_fit_width_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_fit_height_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_fit_button_clicked (GtkButton *button, gpointer user_data); +static void on_axial_button_clicked (GtkButton *button, gpointer user_data); + +static void on_done_button_clicked (GtkButton *button, gpointer user_data); +static void on_apply_button_clicked (GtkButton *button, gpointer user_data); +static void on_cancel_button_clicked (GtkButton *button, gpointer user_data); + + +/* +=================================================== + + SURFACE INSPECTOR + +=================================================== +*/ + + +void IsFaceConflicting() +{ + texdef_t* tmp_texdef; + texdef_to_face_t* temp_texdef_face_list; + char buf[12]; + char texture_name[128]; + + if (texdef_face_list_empty()) + { + gtk_entry_set_text( GTK_ENTRY (hshift_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (vshift_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (hscale_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (vscale_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (rotate_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (texture_combo_entry), ""); + return; + } + + g_bListenChanged = FALSE; + + tmp_texdef = &get_texdef_face_list()->texdef; + + strcpy(texture_name, tmp_texdef->GetName() ); + + texdef_SI_values.shift[0] = tmp_texdef->shift[0]; + texdef_SI_values.shift[1] = tmp_texdef->shift[1]; + texdef_SI_values.scale[0] = tmp_texdef->scale[0]; + texdef_SI_values.scale[1] = tmp_texdef->scale[1]; + texdef_SI_values.rotate = tmp_texdef->rotate; + texdef_SI_values.SetName( texture_name ); + + is_HShift_conflicting = FALSE; + is_VShift_conflicting = FALSE; + is_HScale_conflicting = FALSE; + is_VScale_conflicting = FALSE; + is_Rotate_conflicting = FALSE; + is_TextureName_conflicting = FALSE; + + if (texdef_face_list_size() > 1) + { + temp_texdef_face_list = get_texdef_face_list()->next; + + for (temp_texdef_face_list; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = &temp_texdef_face_list->texdef; + if ( texdef_SI_values.shift[0] != tmp_texdef->shift[0] ) + is_HShift_conflicting = TRUE; + + if ( texdef_SI_values.shift[1] != tmp_texdef->shift[1] ) + is_VShift_conflicting = TRUE; + + if ( texdef_SI_values.scale[0] != tmp_texdef->scale[0] ) + is_HScale_conflicting = TRUE; + + if ( texdef_SI_values.scale[1] != tmp_texdef->scale[1] ) + is_VScale_conflicting = TRUE; + + if ( texdef_SI_values.rotate != tmp_texdef->rotate ) + is_Rotate_conflicting = TRUE; + + if ( strcmp( texture_name, tmp_texdef->GetName() ) ) + is_TextureName_conflicting = TRUE; + } + } + + if(is_HShift_conflicting) + gtk_entry_set_text( GTK_ENTRY (hshift_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(hshift_value_spinbutton) , texdef_SI_values.shift[0] ); + + if(is_VShift_conflicting) + gtk_entry_set_text( GTK_ENTRY (vshift_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(vshift_value_spinbutton) , texdef_SI_values.shift[1] ); + + if(is_HScale_conflicting) + gtk_entry_set_text( GTK_ENTRY (hscale_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(hscale_value_spinbutton) , texdef_SI_values.scale[0] ); + + if(is_VScale_conflicting) + gtk_entry_set_text( GTK_ENTRY (vscale_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(vscale_value_spinbutton) , texdef_SI_values.scale[1] ); + + if(is_Rotate_conflicting) + gtk_entry_set_text( GTK_ENTRY (rotate_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(rotate_value_spinbutton) , texdef_SI_values.rotate ); + + g_bListenChanged = TRUE; +} + +#define MAX_NUM_LIST_ITEMS 15 +static void PopulateTextureComboList() +{ + texdef_t* tmp_texdef; + texdef_to_face_t* temp_texdef_face_list; + char blank[1]; + GList *items = NULL; + GList *tmp_item; + int num_of_list_items = 0; + + blank[0] = 0; + + if (texdef_face_list_empty()) + { + items = g_list_append (items, (gpointer) blank); + // For Texture Entry, activate only on entry change + strcpy (old_texture_entry, blank); + } + else if ( !is_TextureName_conflicting ) + { + temp_texdef_face_list = get_texdef_face_list(); + tmp_texdef = (texdef_t *) &get_texdef_face_list()->texdef; + items = g_list_append( items, (gpointer) tmp_texdef->GetName() ); + // For Texture Entry, activate only on entry change + strcpy (old_texture_entry, tmp_texdef->GetName()); + } + else + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + // Need to do a string compare, hence the custom search + if (!( g_list_find_custom (items, tmp_texdef->GetName(), (GCompareFunc) strcmp ) )) + { + items = g_list_append( items, (gpointer) tmp_texdef->GetName() ); + num_of_list_items++; + } + // Make sure the combo list isn't too long + if (num_of_list_items >= MAX_NUM_LIST_ITEMS) + break; + } + // If this isn't added last (to the top of the list), g_list_find freaks. + items = g_list_prepend (items, (gpointer) blank); + // For Texture Entry, activate only on entry change + strcpy (old_texture_entry, blank); + } + + gtk_combo_set_popdown_strings (GTK_COMBO (texture_combo), items); + g_list_free(items); + +} + +static void ZeroOffsetValues() +{ + texdef_offset.shift[0] = 0.0; + texdef_offset.shift[1] = 0.0; + texdef_offset.scale[0] = 0.0; + texdef_offset.scale[1] = 0.0; + texdef_offset.rotate = 0.0; +} + +static void GetTexdefInfo_from_Radiant() +{ + g_texdef_face_vector.clear(); + + unsigned int count = GetSelectedFaceCountfromBrushes(); + if(count == 0) + count = GetSelectedFaceCount(); + + g_texdef_face_vector.resize(count); + + if (!texdef_face_list_empty()) + { + texdef_to_face_t* p = get_texdef_face_list(); + GetSelFacesTexdef( get_texdef_face_list() ); + } + + IsFaceConflicting(); + PopulateTextureComboList(); + ZeroOffsetValues(); + if ( texdef_face_list_empty() ) + SetFlagButtons_Heretic2( get_texdef_face_list() , TRUE); + else + SetFlagButtons_Heretic2( get_texdef_face_list() , FALSE); + +} + +static gint delete_event_callback(GtkWidget *widget, GdkEvent* event, gpointer data) +{ + HideDlg(); + return TRUE; +} + +// make the shift increments match the grid settings +// the objective being that the shift+arrows shortcuts move the texture by the corresponding grid size +// this depends on a scale value if you have selected a particular texture on which you want it to work: +// we move the textures in pixels, not world units. (i.e. increment values are in pixel) +// depending on the texture scale it doesn't take the same amount of pixels to move of g_qeglobals.d_gridsize +// increment * scale = gridsize +// hscale and vscale are optional parameters, if they are zero they will be set to the default scale +// NOTE: the default scale depends if you are using BP mode or regular. +// For regular it's 0.5f (128 pixels cover 64 world units), for BP it's simply 1.0f +// see fenris #2810 +void DoSnapTToGrid(float hscale, float vscale) +{ + l_pIncrement = Get_SI_Inc(); + + if (hscale == 0.0f) + { + hscale = 0.5f; + } + if (vscale == 0.0f) + { + vscale = 0.5f; + } +#ifdef _DEBUG + Sys_Printf ("DoSnapTToGrid: hscale %g vscale %g\n", hscale, vscale); +#endif + l_pIncrement->shift[0] = GridSize() / hscale; + l_pIncrement->shift[1] = GridSize() / vscale; + // now some update work + // FIXME: doesn't look good here, seems to be called several times + SetTexMods(); +} + +void UpdateSurfaceDialog() +{ + if (!g_bListenUpdate) + return; + + if (!SurfaceInspector) + return; + + // avoid long delays on slow computers + while (gtk_events_pending ()) + gtk_main_iteration (); + + if (g_surfwin) + { +#ifdef DBG_SI + Sys_Printf("UpdateSurfaceDialog\n"); +#endif + GetTexdefInfo_from_Radiant(); + SetTexMods(); + } + +} + +// DoSurface will always try to show the surface inspector +// or update it because something new has been selected +void DoSurface (void) +{ +#ifdef DBG_SI + Sys_Printf("DoSurface\n"); +#endif + if (!SurfaceInspector) + create_SurfaceInspector (); + + ShowDlg(); + SetTexMods (); +} + +void ToggleSurface() +{ +#ifdef DBG_SI + Sys_Printf("ToggleSurface Module\n"); +#endif + if (!g_surfwin) + DoSurface (); + else + on_cancel_button_clicked(NULL, NULL); +} + +// NOTE: will raise and show the Surface inspector and exec fit for patches and brushes +void SurfaceDlgFitAll() +{ + DoSurface(); + FitAll(); +} + +// ============================================================================= +// SurfaceDialog class + +void ShowDlg() +{ + + if(!SurfaceInspector) + create_SurfaceInspector(); + else + gtk_widget_show (SurfaceInspector); + + GetTexdefInfo_from_Radiant(); + GetTexMods(TRUE); // Set Initial Undo Point + g_surfwin = TRUE; +} + +void HideDlg() +{ + g_surfwin = FALSE; + gtk_widget_hide (SurfaceInspector); +} + + +// set default values for increments (shift scale and rot) +// this is called by the prefs code if can't find the values +void InitDefaultIncrement(texdef_t *tex) +{ + tex->SetName("foo"); + tex->shift[0] = 8; + tex->shift[1] = 8; + tex->scale[0] = 0.25; + tex->scale[1] = 0.25; + tex->rotate = 10; +} + +void BuildDialog () +{ + if ( !SurfaceInspector ) + create_SurfaceInspector(); +} + +/* +============== +SetTexMods + +Set the fields to the current texdef (i.e. map/texdef -> dialog widgets) +=============== +*/ + +void SetTexMods() +{ + texdef_t *pt; + GtkSpinButton *spin; + GtkAdjustment *adjust; + + texturewin = Texturewin (); + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("SurfaceDlg SetTexMods\n"); +#endif + + if (!g_surfwin) + return; + + pt = &texturewin->texdef; + + g_bListenChanged = false; + + if(strncmp(pt->GetName(), "textures/", 9) != 0) + texdef_offset.SetName(SHADER_NOT_FOUND); + + + spin = GTK_SPIN_BUTTON (hshift_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.shift[0]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[0]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(hshift_step_spinbutton), l_pIncrement->shift[0]); + + spin = GTK_SPIN_BUTTON (hshift_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[0]; + + + spin = GTK_SPIN_BUTTON (vshift_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.shift[1]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[1]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(vshift_step_spinbutton), l_pIncrement->shift[1]); + + spin = GTK_SPIN_BUTTON (vshift_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[1]; + + + spin = GTK_SPIN_BUTTON (hscale_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.scale[0]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[0]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(hscale_step_spinbutton), l_pIncrement->scale[0]); + + spin = GTK_SPIN_BUTTON (hscale_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[0]; + + + spin = GTK_SPIN_BUTTON (vscale_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.scale[1]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[1]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(vscale_step_spinbutton), l_pIncrement->scale[1]); + + spin = GTK_SPIN_BUTTON (vscale_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[1]; + + + spin = GTK_SPIN_BUTTON (rotate_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.rotate); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->rotate; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(rotate_step_spinbutton), l_pIncrement->rotate); + + spin = GTK_SPIN_BUTTON (rotate_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->rotate; + + + g_bListenChanged = true; + + // store the current texdef as our escape route if user hits OnCancel + g_old_texdef = texturewin->texdef; +} + +/* +============== +GetTexMods + +Shows any changes to the main Radiant windows +=============== +*/ +void GetTexMods(bool b_SetUndoPoint) +{ + +#ifdef DBG_SI + Sys_Printf("SurfaceDlg GetTexMods\n"); +#endif + + if ( !texdef_face_list_empty() ) + { + g_bListenUpdate=FALSE; + SetChangeInFlags_Face_Heretic2 ( get_texdef_face_list() ); + SetTexdef_FaceList( get_texdef_face_list(), b_SetUndoPoint ); + g_bListenUpdate=TRUE; + + if (b_SetUndoPoint) + m_nUndoId = Undo_GetUndoId(); + } +} + +void FitAll() +{ + on_fit_button_clicked(NULL, NULL); +} + + +//////////////////////////////////////////////////////////////////// +// +// GUI Section +// +//////////////////////////////////////////////////////////////////// + +GtkWidget* create_SurfaceInspector (void) +{ + + GtkWidget *label; + GtkWidget *hseparator; + GtkWidget *eventbox; + + GtkWidget *viewport8; + GtkWidget *viewport9; + GtkWidget *viewport2; + GtkWidget *viewport7; + GtkWidget *viewport5; + GtkWidget *viewport6; + GtkWidget *viewport10; + + GtkWidget *table1; + GtkWidget *table4; + GtkWidget *table5; + GtkWidget *table7; + + GtkWidget *alignment1; + GtkWidget *alignment2; + GtkWidget *alignment3; + + GtkWidget *vbox7; + + GtkWidget *hbox1; + GtkWidget *hbox2; + GtkWidget *hbox3; + GtkWidget *hbox4; + + GtkWidget *image1; + GtkWidget *image2; + GtkWidget *image3; + + GtkWidget *hbuttonbox1; + + SurfaceInspector = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (SurfaceInspector), 4); + gtk_window_set_title (GTK_WINDOW (SurfaceInspector), "Surface Inspector"); + + SetWinPos_from_Prefs(SurfaceInspector); + + viewport8 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport8); + gtk_container_add (GTK_CONTAINER (SurfaceInspector), viewport8); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport8), GTK_SHADOW_NONE); + + vbox7 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox7); + gtk_container_add (GTK_CONTAINER (viewport8), vbox7); + + viewport9 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport9); + gtk_box_pack_start (GTK_BOX (vbox7), viewport9, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport9), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport9), GTK_SHADOW_ETCHED_IN); + + hbox1 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox1); + gtk_container_add (GTK_CONTAINER (viewport9), hbox1); + gtk_container_set_border_width (GTK_CONTAINER (hbox1), 4); + + label = gtk_label_new ("Texture: "); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox1), label, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + texture_combo = gtk_combo_new (); + g_object_set_data (G_OBJECT (GTK_COMBO (texture_combo)->popwin), + "KeepMeAround", texture_combo); + gtk_combo_disable_activate ( (GtkCombo*) texture_combo); + gtk_widget_show (texture_combo); + gtk_box_pack_start (GTK_BOX (hbox1), texture_combo, TRUE, TRUE, 0); + + texture_combo_entry = GTK_COMBO (texture_combo)->entry; + gtk_widget_show (texture_combo_entry); + gtk_entry_set_max_length (GTK_ENTRY (texture_combo_entry), 128); + + viewport2 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport2); + gtk_box_pack_start (GTK_BOX (vbox7), viewport2, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport2), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport2), GTK_SHADOW_ETCHED_IN); + + table1 = gtk_table_new (13, 4, FALSE); + gtk_widget_show (table1); + gtk_container_add (GTK_CONTAINER (viewport2), table1); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Offset"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table1), label, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("Step"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table1), label, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 3, 4, 12, 13, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + match_grid_button = gtk_button_new_with_mnemonic ("Match Grid"); + gtk_widget_show (match_grid_button); + gtk_container_add (GTK_CONTAINER (eventbox), match_grid_button); + + label = gtk_label_new ("Value"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table1), label, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_SHRINK | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("V Shift: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 6, 7, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new (" H Scale: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 8, 9, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("V Scale: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 10, 11, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Rotate: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("H Shift: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 1, 2, 12, 13, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + lock_valuechange_togglebutton = gtk_toggle_button_new_with_mnemonic ("UNLOCK"); + gtk_widget_show (lock_valuechange_togglebutton); + gtk_container_add (GTK_CONTAINER (eventbox), lock_valuechange_togglebutton); + + // Value Spins + hshift_value_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + hshift_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_value_spinbutton_adj), 1, 2); + gtk_widget_show (hshift_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hshift_value_spinbutton, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hshift_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( hshift_value_spinbutton ), FALSE ); + + vshift_value_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + vshift_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_value_spinbutton_adj), 1, 2); + gtk_widget_show (vshift_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vshift_value_spinbutton, 1, 2, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vshift_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( vshift_value_spinbutton ), FALSE ); + + hscale_value_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + hscale_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_value_spinbutton_adj), 1, 4); + gtk_widget_show (hscale_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hscale_value_spinbutton, 1, 2, 6, 7, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hscale_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( hscale_value_spinbutton ), FALSE ); + + vscale_value_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + vscale_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_value_spinbutton_adj), 1, 4); + gtk_widget_show (vscale_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vscale_value_spinbutton, 1, 2, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vscale_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( vscale_value_spinbutton ), FALSE ); + + rotate_value_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); + rotate_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_value_spinbutton_adj), 1, 0); + gtk_widget_show (rotate_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), rotate_value_spinbutton, 1, 2, 10, 11, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (rotate_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( rotate_value_spinbutton ), FALSE ); + + // Offset Spins + hshift_offset_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + hshift_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_offset_spinbutton_adj), 0, 2); + gtk_widget_show (hshift_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hshift_offset_spinbutton, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (hshift_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hshift_offset_spinbutton), TRUE); + + vshift_offset_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + vshift_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_offset_spinbutton_adj), 0, 2); + gtk_widget_show (vshift_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vshift_offset_spinbutton, 2, 3, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (vshift_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vshift_offset_spinbutton), TRUE); + + hscale_offset_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + hscale_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_offset_spinbutton_adj), 0, 4); + gtk_widget_show (hscale_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hscale_offset_spinbutton, 2, 3, 6, 7, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (hscale_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hscale_offset_spinbutton), TRUE); + + vscale_offset_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + vscale_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_offset_spinbutton_adj), 0, 4); + gtk_widget_show (vscale_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vscale_offset_spinbutton, 2, 3, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (vscale_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vscale_offset_spinbutton), TRUE); + + rotate_offset_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); + rotate_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_offset_spinbutton_adj), 0, 2); + gtk_widget_show (rotate_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), rotate_offset_spinbutton, 2, 3, 10, 11, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (rotate_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (rotate_offset_spinbutton), TRUE); + + // Step Spins + hshift_step_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + hshift_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_step_spinbutton_adj), 1, 2); + gtk_widget_show (hshift_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hshift_step_spinbutton, 3, 4, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_step_spinbutton), GTK_UPDATE_IF_VALID); + + vshift_step_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + vshift_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_step_spinbutton_adj), 1, 2); + gtk_widget_show (vshift_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vshift_step_spinbutton, 3, 4, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_step_spinbutton), GTK_UPDATE_IF_VALID); + + hscale_step_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + hscale_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_step_spinbutton_adj), 1, 4); + gtk_widget_show (hscale_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hscale_step_spinbutton, 3, 4, 6, 7, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_step_spinbutton), GTK_UPDATE_IF_VALID); + + vscale_step_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + vscale_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_step_spinbutton_adj), 1, 4); + gtk_widget_show (vscale_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vscale_step_spinbutton, 3, 4, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_step_spinbutton), GTK_UPDATE_IF_VALID); + + rotate_step_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); + rotate_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_step_spinbutton_adj), 1, 2); + gtk_widget_show (rotate_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), rotate_step_spinbutton, 3, 4, 10, 11, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_step_spinbutton), GTK_UPDATE_IF_VALID); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 2, 3, 12, 13, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 12, 13, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + viewport7 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport7); + gtk_box_pack_start (GTK_BOX (vbox7), viewport7, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport7), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport7), GTK_SHADOW_ETCHED_IN); + + table4 = gtk_table_new (4, 7, FALSE); + gtk_widget_show (table4); + gtk_container_add (GTK_CONTAINER (viewport7), table4); + + viewport5 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport5); + gtk_table_attach (GTK_TABLE (table4), viewport5, 1, 7, 0, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport5), 6); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport5), GTK_SHADOW_ETCHED_OUT); + + table5 = gtk_table_new (2, 3, FALSE); + gtk_widget_show (table5); + gtk_container_add (GTK_CONTAINER (viewport5), table5); + gtk_container_set_border_width (GTK_CONTAINER (table5), 5); + gtk_table_set_col_spacings (GTK_TABLE (table5), 2); + + label = gtk_label_new ("Height"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table5), label, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); + + label = gtk_label_new ("Width"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table5), label, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); + + fit_width_spinbutton_adj = gtk_adjustment_new (1, 1, 32, 1, 10, 10); + fit_width_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (fit_width_spinbutton_adj), 1, 0); + gtk_widget_show (fit_width_spinbutton); + gtk_table_attach (GTK_TABLE (table5), fit_width_spinbutton, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (fit_width_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (fit_width_spinbutton), GTK_UPDATE_IF_VALID); + + fit_height_spinbutton_adj = gtk_adjustment_new (1, 1, 32, 1, 10, 10); + fit_height_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (fit_height_spinbutton_adj), 1, 0); + gtk_widget_show (fit_height_spinbutton); + gtk_table_attach (GTK_TABLE (table5), fit_height_spinbutton, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 3, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (fit_height_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (fit_height_spinbutton), GTK_UPDATE_IF_VALID); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table5), eventbox, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table5), eventbox, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 4, 0); + + fit_button = gtk_button_new_with_mnemonic (" Fit "); + gtk_widget_show (fit_button); + gtk_container_add (GTK_CONTAINER (eventbox), fit_button); + + viewport6 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport6); + gtk_table_attach (GTK_TABLE (table4), viewport6, 0, 1, 0, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport6), 4); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport6), GTK_SHADOW_NONE); + + table7 = gtk_table_new (2, 1, FALSE); + gtk_widget_show (table7); + gtk_container_add (GTK_CONTAINER (viewport6), table7); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table7), eventbox, 0, 1, 0, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + axial_button = gtk_button_new_with_mnemonic ("Axial"); + gtk_widget_show (axial_button); + gtk_container_add (GTK_CONTAINER (eventbox), axial_button); + gtk_widget_set_size_request (axial_button, 56, 29); + gtk_container_set_border_width (GTK_CONTAINER (axial_button), 4); + + // Fit in Flags sub-dialog + Create_Heretic2FlagsDialog(vbox7); + + viewport10 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport10); + gtk_box_pack_start (GTK_BOX (vbox7), viewport10, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport10), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport10), GTK_SHADOW_ETCHED_IN); + + hbuttonbox1 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox1); + gtk_container_add (GTK_CONTAINER (viewport10), hbuttonbox1); + gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox1), 4); + gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_SPREAD); + + done_button = gtk_button_new (); + gtk_widget_show (done_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), done_button); + GTK_WIDGET_SET_FLAGS (done_button, GTK_CAN_DEFAULT); + + alignment1 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment1); + gtk_container_add (GTK_CONTAINER (done_button), alignment1); + + hbox2 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox2); + gtk_container_add (GTK_CONTAINER (alignment1), hbox2); + + image1 = gtk_image_new_from_stock ("gtk-yes", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image1); + gtk_box_pack_start (GTK_BOX (hbox2), image1, FALSE, FALSE, 0); + + label = gtk_label_new_with_mnemonic ("Done"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + apply_button = gtk_button_new (); + gtk_widget_show (apply_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), apply_button); + GTK_WIDGET_SET_FLAGS (apply_button, GTK_CAN_DEFAULT); + + alignment3 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment3); + gtk_container_add (GTK_CONTAINER (apply_button), alignment3); + + hbox4 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox4); + gtk_container_add (GTK_CONTAINER (alignment3), hbox4); + + image3 = gtk_image_new_from_stock ("gtk-apply", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image3); + gtk_box_pack_start (GTK_BOX (hbox4), image3, FALSE, FALSE, 0); + + label = gtk_label_new_with_mnemonic ("Apply"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox4), label, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + cancel_button = gtk_button_new (); + gtk_widget_show (cancel_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), cancel_button); + GTK_WIDGET_SET_FLAGS (cancel_button, GTK_CAN_DEFAULT); + + alignment2 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment2); + gtk_container_add (GTK_CONTAINER (cancel_button), alignment2); + + hbox3 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox3); + gtk_container_add (GTK_CONTAINER (alignment2), hbox3); + + image2 = gtk_image_new_from_stock ("gtk-no", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image2); + gtk_box_pack_start (GTK_BOX (hbox3), image2, FALSE, FALSE, 0); + + label = gtk_label_new_with_mnemonic ("Cancel"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox3), label, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + + g_signal_connect ( (gpointer) SurfaceInspector, + "delete_event", + G_CALLBACK (delete_event_callback), + NULL ); + g_signal_connect ((gpointer) SurfaceInspector, "destroy", + G_CALLBACK (gtk_widget_destroy), + NULL); + + g_signal_connect ((gpointer) texture_combo_entry, "key_press_event", + G_CALLBACK (on_texture_combo_entry_key_press_event), + NULL); + g_signal_connect ((gpointer) texture_combo_entry, "activate", + G_CALLBACK (on_texture_combo_entry_activate), + NULL); + + + g_signal_connect ((gpointer) hshift_offset_spinbutton, "value_changed", + G_CALLBACK (on_hshift_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vshift_offset_spinbutton, "value_changed", + G_CALLBACK (on_vshift_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) hscale_offset_spinbutton, "value_changed", + G_CALLBACK (on_hscale_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vscale_offset_spinbutton, "value_changed", + G_CALLBACK (on_vscale_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) rotate_offset_spinbutton, "value_changed", + G_CALLBACK (on_rotate_offset_spinbutton_value_changed), + NULL); + + g_signal_connect ((gpointer) hshift_value_spinbutton, "value_changed", + G_CALLBACK (on_hshift_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vshift_value_spinbutton, "value_changed", + G_CALLBACK (on_vshift_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) hscale_value_spinbutton, "value_changed", + G_CALLBACK (on_hscale_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vscale_value_spinbutton, "value_changed", + G_CALLBACK (on_vscale_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) rotate_value_spinbutton, "value_changed", + G_CALLBACK (on_rotate_value_spinbutton_value_changed), + NULL); + + g_signal_connect ((gpointer) hshift_step_spinbutton, "value_changed", + G_CALLBACK (on_hshift_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vshift_step_spinbutton, "value_changed", + G_CALLBACK (on_vshift_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) hscale_step_spinbutton, "value_changed", + G_CALLBACK (on_hscale_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vscale_step_spinbutton, "value_changed", + G_CALLBACK (on_vscale_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) rotate_step_spinbutton, "value_changed", + G_CALLBACK (on_rotate_step_spinbutton_value_changed), + NULL); + + g_signal_connect ((gpointer) match_grid_button, "clicked", + G_CALLBACK (on_match_grid_button_clicked), + NULL); + g_signal_connect ((gpointer) lock_valuechange_togglebutton, "toggled", + G_CALLBACK (on_lock_valuechange_togglebutton_toggled), + NULL); + + g_signal_connect ((gpointer) fit_width_spinbutton, "value_changed", + G_CALLBACK (on_fit_width_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) fit_height_spinbutton, "value_changed", + G_CALLBACK (on_fit_height_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) fit_button, "clicked", + G_CALLBACK (on_fit_button_clicked), + NULL); + + g_signal_connect ((gpointer) axial_button, "clicked", + G_CALLBACK (on_axial_button_clicked), + NULL); + + g_signal_connect ((gpointer) done_button, "clicked", + G_CALLBACK (on_done_button_clicked), + NULL); + g_signal_connect ((gpointer) apply_button, "clicked", + G_CALLBACK (on_apply_button_clicked), + NULL); + g_signal_connect ((gpointer) cancel_button, "clicked", + G_CALLBACK (on_cancel_button_clicked), + NULL); + + + return SurfaceInspector; +} + + +// Texture Combo +gboolean on_texture_combo_entry_key_press_event (GtkWidget *widget, GdkEventKey *event, + gpointer user_data) +{ + // Have Tab activate selection as well as Return + if (event->keyval == GDK_Tab) + g_signal_emit_by_name ( texture_combo_entry, "activate" ); + + return FALSE; +} + +void on_texture_combo_entry_activate (GtkEntry *entry, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + char text[128] = { 0 }; + + if (!texdef_face_list_empty() && g_bListenChanged) + { + // activate only on entry change + strcpy( text, gtk_entry_get_text(entry)); + if ( strcmp( old_texture_entry, text )) + { + // Check for spaces in shader name + if (text[0] <= ' ' || strchr(text, ' ')) + Sys_FPrintf(SYS_WRN, "WARNING: spaces in shader names are not allowed, ignoring '%s'\n", text); + else + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + strcpy( old_texture_entry, text ); + tmp_texdef->SetName( text ); + } + GetTexMods(); + } + } + } +} + +// Offset Spins +static void on_hshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.shift[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_HShift_conflicting) + tmp_texdef->shift[0] = tmp_orig_texdef->shift[0] + texdef_offset.shift[0]; + else + tmp_texdef->shift[0] = texdef_SI_values.shift[0] + texdef_offset.shift[0]; + } + GetTexMods(); + } +} + +static void on_vshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.shift[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_VShift_conflicting) + tmp_texdef->shift[1] = tmp_orig_texdef->shift[1] + texdef_offset.shift[1]; + else + tmp_texdef->shift[1] = texdef_SI_values.shift[1] + texdef_offset.shift[1]; + } + GetTexMods(); + } + +} + +static void on_hscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.scale[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_HScale_conflicting) + tmp_texdef->scale[0] = tmp_orig_texdef->scale[0] + texdef_offset.scale[0]; + else + tmp_texdef->scale[0] = texdef_SI_values.scale[0] + texdef_offset.scale[0]; + } + GetTexMods(); + } + + +} + +static void on_vscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.scale[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_VScale_conflicting) + tmp_texdef->scale[1] = tmp_orig_texdef->scale[1] + texdef_offset.scale[1]; + else + tmp_texdef->scale[1] = texdef_SI_values.scale[1] + texdef_offset.scale[1]; + } + GetTexMods(); + } + +} + +static void on_rotate_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.rotate = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_Rotate_conflicting) + tmp_texdef->rotate = tmp_orig_texdef->rotate + texdef_offset.rotate; + else + tmp_texdef->rotate = texdef_SI_values.rotate + texdef_offset.rotate; + } + GetTexMods(); + } + +} + + +// Match Grid +static void on_match_grid_button_clicked (GtkButton *button, gpointer user_data) +{ + float hscale, vscale; + + if( !strcmp(gtk_entry_get_text (GTK_ENTRY (hscale_value_spinbutton)), "") ) + hscale = 0.0; + else + hscale = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_value_spinbutton) ); + + if( !strcmp( gtk_entry_get_text (GTK_ENTRY (vscale_value_spinbutton)), "") ) + vscale = 0.0; + else + vscale = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_value_spinbutton) ); + DoSnapTToGrid (hscale, vscale); +} + + +// Lock out changes to Value +static void on_lock_valuechange_togglebutton_toggled (GtkToggleButton *togglebutton, gpointer user_data) +{ + bool is_Locked; + + is_Locked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lock_valuechange_togglebutton)); + + gtk_widget_set_sensitive( GTK_WIDGET( hscale_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( vscale_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( hshift_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( vshift_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( rotate_value_spinbutton ), is_Locked ); +} + + +// Value Spins +static void on_hshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.shift[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->shift[0] = texdef_SI_values.shift[0] + texdef_offset.shift[0]; + is_HShift_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_vshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.shift[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->shift[1] = texdef_SI_values.shift[1] + texdef_offset.shift[1]; + is_VShift_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_hscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.scale[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->scale[0] = texdef_SI_values.scale[0] + texdef_offset.scale[0]; + is_HScale_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_vscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.scale[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->scale[1] = texdef_SI_values.scale[1] + texdef_offset.scale[1]; + is_VScale_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_rotate_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.rotate = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->rotate = texdef_SI_values.rotate + texdef_offset.rotate; + is_Rotate_conflicting = FALSE; + } + GetTexMods(); + } +} + + +// Step Spins +static void on_hshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hshift_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hshift_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->shift[0] = val; +} + +static void on_vshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged VShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vshift_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vshift_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->shift[1] = val; +} + +static void on_hscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hscale_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hscale_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->scale[0] = val; +} + +static void on_vscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vscale_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vscale_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->scale[1] = val; +} + +static void on_rotate_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( rotate_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( rotate_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->rotate = val; +} + + +// Fit Texture +static void on_fit_width_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + m_nWidth = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(fit_width_spinbutton) ); +} + +static void on_fit_height_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + m_nHeight = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(fit_height_spinbutton) ); +} + +static void on_fit_button_clicked (GtkButton *button, gpointer user_data) +{ + FaceList_FitTexture(get_texdef_face_list(), m_nHeight, m_nWidth); + Sys_UpdateWindows(W_ALL); +} + + +// Axial Button +static void on_axial_button_clicked (GtkButton *button, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_texdef->shift[0] = 0.0; + tmp_texdef->shift[1] = 0.0; + tmp_texdef->scale[0] = 0.5; + tmp_texdef->scale[1] = 0.5; + tmp_texdef->rotate = 0.0; + } + } + + SetTexdef_FaceList( get_texdef_face_list(), FALSE, TRUE ); + Sys_UpdateWindows(W_ALL); +} + + +// Action Buttons +static void on_done_button_clicked (GtkButton *button, gpointer user_data) +{ + if ( !texdef_face_list_empty() ) + GetTexMods(TRUE); + HideDlg(); + Sys_UpdateWindows(W_ALL); +} + +static void on_apply_button_clicked (GtkButton *button, gpointer user_data) +{ + if (!g_bListenChanged) + return; + + if ( !texdef_face_list_empty() ) + { + GetTexMods (TRUE); + Sys_UpdateWindows(W_CAMERA); + GetTexdefInfo_from_Radiant(); + SetTexMods(); + } +} + +static void on_cancel_button_clicked (GtkButton *button, gpointer user_data) +{ + texturewin = Texturewin (); + texturewin->texdef = g_old_texdef; + // cancel the last do if we own it + if ( (m_nUndoId == Undo_GetUndoId()) && ( m_nUndoId != 0 )) + { +#ifdef DBG_SI + Sys_Printf("OnCancel calling Undo_Undo\n"); +#endif + g_bListenUpdate = false; + Undo_Undo(TRUE); + g_bListenUpdate = true; + m_nUndoId = 0; + } + HideDlg(); +} + + diff --git a/plugins/surface_heretic2/surfaceflagsdialog_heretic2.cpp b/plugins/surface_heretic2/surfaceflagsdialog_heretic2.cpp index d56eaa3c..13e1cb4a 100644 --- a/plugins/surface_heretic2/surfaceflagsdialog_heretic2.cpp +++ b/plugins/surface_heretic2/surfaceflagsdialog_heretic2.cpp @@ -1,1417 +1,1417 @@ -/* -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 -*/ - -#include -#include - -#include "surfdlg_plugin.h" - -#include "surfaceflagsdialog_heretic2.h" - - GtkWidget *surface_lightbutton; - GtkWidget *surface_slickbutton; - GtkWidget *surface_skybutton; - GtkWidget *surface_warpbutton; - GtkWidget *surface_trans33button; - GtkWidget *surface_trans66button; - GtkWidget *surface_flowingbutton; - GtkWidget *surface_nodrawbutton; - GtkWidget *surface_tallwallbutton; - GtkWidget *surface_alphatexbutton; - GtkWidget *surface_animspeedbutton; - GtkWidget *surface_undulatebutton; - - GtkWidget *surf_gravel_radiobutton; - GSList *surf_gravel_radiobutton_group = NULL; - GtkWidget *surf_metal_radiobutton; - GtkWidget *surf_stone_radiobutton; - GtkWidget *surf_wood_radiobutton; - - GtkWidget *surf_value_entry; - - GtkWidget *notebook1; - - GtkWidget *content_solidbutton; - GtkWidget *content_windowbutton; - GtkWidget *content_illusbutton; - GtkWidget *content_lavabutton; - GtkWidget *content_slimebutton; - GtkWidget *content_waterbutton; - GtkWidget *content_mistbutton; - GtkWidget *content_areaportalbutton; - GtkWidget *content_playerclipbutton; - GtkWidget *content_monsterclipbutton; - GtkWidget *content_current0button; - GtkWidget *content_current90button; - GtkWidget *content_current180button; - GtkWidget *content_current270button; - GtkWidget *content_currentUPbutton; - GtkWidget *content_currentDOWNbutton; - GtkWidget *content_originbutton; - GtkWidget *content_detailbutton; - GtkWidget *content_ladderbutton; - GtkWidget *content_camnoblockbutton; - - - gboolean setup_buttons = TRUE; - - int working_surface_flags; - int surface_mask; - int working_content_flags; - int content_mask; - int working_value; - gboolean surface_material_inconsistant = FALSE; - -inline void set_inconsistent(GtkWidget *toggle_button) -{ - gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON (toggle_button), TRUE); -} - -inline void clear_inconsistent(GtkWidget *toggle_button) -{ - if ( gtk_toggle_button_get_inconsistent(GTK_TOGGLE_BUTTON (toggle_button)) ) - { - gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON (toggle_button), FALSE); - } - -} - -void clear_all_inconsistent(void) -{ - clear_inconsistent( surface_lightbutton ); - clear_inconsistent( surface_slickbutton ); - clear_inconsistent( surface_skybutton ); - clear_inconsistent( surface_warpbutton ); - clear_inconsistent( surface_trans33button ); - clear_inconsistent( surface_trans66button ); - clear_inconsistent( surface_flowingbutton ); - clear_inconsistent( surface_nodrawbutton ); - clear_inconsistent( surface_tallwallbutton ); - clear_inconsistent( surface_alphatexbutton ); - clear_inconsistent( surface_animspeedbutton ); - clear_inconsistent( surface_undulatebutton ); - - clear_inconsistent( surf_gravel_radiobutton ); - clear_inconsistent( surf_metal_radiobutton ); - clear_inconsistent( surf_stone_radiobutton ); - clear_inconsistent( surf_wood_radiobutton ); - - clear_inconsistent( content_solidbutton ); - clear_inconsistent( content_windowbutton ); - clear_inconsistent( content_illusbutton ); - clear_inconsistent( content_lavabutton ); - clear_inconsistent( content_slimebutton ); - clear_inconsistent( content_waterbutton ); - clear_inconsistent( content_mistbutton ); - clear_inconsistent( content_areaportalbutton ); - clear_inconsistent( content_playerclipbutton ); - clear_inconsistent( content_monsterclipbutton ); - clear_inconsistent( content_current0button ); - clear_inconsistent( content_current90button ); - clear_inconsistent( content_current180button ); - clear_inconsistent( content_current270button ); - clear_inconsistent( content_currentUPbutton ); - clear_inconsistent( content_currentDOWNbutton ); - clear_inconsistent( content_originbutton ); - clear_inconsistent( content_detailbutton ); - clear_inconsistent( content_ladderbutton ); - clear_inconsistent( content_camnoblockbutton ); -} - -void clear_all_buttons_and_values() -{ - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_lightbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_slickbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_skybutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_warpbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_trans33button ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_trans66button ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_flowingbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_nodrawbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_tallwallbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_alphatexbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_animspeedbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_undulatebutton ), FALSE); - -// surface_material_inconsistant = TRUE; - - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_gravel_radiobutton ), FALSE); - set_inconsistent(surf_gravel_radiobutton); - - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_metal_radiobutton ), FALSE); - set_inconsistent(surf_metal_radiobutton); - - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_stone_radiobutton ), FALSE); - set_inconsistent(surf_stone_radiobutton); - - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_wood_radiobutton ), FALSE); - set_inconsistent(surf_wood_radiobutton); - - gtk_entry_set_text( (GtkEntry *)surf_value_entry, ""); - - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_solidbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_windowbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_illusbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_lavabutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_slimebutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_waterbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_mistbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_areaportalbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_playerclipbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_monsterclipbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_current0button ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_current90button ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_current180button ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_current270button ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_currentUPbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_currentDOWNbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_originbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_detailbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_ladderbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_camnoblockbutton ), FALSE); - -} - -void SetFlagButtons_Heretic2(texdef_to_face_t *texdef_face_list, bool b_isListEmpty) -{ - int i; - int contents = 0; - int flags = 0; - int value = 0; - int diff_contents = 0; - int diff_flags = 0; - gboolean diff_value = FALSE; - char tex_buff[11]; - texdef_t* tmp_texdef; - texdef_to_face_t* temp_texdef_face_list; - gboolean surface_which_material_inconsistant[4]; - int surface_iterator; - - setup_buttons = TRUE; - working_surface_flags = 0; - surface_mask = 0; - working_content_flags = 0; - content_mask = 0; - working_value = 0; - surface_material_inconsistant = FALSE; - surface_which_material_inconsistant[0] = FALSE; - surface_which_material_inconsistant[1] = FALSE; - surface_which_material_inconsistant[2] = FALSE; - surface_which_material_inconsistant[3] = FALSE; - - if(!b_isListEmpty) - { - tmp_texdef = &texdef_face_list->texdef; - contents = tmp_texdef->contents; - flags = tmp_texdef->flags; - value = tmp_texdef->value; - - surface_iterator = (tmp_texdef->flags & ~HERETIC2_SURF_MATERIAL_MASK) >> 24; // Inconsistant Material? - surface_which_material_inconsistant[surface_iterator] = TRUE; - - for (temp_texdef_face_list = texdef_face_list->next; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = &temp_texdef_face_list->texdef; - diff_contents |= contents ^ tmp_texdef->contents; // Figure out which buttons are inconsistent - diff_flags |= flags ^ tmp_texdef->flags; - if (tmp_texdef->value != value) - diff_value = TRUE; - - surface_iterator = (tmp_texdef->flags & ~HERETIC2_SURF_MATERIAL_MASK) >> 24; // Inconsistant Material? - surface_which_material_inconsistant[surface_iterator] = TRUE; - - Sys_Printf("Diff_Flags: %d\t Surf_Iter: %d\n",diff_flags, surface_iterator); - - } - } - - - clear_all_inconsistent(); - - // If no faces/brushes are selected, clear everything and bail - if(b_isListEmpty) - { - clear_all_buttons_and_values(); - setup_buttons = FALSE; - return; - } - - // Set surface buttons to reflect brush/face flags, contents, and values - if(diff_flags & HERETIC2_SURF_LIGHT) - set_inconsistent(surface_lightbutton); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (surface_lightbutton), (flags & HERETIC2_SURF_LIGHT)); - - if(diff_flags & HERETIC2_SURF_SLICK) - set_inconsistent(surface_slickbutton); - else if(flags & HERETIC2_SURF_SLICK) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_slickbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_slickbutton ), FALSE); - - if(diff_flags & HERETIC2_SURF_SKY) - set_inconsistent(surface_skybutton); - else if(flags & HERETIC2_SURF_SKY) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skybutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skybutton ), FALSE); - - if(diff_flags & HERETIC2_SURF_WARP) - set_inconsistent(surface_warpbutton); - else if(flags & HERETIC2_SURF_WARP) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_warpbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_warpbutton ), FALSE); - - if(diff_flags & HERETIC2_SURF_TRANS33) - set_inconsistent(surface_trans33button); - else if(flags & HERETIC2_SURF_TRANS33) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans33button ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans33button ), FALSE); - - if(diff_flags & HERETIC2_SURF_TRANS66) - set_inconsistent(surface_trans66button); - else if(flags & HERETIC2_SURF_TRANS66) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans66button ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans66button ), FALSE); - - if(diff_flags & HERETIC2_SURF_FLOWING) - set_inconsistent(surface_flowingbutton); - else if(flags & HERETIC2_SURF_FLOWING) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_flowingbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_flowingbutton ), FALSE); - - if(diff_flags & HERETIC2_SURF_NODRAW) - set_inconsistent(surface_nodrawbutton); - else if(flags & HERETIC2_SURF_NODRAW) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_nodrawbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_nodrawbutton ), FALSE); - - if(diff_flags & HERETIC2_SURF_TALL_WALL) - set_inconsistent(surface_tallwallbutton); - else if(flags & HERETIC2_SURF_TALL_WALL) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_tallwallbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_tallwallbutton ), FALSE); - - if(diff_flags & HERETIC2_SURF_ALPHA_TEXTURE) - set_inconsistent(surface_alphatexbutton); - else if(flags & HERETIC2_SURF_ALPHA_TEXTURE) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_alphatexbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_alphatexbutton ), FALSE); - - if(diff_flags & HERETIC2_SURF_ANIMSPEED) - set_inconsistent(surface_animspeedbutton); - else if(flags & HERETIC2_SURF_ANIMSPEED) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_animspeedbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_animspeedbutton ), FALSE); - - if(diff_flags & HERETIC2_SURF_UNDULATE) - set_inconsistent(surface_undulatebutton); - else if(flags & HERETIC2_SURF_UNDULATE) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_undulatebutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_undulatebutton ), FALSE); - - if(diff_flags & ~HERETIC2_SURF_MATERIAL_MASK) - { - Sys_Printf("--> %d\n", (diff_flags & ~HERETIC2_SURF_MATERIAL_MASK) ); - Sys_Printf("%d\t%d\t%d\t%d\n", surface_which_material_inconsistant[0], surface_which_material_inconsistant[1], surface_which_material_inconsistant[2], surface_which_material_inconsistant[3]); - - if (surface_which_material_inconsistant[0]) - { - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_gravel_radiobutton ), FALSE); - surface_material_inconsistant = TRUE; - set_inconsistent(surf_gravel_radiobutton); - } - if (surface_which_material_inconsistant[1]) - { - //if (!surface_material_inconsistant) - //{ - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_metal_radiobutton ), FALSE); - surface_material_inconsistant = TRUE; - //} - set_inconsistent(surf_metal_radiobutton); - } - if (surface_which_material_inconsistant[2]) - { - //if (!surface_material_inconsistant) - //{ - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_stone_radiobutton ), FALSE); - surface_material_inconsistant = TRUE; - //} - set_inconsistent(surf_stone_radiobutton); - } - if (surface_which_material_inconsistant[3]) - { - //if (!surface_material_inconsistant) - //{ - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_wood_radiobutton ), FALSE); - surface_material_inconsistant = TRUE; - //} - set_inconsistent(surf_wood_radiobutton); - } - } - else - { - if(flags & ~HERETIC2_SURF_MATERIAL_MASK) - { - surface_iterator = (flags & ~HERETIC2_SURF_MATERIAL_MASK) >> 24; - if( surface_iterator == 1) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_metal_radiobutton ), TRUE); - else if(surface_iterator == 2) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_stone_radiobutton ), TRUE); - else if(surface_iterator == 3) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_wood_radiobutton ), TRUE); - } - else - { - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_gravel_radiobutton ), TRUE); - } - } - - // Set content buttons to reflect brush values - if(diff_contents & HERETIC2_CONTENTS_SOLID) - set_inconsistent(content_solidbutton); - else if(contents & HERETIC2_CONTENTS_SOLID) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_solidbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_solidbutton ), FALSE); - - if(diff_contents & HERETIC2_CONTENTS_WINDOW) - set_inconsistent(content_windowbutton); - else if(contents & HERETIC2_CONTENTS_WINDOW) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_windowbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_windowbutton ), FALSE); - - if(diff_contents & HERETIC2_CONTENTS_ILLUSIONARY) - set_inconsistent(content_illusbutton); - else if(contents & HERETIC2_CONTENTS_ILLUSIONARY) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_illusbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_illusbutton ), FALSE); - - if(diff_contents & HERETIC2_CONTENTS_LAVA) - set_inconsistent(content_lavabutton); - else if(contents & HERETIC2_CONTENTS_LAVA) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_lavabutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_lavabutton ), FALSE); - - if(diff_contents & HERETIC2_CONTENTS_SLIME) - set_inconsistent(content_slimebutton); - else if(contents & HERETIC2_CONTENTS_SLIME) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_slimebutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_slimebutton ), FALSE); - - if(diff_contents & HERETIC2_CONTENTS_WATER) - set_inconsistent(content_waterbutton); - else if(contents & HERETIC2_CONTENTS_WATER) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_waterbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_waterbutton ), FALSE); - - if(diff_contents & HERETIC2_CONTENTS_MIST) - set_inconsistent(content_mistbutton); - else if(contents & HERETIC2_CONTENTS_MIST) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_mistbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_mistbutton ), FALSE); - - if(diff_contents & HERETIC2_CONTENTS_AREAPORTAL) - set_inconsistent(content_areaportalbutton); - else if(contents & HERETIC2_CONTENTS_AREAPORTAL) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_areaportalbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_areaportalbutton ), FALSE); - - if(diff_contents & HERETIC2_CONTENTS_PLAYERCLIP) - set_inconsistent(content_playerclipbutton); - else if(contents & HERETIC2_CONTENTS_PLAYERCLIP) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_playerclipbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_playerclipbutton ), FALSE); - - if(diff_contents & HERETIC2_CONTENTS_MONSTERCLIP) - set_inconsistent(content_monsterclipbutton); - else if(contents & HERETIC2_CONTENTS_MONSTERCLIP) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_monsterclipbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_monsterclipbutton ), FALSE); - - if(diff_contents & HERETIC2_CONTENTS_CURRENT_0) - set_inconsistent(content_current0button); - else if(contents & HERETIC2_CONTENTS_CURRENT_0) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current0button ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current0button ), FALSE); - - if(diff_contents & HERETIC2_CONTENTS_CURRENT_90) - set_inconsistent(content_current90button); - else if(contents & HERETIC2_CONTENTS_CURRENT_90) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current90button ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current90button ), FALSE); - - if(diff_contents & HERETIC2_CONTENTS_CURRENT_180) - set_inconsistent(content_current180button); - else if(contents & HERETIC2_CONTENTS_CURRENT_180) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current180button ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current180button ), FALSE); - - if(diff_contents & HERETIC2_CONTENTS_CURRENT_270) - set_inconsistent(content_current270button); - else if(contents & HERETIC2_CONTENTS_CURRENT_270) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current270button ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current270button ), FALSE); - - if(diff_contents & HERETIC2_CONTENTS_CURRENT_UP) - set_inconsistent(content_currentUPbutton); - else if(contents & HERETIC2_CONTENTS_CURRENT_UP) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentUPbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentUPbutton ), FALSE); - - if(diff_contents & HERETIC2_CONTENTS_CURRENT_DOWN) - set_inconsistent(content_currentDOWNbutton); - else if(contents & HERETIC2_CONTENTS_CURRENT_DOWN) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentDOWNbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentDOWNbutton ), FALSE); - - if(diff_contents & HERETIC2_CONTENTS_ORIGIN) - set_inconsistent(content_originbutton); - else if(contents & HERETIC2_CONTENTS_ORIGIN) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_originbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_originbutton ), FALSE); - - if(diff_contents & HERETIC2_CONTENTS_DETAIL) - set_inconsistent(content_detailbutton); - else if(contents & HERETIC2_CONTENTS_DETAIL) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_detailbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_detailbutton ), FALSE); - - if(diff_contents & HERETIC2_CONTENTS_LADDER) - set_inconsistent(content_ladderbutton); - else if(contents & HERETIC2_CONTENTS_LADDER) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_ladderbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_ladderbutton ), FALSE); - - if(diff_contents & HERETIC2_CONTENTS_CAMERANOBLOCK) - set_inconsistent(content_camnoblockbutton); - else if(contents & HERETIC2_CONTENTS_CAMERANOBLOCK) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_camnoblockbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_camnoblockbutton ), FALSE); - - // Set Value - if(diff_value) - gtk_entry_set_text( (GtkEntry *)surf_value_entry, ""); - else - { - working_value = value; - sprintf( tex_buff, "%d", value); - gtk_entry_set_text( (GtkEntry *)surf_value_entry, tex_buff); - } - - setup_buttons = FALSE; -} - -void SetChangeInFlags_Face_Heretic2 (texdef_to_face_t *texdef_face_list) -{ - texdef_to_face_t *temp_texdef_face_list; - texdef_t *tmp_texdef; - - for (temp_texdef_face_list = texdef_face_list; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = &temp_texdef_face_list->texdef; - tmp_texdef->flags = (tmp_texdef->flags & ~surface_mask) | working_surface_flags; - tmp_texdef->contents = (tmp_texdef->contents & ~content_mask) | working_content_flags; - tmp_texdef->value = working_value; - Sys_Printf("content_flag: %d content_mask: %d\n",working_content_flags,content_mask); - Sys_Printf("content: %d\n",tmp_texdef->contents); - } -} - -inline void change_surfaceflag (GtkWidget *togglebutton, int sur_flag) // For Material -{ - if (!setup_buttons) // If we're setting up the buttons, we really don't need to - { // set flags that are already set - if (surface_material_inconsistant) - { - clear_inconsistent( surf_gravel_radiobutton ); - clear_inconsistent( surf_metal_radiobutton ); - clear_inconsistent( surf_stone_radiobutton ); - clear_inconsistent( surf_wood_radiobutton ); - } - surface_mask |= ~HERETIC2_SURF_MATERIAL_MASK; - working_surface_flags = (working_surface_flags & HERETIC2_SURF_MATERIAL_MASK) | sur_flag; - } -} - -inline void change_material (GtkWidget *togglebutton) -{ - if (!setup_buttons) // If we're setting up the buttons, we really don't need to - { // set flags that are already set - if (surface_material_inconsistant) - { - clear_inconsistent( surf_gravel_radiobutton ); - clear_inconsistent( surf_metal_radiobutton ); - clear_inconsistent( surf_stone_radiobutton ); - clear_inconsistent( surf_wood_radiobutton ); - } - if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_gravel_radiobutton)) ) - { - surface_mask |= ~HERETIC2_SURF_MATERIAL_MASK; - working_surface_flags = (working_surface_flags & HERETIC2_SURF_MATERIAL_MASK) | HERETIC2_SURF_TYPE_GRAVEL; - } - else if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_metal_radiobutton)) ) - { - surface_mask |= ~HERETIC2_SURF_MATERIAL_MASK; - working_surface_flags = (working_surface_flags & HERETIC2_SURF_MATERIAL_MASK) | HERETIC2_SURF_TYPE_METAL; - } - else if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_stone_radiobutton)) ) - { - surface_mask |= ~HERETIC2_SURF_MATERIAL_MASK; - working_surface_flags = (working_surface_flags & HERETIC2_SURF_MATERIAL_MASK) | HERETIC2_SURF_TYPE_STONE; - } - else if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_wood_radiobutton)) ) - { - surface_mask |= ~HERETIC2_SURF_MATERIAL_MASK; - working_surface_flags = (working_surface_flags & HERETIC2_SURF_MATERIAL_MASK) | HERETIC2_SURF_TYPE_WOOD; - } - } -} - -inline void change_surfaceflag (GtkWidget *togglebutton, int sur_flag, gboolean change_flag_to) -{ - - if (!setup_buttons) // If we're setting up the buttons, we really don't need to - { // set flags that are already set - if (gtk_toggle_button_get_inconsistent(GTK_TOGGLE_BUTTON (togglebutton))) // Clear out inconsistent, if set - clear_inconsistent(GTK_WIDGET (togglebutton)); - - surface_mask |= sur_flag; - - if (change_flag_to) - working_surface_flags |= sur_flag; - else - working_surface_flags &= ~sur_flag; - } -} - -inline void change_contentflag (GtkWidget *togglebutton, int content_flag, gboolean change_flag_to) -{ - - if ( (!setup_buttons) ) // If we're setting up the buttons, we really don't need to - { // set flags that are already set - - if (gtk_toggle_button_get_inconsistent(GTK_TOGGLE_BUTTON (togglebutton))) - clear_inconsistent(togglebutton); - //if (g_ptrSelectedFaces.GetSize() == 0) // Only changing content flags on whole brushes, not faces. - //{ - content_mask |= content_flag; - - if (change_flag_to) - working_content_flags |= content_flag; - else - working_content_flags &= ~content_flag; - //} - } -} - -// Surface Flags Callbacks -void -on_surface_lightbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_surfaceflag(surface_lightbutton, HERETIC2_SURF_LIGHT, (GTK_TOGGLE_BUTTON (surface_lightbutton)->active)); -} - - -void -on_surface_slickbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_surfaceflag(surface_slickbutton, HERETIC2_SURF_SLICK, (GTK_TOGGLE_BUTTON (surface_slickbutton)->active)); -} - - -void -on_surface_skybutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_surfaceflag(surface_skybutton, HERETIC2_SURF_SKY, (GTK_TOGGLE_BUTTON (surface_skybutton)->active)); -} - - -void -on_surface_warpbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_surfaceflag(surface_warpbutton, HERETIC2_SURF_WARP, (GTK_TOGGLE_BUTTON (surface_warpbutton)->active)); -} - - -void -on_surface_trans33button_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_surfaceflag(surface_trans33button, HERETIC2_SURF_TRANS33, (GTK_TOGGLE_BUTTON (surface_trans33button)->active)); -} - - -void -on_surface_trans66button_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_surfaceflag(surface_trans66button, HERETIC2_SURF_TRANS66, (GTK_TOGGLE_BUTTON (surface_trans66button)->active)); -} - - -void -on_surface_flowingbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_surfaceflag(surface_flowingbutton, HERETIC2_SURF_FLOWING, (GTK_TOGGLE_BUTTON (surface_flowingbutton)->active)); -} - - -void -on_surface_nodrawbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_surfaceflag(surface_nodrawbutton, HERETIC2_SURF_NODRAW, (GTK_TOGGLE_BUTTON (surface_nodrawbutton)->active)); -} - - -void -on_surface_tallwallbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_surfaceflag(surface_tallwallbutton, HERETIC2_SURF_TALL_WALL, (GTK_TOGGLE_BUTTON (surface_tallwallbutton)->active)); -} - - -void -on_surface_alphatexbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_surfaceflag(surface_alphatexbutton, HERETIC2_SURF_ALPHA_TEXTURE, (GTK_TOGGLE_BUTTON (surface_alphatexbutton)->active)); -} - - -void -on_surface_animspeedbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_surfaceflag(surface_animspeedbutton, HERETIC2_SURF_ANIMSPEED, (GTK_TOGGLE_BUTTON (surface_animspeedbutton)->active)); -} - - -void -on_surface_undulatebutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_surfaceflag(surface_undulatebutton, HERETIC2_SURF_UNDULATE, (GTK_TOGGLE_BUTTON (surface_undulatebutton)->active)); -} - - -void -on_surf_gravel_radiobutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_gravel_radiobutton))) - change_material(GTK_WIDGET(togglebutton)); -} - -void -on_surf_metal_radiobutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_metal_radiobutton))) - change_material(GTK_WIDGET(togglebutton)); -} - -void -on_surf_stone_radiobutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_stone_radiobutton))) - change_material(GTK_WIDGET(togglebutton)); -} - -void -on_surf_wood_radiobutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_wood_radiobutton))) - change_material(GTK_WIDGET(togglebutton)); -} - -// Content Flags Callbacks -void -on_content_solidbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_solidbutton, HERETIC2_CONTENTS_SOLID, (GTK_TOGGLE_BUTTON (content_solidbutton)->active)); -} - - -void -on_content_windowbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_windowbutton, HERETIC2_CONTENTS_WINDOW, (GTK_TOGGLE_BUTTON (content_windowbutton)->active)); -} - - -void -on_content_illusbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_illusbutton, HERETIC2_CONTENTS_ILLUSIONARY, (GTK_TOGGLE_BUTTON (content_illusbutton)->active)); -} - - -void -on_content_lavabutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_lavabutton, HERETIC2_CONTENTS_LAVA, (GTK_TOGGLE_BUTTON (content_lavabutton)->active)); -} - - -void -on_content_slimebutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_slimebutton, HERETIC2_CONTENTS_SLIME, (GTK_TOGGLE_BUTTON (content_slimebutton)->active)); -} - - -void -on_content_waterbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_waterbutton, HERETIC2_CONTENTS_WATER, (GTK_TOGGLE_BUTTON (content_waterbutton)->active)); -} - - -void -on_content_mistbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_mistbutton, HERETIC2_CONTENTS_MIST, (GTK_TOGGLE_BUTTON (content_mistbutton)->active)); -} - - -void -on_content_areaportalbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_areaportalbutton, HERETIC2_CONTENTS_AREAPORTAL, (GTK_TOGGLE_BUTTON (content_areaportalbutton)->active)); -} - - -void -on_content_playerclipbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_playerclipbutton, HERETIC2_CONTENTS_PLAYERCLIP, (GTK_TOGGLE_BUTTON (content_playerclipbutton)->active)); -} - - -void -on_content_monsterclipbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_monsterclipbutton, HERETIC2_CONTENTS_MONSTERCLIP, (GTK_TOGGLE_BUTTON (content_monsterclipbutton)->active)); -} - - -void -on_content_current0button_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_current0button, HERETIC2_CONTENTS_CURRENT_0, (GTK_TOGGLE_BUTTON (content_current0button)->active)); -} - - -void -on_content_current90button_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_current90button, HERETIC2_CONTENTS_CURRENT_90, (GTK_TOGGLE_BUTTON (content_current90button)->active)); -} - - -void -on_content_current180button_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_current180button, HERETIC2_CONTENTS_CURRENT_180, (GTK_TOGGLE_BUTTON (content_current180button)->active)); -} - - -void -on_content_current270button_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_current270button, HERETIC2_CONTENTS_CURRENT_270, (GTK_TOGGLE_BUTTON (content_current270button)->active)); -} - - -void -on_content_currentUPbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_currentUPbutton, HERETIC2_CONTENTS_CURRENT_UP, (GTK_TOGGLE_BUTTON (content_currentUPbutton)->active)); -} - - -void -on_content_currentDOWNbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_currentDOWNbutton, HERETIC2_CONTENTS_CURRENT_DOWN, (GTK_TOGGLE_BUTTON (content_currentDOWNbutton)->active)); -} - - -void -on_content_originbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_originbutton, HERETIC2_CONTENTS_ORIGIN, (GTK_TOGGLE_BUTTON (content_originbutton)->active)); -} - - -void -on_content_detailbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_detailbutton, HERETIC2_CONTENTS_DETAIL, (GTK_TOGGLE_BUTTON (content_detailbutton)->active)); -} - - -void -on_content_ladderbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_ladderbutton, HERETIC2_CONTENTS_LADDER, (GTK_TOGGLE_BUTTON (content_ladderbutton)->active)); -} - - -void -on_content_camnoblockbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_camnoblockbutton, HERETIC2_CONTENTS_CAMERANOBLOCK, (GTK_TOGGLE_BUTTON (content_camnoblockbutton)->active)); -} - -// Value Entry Callback -void -on_surf_value_entry_changed (GtkEditable *editable, - gpointer user_data) -{ - if ( (!setup_buttons) ) // If we're setting up the buttons, don't change value - working_value = atoi( gtk_entry_get_text( (GtkEntry*)editable) ); -} - -void -on_surf_value_entry_insert_text (GtkEditable *editable, - gchar *new_text, - gint new_text_length, - gint *position, - gpointer user_data) -{ - int i, count=0; - gchar *result; - int entry_value; - texdef_t *pt; - brush_t *b; - face_t *f; - - // Limit input to digits, throwing out anything else - // Modified from Gtk FAQ for text filtering of GtkEntry - result = g_new (gchar, new_text_length); - - for (i=0; i < new_text_length; i++) { - if (!isdigit(new_text[i])) - continue; - result[count++] = new_text[i]; - } - - if (count > 0) { - gtk_signal_handler_block_by_func (GTK_OBJECT (editable), - GTK_SIGNAL_FUNC (on_surf_value_entry_insert_text), - user_data); - gtk_editable_insert_text (editable, result, count, position); - gtk_signal_handler_unblock_by_func (GTK_OBJECT (editable), - GTK_SIGNAL_FUNC (on_surf_value_entry_insert_text), - user_data); - } - gtk_signal_emit_stop_by_name (GTK_OBJECT (editable), "insert_text"); - - g_free (result); -} - -#define HERETIC2_FLAG_BUTTON_BORDER 3 - -GtkWidget* Create_Heretic2FlagsDialog (GtkWidget* surfacedialog_widget) -{ - GtkWidget *frame1; - GtkWidget *notebook1; - GtkWidget *vbox3; - GtkWidget *table1; - GtkWidget *frame2; - GtkWidget *hbox4; - GtkWidget *label4; - GtkWidget *vbox4; - GtkWidget *table3; - GtkWidget *label5; - - GtkWidget *hbox1; - GtkWidget *hbox2; - GtkWidget *label2; - GtkWidget *table2; - GtkWidget *label3; - - - frame1 = gtk_frame_new ("Brush/Face Flags"); - gtk_widget_show (frame1); - gtk_container_add (GTK_CONTAINER (surfacedialog_widget), frame1); - - notebook1 = gtk_notebook_new (); - gtk_widget_show (notebook1); - gtk_container_add (GTK_CONTAINER (frame1), notebook1); - - vbox3 = gtk_vbox_new (FALSE, 0); - gtk_widget_show (vbox3); - gtk_container_add (GTK_CONTAINER (notebook1), vbox3); - - table1 = gtk_table_new (3, 4, TRUE); - gtk_widget_show (table1); - gtk_box_pack_start (GTK_BOX (vbox3), table1, TRUE, TRUE, 0); - - surface_lightbutton = gtk_toggle_button_new_with_mnemonic ("Light"); - gtk_widget_show (surface_lightbutton); - gtk_table_attach (GTK_TABLE (table1), surface_lightbutton, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - surface_slickbutton = gtk_toggle_button_new_with_mnemonic ("Slick"); - gtk_widget_show (surface_slickbutton); - gtk_table_attach (GTK_TABLE (table1), surface_slickbutton, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - surface_skybutton = gtk_toggle_button_new_with_mnemonic ("Sky"); - gtk_widget_show (surface_skybutton); - gtk_table_attach (GTK_TABLE (table1), surface_skybutton, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - surface_warpbutton = gtk_toggle_button_new_with_mnemonic ("Warp"); - gtk_widget_show (surface_warpbutton); - gtk_table_attach (GTK_TABLE (table1), surface_warpbutton, 3, 4, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - surface_trans33button = gtk_toggle_button_new_with_mnemonic ("Trans33"); - gtk_widget_show (surface_trans33button); - gtk_table_attach (GTK_TABLE (table1), surface_trans33button, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - surface_trans66button = gtk_toggle_button_new_with_mnemonic ("Trans66"); - gtk_widget_show (surface_trans66button); - gtk_table_attach (GTK_TABLE (table1), surface_trans66button, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - surface_flowingbutton = gtk_toggle_button_new_with_mnemonic ("Flowing"); - gtk_widget_show (surface_flowingbutton); - gtk_table_attach (GTK_TABLE (table1), surface_flowingbutton, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - surface_nodrawbutton = gtk_toggle_button_new_with_mnemonic ("NoDraw"); - gtk_widget_show (surface_nodrawbutton); - gtk_table_attach (GTK_TABLE (table1), surface_nodrawbutton, 3, 4, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - surface_tallwallbutton = gtk_toggle_button_new_with_mnemonic ("TallWall"); - gtk_widget_show (surface_tallwallbutton); - gtk_table_attach (GTK_TABLE (table1), surface_tallwallbutton, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - surface_alphatexbutton = gtk_toggle_button_new_with_mnemonic ("AlphaTex"); - gtk_widget_show (surface_alphatexbutton); - gtk_table_attach (GTK_TABLE (table1), surface_alphatexbutton, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - surface_animspeedbutton = gtk_toggle_button_new_with_mnemonic ("AnimSpeed"); - gtk_widget_show (surface_animspeedbutton); - gtk_table_attach (GTK_TABLE (table1), surface_animspeedbutton, 2, 3, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - surface_undulatebutton = gtk_toggle_button_new_with_mnemonic ("Undulate"); - gtk_widget_show (surface_undulatebutton); - gtk_table_attach (GTK_TABLE (table1), surface_undulatebutton, 3, 4, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - frame2 = gtk_frame_new (NULL); - gtk_widget_show (frame2); - gtk_box_pack_start (GTK_BOX (vbox3), frame2, FALSE, FALSE, 0); - gtk_frame_set_shadow_type (GTK_FRAME (frame2), GTK_SHADOW_ETCHED_OUT); - gtk_container_set_border_width (GTK_CONTAINER (frame2), 4); - - hbox4 = gtk_hbox_new (FALSE, 0); - gtk_widget_show (hbox4); - gtk_container_add (GTK_CONTAINER (frame2), hbox4); - - surf_gravel_radiobutton = gtk_radio_button_new_with_mnemonic (NULL, "Gravel"); - gtk_widget_show (surf_gravel_radiobutton); - gtk_box_pack_start (GTK_BOX (hbox4), surf_gravel_radiobutton, TRUE, FALSE, 0); - - surf_metal_radiobutton = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON(surf_gravel_radiobutton), "Metal"); - gtk_widget_show (surf_metal_radiobutton); - gtk_box_pack_start (GTK_BOX (hbox4), surf_metal_radiobutton, TRUE, FALSE, 0); - - surf_stone_radiobutton = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON(surf_metal_radiobutton), "Stone"); - gtk_widget_show (surf_stone_radiobutton); - gtk_box_pack_start (GTK_BOX (hbox4), surf_stone_radiobutton, TRUE, FALSE, 0); - - surf_wood_radiobutton = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON(surf_stone_radiobutton), "Wood"); - gtk_widget_show (surf_wood_radiobutton); - gtk_box_pack_start (GTK_BOX (hbox4), surf_wood_radiobutton, TRUE, FALSE, 0); - - label4 = gtk_label_new ("Material"); - gtk_widget_show (label4); - gtk_frame_set_label_widget (GTK_FRAME (frame2), label4); - gtk_label_set_justify (GTK_LABEL (label4), GTK_JUSTIFY_LEFT); - - table3 = gtk_table_new (1, 4, FALSE); - gtk_widget_show (table3); - gtk_box_pack_start (GTK_BOX (vbox3), table3, FALSE, FALSE, 0); - gtk_container_set_border_width (GTK_CONTAINER (table3), 3); - - hbox1 = gtk_hbox_new (FALSE, 0); - gtk_widget_show (hbox1); - gtk_table_attach (GTK_TABLE (table3), hbox1, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label5 = gtk_label_new ("Value: "); - gtk_widget_show (label5); - gtk_table_attach (GTK_TABLE (table3), label5, 1, 2, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label5), 0, 0); - gtk_label_set_justify (GTK_LABEL (label5), GTK_JUSTIFY_RIGHT); - - surf_value_entry = gtk_entry_new (); - gtk_widget_show (surf_value_entry); - gtk_table_attach (GTK_TABLE (table3), surf_value_entry, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - hbox2 = gtk_hbox_new (FALSE, 0); - gtk_widget_show (hbox2); - gtk_table_attach (GTK_TABLE (table3), hbox2, 3, 4, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label2 = gtk_label_new ("Surface Flags"); - gtk_widget_show (label2); - gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 0), label2); - gtk_label_set_justify (GTK_LABEL (label2), GTK_JUSTIFY_LEFT); - - table2 = gtk_table_new (5, 4, TRUE); - gtk_widget_show (table2); - gtk_container_add (GTK_CONTAINER (notebook1), table2); - - content_solidbutton = gtk_toggle_button_new_with_mnemonic ("Solid"); - gtk_widget_show (content_solidbutton); - gtk_table_attach (GTK_TABLE (table2), content_solidbutton, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - content_windowbutton = gtk_toggle_button_new_with_mnemonic ("Window"); - gtk_widget_show (content_windowbutton); - gtk_table_attach (GTK_TABLE (table2), content_windowbutton, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - content_illusbutton = gtk_toggle_button_new_with_mnemonic ("Illusion"); - gtk_widget_show (content_illusbutton); - gtk_table_attach (GTK_TABLE (table2), content_illusbutton, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - content_lavabutton = gtk_toggle_button_new_with_mnemonic ("Lava"); - gtk_widget_show (content_lavabutton); - gtk_table_attach (GTK_TABLE (table2), content_lavabutton, 3, 4, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - content_slimebutton = gtk_toggle_button_new_with_mnemonic ("Slime"); - gtk_widget_show (content_slimebutton); - gtk_table_attach (GTK_TABLE (table2), content_slimebutton, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - content_waterbutton = gtk_toggle_button_new_with_mnemonic ("Water"); - gtk_widget_show (content_waterbutton); - gtk_table_attach (GTK_TABLE (table2), content_waterbutton, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - content_mistbutton = gtk_toggle_button_new_with_mnemonic ("Mist"); - gtk_widget_show (content_mistbutton); - gtk_table_attach (GTK_TABLE (table2), content_mistbutton, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - content_areaportalbutton = gtk_toggle_button_new_with_mnemonic ("AreaPortal"); - gtk_widget_show (content_areaportalbutton); - gtk_table_attach (GTK_TABLE (table2), content_areaportalbutton, 3, 4, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - content_playerclipbutton = gtk_toggle_button_new_with_mnemonic ("PlayerClip"); - gtk_widget_show (content_playerclipbutton); - gtk_table_attach (GTK_TABLE (table2), content_playerclipbutton, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - content_monsterclipbutton = gtk_toggle_button_new_with_mnemonic ("MonsterClip"); - gtk_widget_show (content_monsterclipbutton); - gtk_table_attach (GTK_TABLE (table2), content_monsterclipbutton, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - content_current0button = gtk_toggle_button_new_with_mnemonic ("Current 0"); - gtk_widget_show (content_current0button); - gtk_table_attach (GTK_TABLE (table2), content_current0button, 2, 3, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - content_current90button = gtk_toggle_button_new_with_mnemonic ("Current 90"); - gtk_widget_show (content_current90button); - gtk_table_attach (GTK_TABLE (table2), content_current90button, 3, 4, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - content_current180button = gtk_toggle_button_new_with_mnemonic ("Current 180"); - gtk_widget_show (content_current180button); - gtk_table_attach (GTK_TABLE (table2), content_current180button, 0, 1, 3, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - content_current270button = gtk_toggle_button_new_with_mnemonic ("Current 270"); - gtk_widget_show (content_current270button); - gtk_table_attach (GTK_TABLE (table2), content_current270button, 1, 2, 3, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - content_currentUPbutton = gtk_toggle_button_new_with_mnemonic ("Current UP"); - gtk_widget_show (content_currentUPbutton); - gtk_table_attach (GTK_TABLE (table2), content_currentUPbutton, 2, 3, 3, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - content_currentDOWNbutton = gtk_toggle_button_new_with_mnemonic ("Current DOWN"); - gtk_widget_show (content_currentDOWNbutton); - gtk_table_attach (GTK_TABLE (table2), content_currentDOWNbutton, 3, 4, 3, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - content_originbutton = gtk_toggle_button_new_with_mnemonic ("Origin"); - gtk_widget_show (content_originbutton); - gtk_table_attach (GTK_TABLE (table2), content_originbutton, 0, 1, 4, 5, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - content_detailbutton = gtk_toggle_button_new_with_mnemonic ("Detail"); - gtk_widget_show (content_detailbutton); - gtk_table_attach (GTK_TABLE (table2), content_detailbutton, 1, 2, 4, 5, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - content_ladderbutton = gtk_toggle_button_new_with_mnemonic ("Ladder"); - gtk_widget_show (content_ladderbutton); - gtk_table_attach (GTK_TABLE (table2), content_ladderbutton, 2, 3, 4, 5, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - content_camnoblockbutton = gtk_toggle_button_new_with_mnemonic ("Cam No Block"); - gtk_widget_show (content_camnoblockbutton); - gtk_table_attach (GTK_TABLE (table2), content_camnoblockbutton, 3, 4, 4, 5, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - label3 = gtk_label_new ("Content Flags"); - gtk_widget_show (label3); - gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 1), label3); - gtk_label_set_justify (GTK_LABEL (label3), GTK_JUSTIFY_LEFT); - - // Signal Connects - g_signal_connect ((gpointer) surface_lightbutton, "toggled", - G_CALLBACK (on_surface_lightbutton_toggled), - NULL); - g_signal_connect ((gpointer) surface_slickbutton, "toggled", - G_CALLBACK (on_surface_slickbutton_toggled), - NULL); - g_signal_connect ((gpointer) surface_skybutton, "toggled", - G_CALLBACK (on_surface_skybutton_toggled), - NULL); - g_signal_connect ((gpointer) surface_warpbutton, "toggled", - G_CALLBACK (on_surface_warpbutton_toggled), - NULL); - g_signal_connect ((gpointer) surface_trans33button, "toggled", - G_CALLBACK (on_surface_trans33button_toggled), - NULL); - g_signal_connect ((gpointer) surface_trans66button, "toggled", - G_CALLBACK (on_surface_trans66button_toggled), - NULL); - g_signal_connect ((gpointer) surface_flowingbutton, "toggled", - G_CALLBACK (on_surface_flowingbutton_toggled), - NULL); - g_signal_connect ((gpointer) surface_nodrawbutton, "toggled", - G_CALLBACK (on_surface_nodrawbutton_toggled), - NULL); - g_signal_connect ((gpointer) surface_tallwallbutton, "toggled", - G_CALLBACK (on_surface_tallwallbutton_toggled), - NULL); - g_signal_connect ((gpointer) surface_alphatexbutton, "toggled", - G_CALLBACK (on_surface_alphatexbutton_toggled), - NULL); - g_signal_connect ((gpointer) surface_animspeedbutton, "toggled", - G_CALLBACK (on_surface_animspeedbutton_toggled), - NULL); - g_signal_connect ((gpointer) surface_undulatebutton, "toggled", - G_CALLBACK (on_surface_undulatebutton_toggled), - NULL); - - g_signal_connect ((gpointer) surf_gravel_radiobutton, "toggled", - G_CALLBACK (on_surf_gravel_radiobutton_toggled), - NULL); - g_signal_connect ((gpointer) surf_metal_radiobutton, "toggled", - G_CALLBACK (on_surf_metal_radiobutton_toggled), - NULL); - g_signal_connect ((gpointer) surf_stone_radiobutton, "toggled", - G_CALLBACK (on_surf_stone_radiobutton_toggled), - NULL); - g_signal_connect ((gpointer) surf_wood_radiobutton, "toggled", - G_CALLBACK (on_surf_wood_radiobutton_toggled), - NULL); - - g_signal_connect ((gpointer) surf_value_entry, "changed", - G_CALLBACK (on_surf_value_entry_changed), - NULL); - g_signal_connect ((gpointer) surf_value_entry, "insert_text", - G_CALLBACK (on_surf_value_entry_insert_text), - NULL); - g_signal_connect ((gpointer) content_solidbutton, "toggled", - G_CALLBACK (on_content_solidbutton_toggled), - NULL); - g_signal_connect ((gpointer) content_windowbutton, "toggled", - G_CALLBACK (on_content_windowbutton_toggled), - NULL); - g_signal_connect ((gpointer) content_illusbutton, "toggled", - G_CALLBACK (on_content_illusbutton_toggled), - NULL); - g_signal_connect ((gpointer) content_lavabutton, "toggled", - G_CALLBACK (on_content_lavabutton_toggled), - NULL); - g_signal_connect ((gpointer) content_slimebutton, "toggled", - G_CALLBACK (on_content_slimebutton_toggled), - NULL); - g_signal_connect ((gpointer) content_waterbutton, "toggled", - G_CALLBACK (on_content_waterbutton_toggled), - NULL); - g_signal_connect ((gpointer) content_mistbutton, "toggled", - G_CALLBACK (on_content_mistbutton_toggled), - NULL); - g_signal_connect ((gpointer) content_areaportalbutton, "toggled", - G_CALLBACK (on_content_areaportalbutton_toggled), - NULL); - g_signal_connect ((gpointer) content_playerclipbutton, "toggled", - G_CALLBACK (on_content_playerclipbutton_toggled), - NULL); - g_signal_connect ((gpointer) content_monsterclipbutton, "toggled", - G_CALLBACK (on_content_monsterclipbutton_toggled), - NULL); - g_signal_connect ((gpointer) content_current0button, "toggled", - G_CALLBACK (on_content_current0button_toggled), - NULL); - g_signal_connect ((gpointer) content_current90button, "toggled", - G_CALLBACK (on_content_current90button_toggled), - NULL); - g_signal_connect ((gpointer) content_current180button, "toggled", - G_CALLBACK (on_content_current180button_toggled), - NULL); - g_signal_connect ((gpointer) content_current270button, "toggled", - G_CALLBACK (on_content_current270button_toggled), - NULL); - g_signal_connect ((gpointer) content_currentUPbutton, "toggled", - G_CALLBACK (on_content_currentUPbutton_toggled), - NULL); - g_signal_connect ((gpointer) content_currentDOWNbutton, "toggled", - G_CALLBACK (on_content_currentDOWNbutton_toggled), - NULL); - g_signal_connect ((gpointer) content_originbutton, "toggled", - G_CALLBACK (on_content_originbutton_toggled), - NULL); - g_signal_connect ((gpointer) content_detailbutton, "toggled", - G_CALLBACK (on_content_detailbutton_toggled), - NULL); - g_signal_connect ((gpointer) content_ladderbutton, "toggled", - G_CALLBACK (on_content_ladderbutton_toggled), - NULL); - g_signal_connect ((gpointer) content_camnoblockbutton, "toggled", - G_CALLBACK (on_content_camnoblockbutton_toggled), - NULL); - - - return frame1; -} - +/* +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 +*/ + +#include +#include + +#include "surfdlg_plugin.h" + +#include "surfaceflagsdialog_heretic2.h" + + GtkWidget *surface_lightbutton; + GtkWidget *surface_slickbutton; + GtkWidget *surface_skybutton; + GtkWidget *surface_warpbutton; + GtkWidget *surface_trans33button; + GtkWidget *surface_trans66button; + GtkWidget *surface_flowingbutton; + GtkWidget *surface_nodrawbutton; + GtkWidget *surface_tallwallbutton; + GtkWidget *surface_alphatexbutton; + GtkWidget *surface_animspeedbutton; + GtkWidget *surface_undulatebutton; + + GtkWidget *surf_gravel_radiobutton; + GSList *surf_gravel_radiobutton_group = NULL; + GtkWidget *surf_metal_radiobutton; + GtkWidget *surf_stone_radiobutton; + GtkWidget *surf_wood_radiobutton; + + GtkWidget *surf_value_entry; + + GtkWidget *notebook1; + + GtkWidget *content_solidbutton; + GtkWidget *content_windowbutton; + GtkWidget *content_illusbutton; + GtkWidget *content_lavabutton; + GtkWidget *content_slimebutton; + GtkWidget *content_waterbutton; + GtkWidget *content_mistbutton; + GtkWidget *content_areaportalbutton; + GtkWidget *content_playerclipbutton; + GtkWidget *content_monsterclipbutton; + GtkWidget *content_current0button; + GtkWidget *content_current90button; + GtkWidget *content_current180button; + GtkWidget *content_current270button; + GtkWidget *content_currentUPbutton; + GtkWidget *content_currentDOWNbutton; + GtkWidget *content_originbutton; + GtkWidget *content_detailbutton; + GtkWidget *content_ladderbutton; + GtkWidget *content_camnoblockbutton; + + + gboolean setup_buttons = TRUE; + + int working_surface_flags; + int surface_mask; + int working_content_flags; + int content_mask; + int working_value; + gboolean surface_material_inconsistant = FALSE; + +inline void set_inconsistent(GtkWidget *toggle_button) +{ + gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON (toggle_button), TRUE); +} + +inline void clear_inconsistent(GtkWidget *toggle_button) +{ + if ( gtk_toggle_button_get_inconsistent(GTK_TOGGLE_BUTTON (toggle_button)) ) + { + gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON (toggle_button), FALSE); + } + +} + +void clear_all_inconsistent(void) +{ + clear_inconsistent( surface_lightbutton ); + clear_inconsistent( surface_slickbutton ); + clear_inconsistent( surface_skybutton ); + clear_inconsistent( surface_warpbutton ); + clear_inconsistent( surface_trans33button ); + clear_inconsistent( surface_trans66button ); + clear_inconsistent( surface_flowingbutton ); + clear_inconsistent( surface_nodrawbutton ); + clear_inconsistent( surface_tallwallbutton ); + clear_inconsistent( surface_alphatexbutton ); + clear_inconsistent( surface_animspeedbutton ); + clear_inconsistent( surface_undulatebutton ); + + clear_inconsistent( surf_gravel_radiobutton ); + clear_inconsistent( surf_metal_radiobutton ); + clear_inconsistent( surf_stone_radiobutton ); + clear_inconsistent( surf_wood_radiobutton ); + + clear_inconsistent( content_solidbutton ); + clear_inconsistent( content_windowbutton ); + clear_inconsistent( content_illusbutton ); + clear_inconsistent( content_lavabutton ); + clear_inconsistent( content_slimebutton ); + clear_inconsistent( content_waterbutton ); + clear_inconsistent( content_mistbutton ); + clear_inconsistent( content_areaportalbutton ); + clear_inconsistent( content_playerclipbutton ); + clear_inconsistent( content_monsterclipbutton ); + clear_inconsistent( content_current0button ); + clear_inconsistent( content_current90button ); + clear_inconsistent( content_current180button ); + clear_inconsistent( content_current270button ); + clear_inconsistent( content_currentUPbutton ); + clear_inconsistent( content_currentDOWNbutton ); + clear_inconsistent( content_originbutton ); + clear_inconsistent( content_detailbutton ); + clear_inconsistent( content_ladderbutton ); + clear_inconsistent( content_camnoblockbutton ); +} + +void clear_all_buttons_and_values() +{ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_lightbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_slickbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_skybutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_warpbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_trans33button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_trans66button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_flowingbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_nodrawbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_tallwallbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_alphatexbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_animspeedbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( surface_undulatebutton ), FALSE); + +// surface_material_inconsistant = TRUE; + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_gravel_radiobutton ), FALSE); + set_inconsistent(surf_gravel_radiobutton); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_metal_radiobutton ), FALSE); + set_inconsistent(surf_metal_radiobutton); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_stone_radiobutton ), FALSE); + set_inconsistent(surf_stone_radiobutton); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_wood_radiobutton ), FALSE); + set_inconsistent(surf_wood_radiobutton); + + gtk_entry_set_text( (GtkEntry *)surf_value_entry, ""); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_solidbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_windowbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_illusbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_lavabutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_slimebutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_waterbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_mistbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_areaportalbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_playerclipbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_monsterclipbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_current0button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_current90button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_current180button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_current270button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_currentUPbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_currentDOWNbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_originbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_detailbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_ladderbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( content_camnoblockbutton ), FALSE); + +} + +void SetFlagButtons_Heretic2(texdef_to_face_t *texdef_face_list, bool b_isListEmpty) +{ + int i; + int contents = 0; + int flags = 0; + int value = 0; + int diff_contents = 0; + int diff_flags = 0; + gboolean diff_value = FALSE; + char tex_buff[11]; + texdef_t* tmp_texdef; + texdef_to_face_t* temp_texdef_face_list; + gboolean surface_which_material_inconsistant[4]; + int surface_iterator; + + setup_buttons = TRUE; + working_surface_flags = 0; + surface_mask = 0; + working_content_flags = 0; + content_mask = 0; + working_value = 0; + surface_material_inconsistant = FALSE; + surface_which_material_inconsistant[0] = FALSE; + surface_which_material_inconsistant[1] = FALSE; + surface_which_material_inconsistant[2] = FALSE; + surface_which_material_inconsistant[3] = FALSE; + + if(!b_isListEmpty) + { + tmp_texdef = &texdef_face_list->texdef; + contents = tmp_texdef->contents; + flags = tmp_texdef->flags; + value = tmp_texdef->value; + + surface_iterator = (tmp_texdef->flags & ~HERETIC2_SURF_MATERIAL_MASK) >> 24; // Inconsistant Material? + surface_which_material_inconsistant[surface_iterator] = TRUE; + + for (temp_texdef_face_list = texdef_face_list->next; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = &temp_texdef_face_list->texdef; + diff_contents |= contents ^ tmp_texdef->contents; // Figure out which buttons are inconsistent + diff_flags |= flags ^ tmp_texdef->flags; + if (tmp_texdef->value != value) + diff_value = TRUE; + + surface_iterator = (tmp_texdef->flags & ~HERETIC2_SURF_MATERIAL_MASK) >> 24; // Inconsistant Material? + surface_which_material_inconsistant[surface_iterator] = TRUE; + + Sys_Printf("Diff_Flags: %d\t Surf_Iter: %d\n",diff_flags, surface_iterator); + + } + } + + + clear_all_inconsistent(); + + // If no faces/brushes are selected, clear everything and bail + if(b_isListEmpty) + { + clear_all_buttons_and_values(); + setup_buttons = FALSE; + return; + } + + // Set surface buttons to reflect brush/face flags, contents, and values + if(diff_flags & HERETIC2_SURF_LIGHT) + set_inconsistent(surface_lightbutton); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (surface_lightbutton), (flags & HERETIC2_SURF_LIGHT)); + + if(diff_flags & HERETIC2_SURF_SLICK) + set_inconsistent(surface_slickbutton); + else if(flags & HERETIC2_SURF_SLICK) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_slickbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_slickbutton ), FALSE); + + if(diff_flags & HERETIC2_SURF_SKY) + set_inconsistent(surface_skybutton); + else if(flags & HERETIC2_SURF_SKY) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skybutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skybutton ), FALSE); + + if(diff_flags & HERETIC2_SURF_WARP) + set_inconsistent(surface_warpbutton); + else if(flags & HERETIC2_SURF_WARP) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_warpbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_warpbutton ), FALSE); + + if(diff_flags & HERETIC2_SURF_TRANS33) + set_inconsistent(surface_trans33button); + else if(flags & HERETIC2_SURF_TRANS33) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans33button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans33button ), FALSE); + + if(diff_flags & HERETIC2_SURF_TRANS66) + set_inconsistent(surface_trans66button); + else if(flags & HERETIC2_SURF_TRANS66) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans66button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans66button ), FALSE); + + if(diff_flags & HERETIC2_SURF_FLOWING) + set_inconsistent(surface_flowingbutton); + else if(flags & HERETIC2_SURF_FLOWING) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_flowingbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_flowingbutton ), FALSE); + + if(diff_flags & HERETIC2_SURF_NODRAW) + set_inconsistent(surface_nodrawbutton); + else if(flags & HERETIC2_SURF_NODRAW) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_nodrawbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_nodrawbutton ), FALSE); + + if(diff_flags & HERETIC2_SURF_TALL_WALL) + set_inconsistent(surface_tallwallbutton); + else if(flags & HERETIC2_SURF_TALL_WALL) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_tallwallbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_tallwallbutton ), FALSE); + + if(diff_flags & HERETIC2_SURF_ALPHA_TEXTURE) + set_inconsistent(surface_alphatexbutton); + else if(flags & HERETIC2_SURF_ALPHA_TEXTURE) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_alphatexbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_alphatexbutton ), FALSE); + + if(diff_flags & HERETIC2_SURF_ANIMSPEED) + set_inconsistent(surface_animspeedbutton); + else if(flags & HERETIC2_SURF_ANIMSPEED) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_animspeedbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_animspeedbutton ), FALSE); + + if(diff_flags & HERETIC2_SURF_UNDULATE) + set_inconsistent(surface_undulatebutton); + else if(flags & HERETIC2_SURF_UNDULATE) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_undulatebutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_undulatebutton ), FALSE); + + if(diff_flags & ~HERETIC2_SURF_MATERIAL_MASK) + { + Sys_Printf("--> %d\n", (diff_flags & ~HERETIC2_SURF_MATERIAL_MASK) ); + Sys_Printf("%d\t%d\t%d\t%d\n", surface_which_material_inconsistant[0], surface_which_material_inconsistant[1], surface_which_material_inconsistant[2], surface_which_material_inconsistant[3]); + + if (surface_which_material_inconsistant[0]) + { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_gravel_radiobutton ), FALSE); + surface_material_inconsistant = TRUE; + set_inconsistent(surf_gravel_radiobutton); + } + if (surface_which_material_inconsistant[1]) + { + //if (!surface_material_inconsistant) + //{ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_metal_radiobutton ), FALSE); + surface_material_inconsistant = TRUE; + //} + set_inconsistent(surf_metal_radiobutton); + } + if (surface_which_material_inconsistant[2]) + { + //if (!surface_material_inconsistant) + //{ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_stone_radiobutton ), FALSE); + surface_material_inconsistant = TRUE; + //} + set_inconsistent(surf_stone_radiobutton); + } + if (surface_which_material_inconsistant[3]) + { + //if (!surface_material_inconsistant) + //{ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_wood_radiobutton ), FALSE); + surface_material_inconsistant = TRUE; + //} + set_inconsistent(surf_wood_radiobutton); + } + } + else + { + if(flags & ~HERETIC2_SURF_MATERIAL_MASK) + { + surface_iterator = (flags & ~HERETIC2_SURF_MATERIAL_MASK) >> 24; + if( surface_iterator == 1) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_metal_radiobutton ), TRUE); + else if(surface_iterator == 2) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_stone_radiobutton ), TRUE); + else if(surface_iterator == 3) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_wood_radiobutton ), TRUE); + } + else + { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surf_gravel_radiobutton ), TRUE); + } + } + + // Set content buttons to reflect brush values + if(diff_contents & HERETIC2_CONTENTS_SOLID) + set_inconsistent(content_solidbutton); + else if(contents & HERETIC2_CONTENTS_SOLID) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_solidbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_solidbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_WINDOW) + set_inconsistent(content_windowbutton); + else if(contents & HERETIC2_CONTENTS_WINDOW) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_windowbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_windowbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_ILLUSIONARY) + set_inconsistent(content_illusbutton); + else if(contents & HERETIC2_CONTENTS_ILLUSIONARY) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_illusbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_illusbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_LAVA) + set_inconsistent(content_lavabutton); + else if(contents & HERETIC2_CONTENTS_LAVA) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_lavabutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_lavabutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_SLIME) + set_inconsistent(content_slimebutton); + else if(contents & HERETIC2_CONTENTS_SLIME) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_slimebutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_slimebutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_WATER) + set_inconsistent(content_waterbutton); + else if(contents & HERETIC2_CONTENTS_WATER) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_waterbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_waterbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_MIST) + set_inconsistent(content_mistbutton); + else if(contents & HERETIC2_CONTENTS_MIST) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_mistbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_mistbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_AREAPORTAL) + set_inconsistent(content_areaportalbutton); + else if(contents & HERETIC2_CONTENTS_AREAPORTAL) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_areaportalbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_areaportalbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_PLAYERCLIP) + set_inconsistent(content_playerclipbutton); + else if(contents & HERETIC2_CONTENTS_PLAYERCLIP) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_playerclipbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_playerclipbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_MONSTERCLIP) + set_inconsistent(content_monsterclipbutton); + else if(contents & HERETIC2_CONTENTS_MONSTERCLIP) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_monsterclipbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_monsterclipbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_CURRENT_0) + set_inconsistent(content_current0button); + else if(contents & HERETIC2_CONTENTS_CURRENT_0) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current0button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current0button ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_CURRENT_90) + set_inconsistent(content_current90button); + else if(contents & HERETIC2_CONTENTS_CURRENT_90) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current90button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current90button ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_CURRENT_180) + set_inconsistent(content_current180button); + else if(contents & HERETIC2_CONTENTS_CURRENT_180) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current180button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current180button ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_CURRENT_270) + set_inconsistent(content_current270button); + else if(contents & HERETIC2_CONTENTS_CURRENT_270) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current270button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current270button ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_CURRENT_UP) + set_inconsistent(content_currentUPbutton); + else if(contents & HERETIC2_CONTENTS_CURRENT_UP) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentUPbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentUPbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_CURRENT_DOWN) + set_inconsistent(content_currentDOWNbutton); + else if(contents & HERETIC2_CONTENTS_CURRENT_DOWN) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentDOWNbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentDOWNbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_ORIGIN) + set_inconsistent(content_originbutton); + else if(contents & HERETIC2_CONTENTS_ORIGIN) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_originbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_originbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_DETAIL) + set_inconsistent(content_detailbutton); + else if(contents & HERETIC2_CONTENTS_DETAIL) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_detailbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_detailbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_LADDER) + set_inconsistent(content_ladderbutton); + else if(contents & HERETIC2_CONTENTS_LADDER) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_ladderbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_ladderbutton ), FALSE); + + if(diff_contents & HERETIC2_CONTENTS_CAMERANOBLOCK) + set_inconsistent(content_camnoblockbutton); + else if(contents & HERETIC2_CONTENTS_CAMERANOBLOCK) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_camnoblockbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_camnoblockbutton ), FALSE); + + // Set Value + if(diff_value) + gtk_entry_set_text( (GtkEntry *)surf_value_entry, ""); + else + { + working_value = value; + sprintf( tex_buff, "%d", value); + gtk_entry_set_text( (GtkEntry *)surf_value_entry, tex_buff); + } + + setup_buttons = FALSE; +} + +void SetChangeInFlags_Face_Heretic2 (texdef_to_face_t *texdef_face_list) +{ + texdef_to_face_t *temp_texdef_face_list; + texdef_t *tmp_texdef; + + for (temp_texdef_face_list = texdef_face_list; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = &temp_texdef_face_list->texdef; + tmp_texdef->flags = (tmp_texdef->flags & ~surface_mask) | working_surface_flags; + tmp_texdef->contents = (tmp_texdef->contents & ~content_mask) | working_content_flags; + tmp_texdef->value = working_value; + Sys_Printf("content_flag: %d content_mask: %d\n",working_content_flags,content_mask); + Sys_Printf("content: %d\n",tmp_texdef->contents); + } +} + +inline void change_surfaceflag (GtkWidget *togglebutton, int sur_flag) // For Material +{ + if (!setup_buttons) // If we're setting up the buttons, we really don't need to + { // set flags that are already set + if (surface_material_inconsistant) + { + clear_inconsistent( surf_gravel_radiobutton ); + clear_inconsistent( surf_metal_radiobutton ); + clear_inconsistent( surf_stone_radiobutton ); + clear_inconsistent( surf_wood_radiobutton ); + } + surface_mask |= ~HERETIC2_SURF_MATERIAL_MASK; + working_surface_flags = (working_surface_flags & HERETIC2_SURF_MATERIAL_MASK) | sur_flag; + } +} + +inline void change_material (GtkWidget *togglebutton) +{ + if (!setup_buttons) // If we're setting up the buttons, we really don't need to + { // set flags that are already set + if (surface_material_inconsistant) + { + clear_inconsistent( surf_gravel_radiobutton ); + clear_inconsistent( surf_metal_radiobutton ); + clear_inconsistent( surf_stone_radiobutton ); + clear_inconsistent( surf_wood_radiobutton ); + } + if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_gravel_radiobutton)) ) + { + surface_mask |= ~HERETIC2_SURF_MATERIAL_MASK; + working_surface_flags = (working_surface_flags & HERETIC2_SURF_MATERIAL_MASK) | HERETIC2_SURF_TYPE_GRAVEL; + } + else if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_metal_radiobutton)) ) + { + surface_mask |= ~HERETIC2_SURF_MATERIAL_MASK; + working_surface_flags = (working_surface_flags & HERETIC2_SURF_MATERIAL_MASK) | HERETIC2_SURF_TYPE_METAL; + } + else if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_stone_radiobutton)) ) + { + surface_mask |= ~HERETIC2_SURF_MATERIAL_MASK; + working_surface_flags = (working_surface_flags & HERETIC2_SURF_MATERIAL_MASK) | HERETIC2_SURF_TYPE_STONE; + } + else if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_wood_radiobutton)) ) + { + surface_mask |= ~HERETIC2_SURF_MATERIAL_MASK; + working_surface_flags = (working_surface_flags & HERETIC2_SURF_MATERIAL_MASK) | HERETIC2_SURF_TYPE_WOOD; + } + } +} + +inline void change_surfaceflag (GtkWidget *togglebutton, int sur_flag, gboolean change_flag_to) +{ + + if (!setup_buttons) // If we're setting up the buttons, we really don't need to + { // set flags that are already set + if (gtk_toggle_button_get_inconsistent(GTK_TOGGLE_BUTTON (togglebutton))) // Clear out inconsistent, if set + clear_inconsistent(GTK_WIDGET (togglebutton)); + + surface_mask |= sur_flag; + + if (change_flag_to) + working_surface_flags |= sur_flag; + else + working_surface_flags &= ~sur_flag; + } +} + +inline void change_contentflag (GtkWidget *togglebutton, int content_flag, gboolean change_flag_to) +{ + + if ( (!setup_buttons) ) // If we're setting up the buttons, we really don't need to + { // set flags that are already set + + if (gtk_toggle_button_get_inconsistent(GTK_TOGGLE_BUTTON (togglebutton))) + clear_inconsistent(togglebutton); + //if (g_ptrSelectedFaces.GetSize() == 0) // Only changing content flags on whole brushes, not faces. + //{ + content_mask |= content_flag; + + if (change_flag_to) + working_content_flags |= content_flag; + else + working_content_flags &= ~content_flag; + //} + } +} + +// Surface Flags Callbacks +void +on_surface_lightbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_lightbutton, HERETIC2_SURF_LIGHT, (GTK_TOGGLE_BUTTON (surface_lightbutton)->active)); +} + + +void +on_surface_slickbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_slickbutton, HERETIC2_SURF_SLICK, (GTK_TOGGLE_BUTTON (surface_slickbutton)->active)); +} + + +void +on_surface_skybutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_skybutton, HERETIC2_SURF_SKY, (GTK_TOGGLE_BUTTON (surface_skybutton)->active)); +} + + +void +on_surface_warpbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_warpbutton, HERETIC2_SURF_WARP, (GTK_TOGGLE_BUTTON (surface_warpbutton)->active)); +} + + +void +on_surface_trans33button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_trans33button, HERETIC2_SURF_TRANS33, (GTK_TOGGLE_BUTTON (surface_trans33button)->active)); +} + + +void +on_surface_trans66button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_trans66button, HERETIC2_SURF_TRANS66, (GTK_TOGGLE_BUTTON (surface_trans66button)->active)); +} + + +void +on_surface_flowingbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_flowingbutton, HERETIC2_SURF_FLOWING, (GTK_TOGGLE_BUTTON (surface_flowingbutton)->active)); +} + + +void +on_surface_nodrawbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_nodrawbutton, HERETIC2_SURF_NODRAW, (GTK_TOGGLE_BUTTON (surface_nodrawbutton)->active)); +} + + +void +on_surface_tallwallbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_tallwallbutton, HERETIC2_SURF_TALL_WALL, (GTK_TOGGLE_BUTTON (surface_tallwallbutton)->active)); +} + + +void +on_surface_alphatexbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_alphatexbutton, HERETIC2_SURF_ALPHA_TEXTURE, (GTK_TOGGLE_BUTTON (surface_alphatexbutton)->active)); +} + + +void +on_surface_animspeedbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_animspeedbutton, HERETIC2_SURF_ANIMSPEED, (GTK_TOGGLE_BUTTON (surface_animspeedbutton)->active)); +} + + +void +on_surface_undulatebutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_undulatebutton, HERETIC2_SURF_UNDULATE, (GTK_TOGGLE_BUTTON (surface_undulatebutton)->active)); +} + + +void +on_surf_gravel_radiobutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_gravel_radiobutton))) + change_material(GTK_WIDGET(togglebutton)); +} + +void +on_surf_metal_radiobutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_metal_radiobutton))) + change_material(GTK_WIDGET(togglebutton)); +} + +void +on_surf_stone_radiobutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_stone_radiobutton))) + change_material(GTK_WIDGET(togglebutton)); +} + +void +on_surf_wood_radiobutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(surf_wood_radiobutton))) + change_material(GTK_WIDGET(togglebutton)); +} + +// Content Flags Callbacks +void +on_content_solidbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_solidbutton, HERETIC2_CONTENTS_SOLID, (GTK_TOGGLE_BUTTON (content_solidbutton)->active)); +} + + +void +on_content_windowbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_windowbutton, HERETIC2_CONTENTS_WINDOW, (GTK_TOGGLE_BUTTON (content_windowbutton)->active)); +} + + +void +on_content_illusbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_illusbutton, HERETIC2_CONTENTS_ILLUSIONARY, (GTK_TOGGLE_BUTTON (content_illusbutton)->active)); +} + + +void +on_content_lavabutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_lavabutton, HERETIC2_CONTENTS_LAVA, (GTK_TOGGLE_BUTTON (content_lavabutton)->active)); +} + + +void +on_content_slimebutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_slimebutton, HERETIC2_CONTENTS_SLIME, (GTK_TOGGLE_BUTTON (content_slimebutton)->active)); +} + + +void +on_content_waterbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_waterbutton, HERETIC2_CONTENTS_WATER, (GTK_TOGGLE_BUTTON (content_waterbutton)->active)); +} + + +void +on_content_mistbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_mistbutton, HERETIC2_CONTENTS_MIST, (GTK_TOGGLE_BUTTON (content_mistbutton)->active)); +} + + +void +on_content_areaportalbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_areaportalbutton, HERETIC2_CONTENTS_AREAPORTAL, (GTK_TOGGLE_BUTTON (content_areaportalbutton)->active)); +} + + +void +on_content_playerclipbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_playerclipbutton, HERETIC2_CONTENTS_PLAYERCLIP, (GTK_TOGGLE_BUTTON (content_playerclipbutton)->active)); +} + + +void +on_content_monsterclipbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_monsterclipbutton, HERETIC2_CONTENTS_MONSTERCLIP, (GTK_TOGGLE_BUTTON (content_monsterclipbutton)->active)); +} + + +void +on_content_current0button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_current0button, HERETIC2_CONTENTS_CURRENT_0, (GTK_TOGGLE_BUTTON (content_current0button)->active)); +} + + +void +on_content_current90button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_current90button, HERETIC2_CONTENTS_CURRENT_90, (GTK_TOGGLE_BUTTON (content_current90button)->active)); +} + + +void +on_content_current180button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_current180button, HERETIC2_CONTENTS_CURRENT_180, (GTK_TOGGLE_BUTTON (content_current180button)->active)); +} + + +void +on_content_current270button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_current270button, HERETIC2_CONTENTS_CURRENT_270, (GTK_TOGGLE_BUTTON (content_current270button)->active)); +} + + +void +on_content_currentUPbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_currentUPbutton, HERETIC2_CONTENTS_CURRENT_UP, (GTK_TOGGLE_BUTTON (content_currentUPbutton)->active)); +} + + +void +on_content_currentDOWNbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_currentDOWNbutton, HERETIC2_CONTENTS_CURRENT_DOWN, (GTK_TOGGLE_BUTTON (content_currentDOWNbutton)->active)); +} + + +void +on_content_originbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_originbutton, HERETIC2_CONTENTS_ORIGIN, (GTK_TOGGLE_BUTTON (content_originbutton)->active)); +} + + +void +on_content_detailbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_detailbutton, HERETIC2_CONTENTS_DETAIL, (GTK_TOGGLE_BUTTON (content_detailbutton)->active)); +} + + +void +on_content_ladderbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_ladderbutton, HERETIC2_CONTENTS_LADDER, (GTK_TOGGLE_BUTTON (content_ladderbutton)->active)); +} + + +void +on_content_camnoblockbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_camnoblockbutton, HERETIC2_CONTENTS_CAMERANOBLOCK, (GTK_TOGGLE_BUTTON (content_camnoblockbutton)->active)); +} + +// Value Entry Callback +void +on_surf_value_entry_changed (GtkEditable *editable, + gpointer user_data) +{ + if ( (!setup_buttons) ) // If we're setting up the buttons, don't change value + working_value = atoi( gtk_entry_get_text( (GtkEntry*)editable) ); +} + +void +on_surf_value_entry_insert_text (GtkEditable *editable, + gchar *new_text, + gint new_text_length, + gint *position, + gpointer user_data) +{ + int i, count=0; + gchar *result; + int entry_value; + texdef_t *pt; + brush_t *b; + face_t *f; + + // Limit input to digits, throwing out anything else + // Modified from Gtk FAQ for text filtering of GtkEntry + result = g_new (gchar, new_text_length); + + for (i=0; i < new_text_length; i++) { + if (!isdigit(new_text[i])) + continue; + result[count++] = new_text[i]; + } + + if (count > 0) { + gtk_signal_handler_block_by_func (GTK_OBJECT (editable), + GTK_SIGNAL_FUNC (on_surf_value_entry_insert_text), + user_data); + gtk_editable_insert_text (editable, result, count, position); + gtk_signal_handler_unblock_by_func (GTK_OBJECT (editable), + GTK_SIGNAL_FUNC (on_surf_value_entry_insert_text), + user_data); + } + gtk_signal_emit_stop_by_name (GTK_OBJECT (editable), "insert_text"); + + g_free (result); +} + +#define HERETIC2_FLAG_BUTTON_BORDER 3 + +GtkWidget* Create_Heretic2FlagsDialog (GtkWidget* surfacedialog_widget) +{ + GtkWidget *frame1; + GtkWidget *notebook1; + GtkWidget *vbox3; + GtkWidget *table1; + GtkWidget *frame2; + GtkWidget *hbox4; + GtkWidget *label4; + GtkWidget *vbox4; + GtkWidget *table3; + GtkWidget *label5; + + GtkWidget *hbox1; + GtkWidget *hbox2; + GtkWidget *label2; + GtkWidget *table2; + GtkWidget *label3; + + + frame1 = gtk_frame_new ("Brush/Face Flags"); + gtk_widget_show (frame1); + gtk_container_add (GTK_CONTAINER (surfacedialog_widget), frame1); + + notebook1 = gtk_notebook_new (); + gtk_widget_show (notebook1); + gtk_container_add (GTK_CONTAINER (frame1), notebook1); + + vbox3 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox3); + gtk_container_add (GTK_CONTAINER (notebook1), vbox3); + + table1 = gtk_table_new (3, 4, TRUE); + gtk_widget_show (table1); + gtk_box_pack_start (GTK_BOX (vbox3), table1, TRUE, TRUE, 0); + + surface_lightbutton = gtk_toggle_button_new_with_mnemonic ("Light"); + gtk_widget_show (surface_lightbutton); + gtk_table_attach (GTK_TABLE (table1), surface_lightbutton, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + surface_slickbutton = gtk_toggle_button_new_with_mnemonic ("Slick"); + gtk_widget_show (surface_slickbutton); + gtk_table_attach (GTK_TABLE (table1), surface_slickbutton, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + surface_skybutton = gtk_toggle_button_new_with_mnemonic ("Sky"); + gtk_widget_show (surface_skybutton); + gtk_table_attach (GTK_TABLE (table1), surface_skybutton, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + surface_warpbutton = gtk_toggle_button_new_with_mnemonic ("Warp"); + gtk_widget_show (surface_warpbutton); + gtk_table_attach (GTK_TABLE (table1), surface_warpbutton, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + surface_trans33button = gtk_toggle_button_new_with_mnemonic ("Trans33"); + gtk_widget_show (surface_trans33button); + gtk_table_attach (GTK_TABLE (table1), surface_trans33button, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + surface_trans66button = gtk_toggle_button_new_with_mnemonic ("Trans66"); + gtk_widget_show (surface_trans66button); + gtk_table_attach (GTK_TABLE (table1), surface_trans66button, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + surface_flowingbutton = gtk_toggle_button_new_with_mnemonic ("Flowing"); + gtk_widget_show (surface_flowingbutton); + gtk_table_attach (GTK_TABLE (table1), surface_flowingbutton, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + surface_nodrawbutton = gtk_toggle_button_new_with_mnemonic ("NoDraw"); + gtk_widget_show (surface_nodrawbutton); + gtk_table_attach (GTK_TABLE (table1), surface_nodrawbutton, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + surface_tallwallbutton = gtk_toggle_button_new_with_mnemonic ("TallWall"); + gtk_widget_show (surface_tallwallbutton); + gtk_table_attach (GTK_TABLE (table1), surface_tallwallbutton, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + surface_alphatexbutton = gtk_toggle_button_new_with_mnemonic ("AlphaTex"); + gtk_widget_show (surface_alphatexbutton); + gtk_table_attach (GTK_TABLE (table1), surface_alphatexbutton, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + surface_animspeedbutton = gtk_toggle_button_new_with_mnemonic ("AnimSpeed"); + gtk_widget_show (surface_animspeedbutton); + gtk_table_attach (GTK_TABLE (table1), surface_animspeedbutton, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + surface_undulatebutton = gtk_toggle_button_new_with_mnemonic ("Undulate"); + gtk_widget_show (surface_undulatebutton); + gtk_table_attach (GTK_TABLE (table1), surface_undulatebutton, 3, 4, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + frame2 = gtk_frame_new (NULL); + gtk_widget_show (frame2); + gtk_box_pack_start (GTK_BOX (vbox3), frame2, FALSE, FALSE, 0); + gtk_frame_set_shadow_type (GTK_FRAME (frame2), GTK_SHADOW_ETCHED_OUT); + gtk_container_set_border_width (GTK_CONTAINER (frame2), 4); + + hbox4 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox4); + gtk_container_add (GTK_CONTAINER (frame2), hbox4); + + surf_gravel_radiobutton = gtk_radio_button_new_with_mnemonic (NULL, "Gravel"); + gtk_widget_show (surf_gravel_radiobutton); + gtk_box_pack_start (GTK_BOX (hbox4), surf_gravel_radiobutton, TRUE, FALSE, 0); + + surf_metal_radiobutton = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON(surf_gravel_radiobutton), "Metal"); + gtk_widget_show (surf_metal_radiobutton); + gtk_box_pack_start (GTK_BOX (hbox4), surf_metal_radiobutton, TRUE, FALSE, 0); + + surf_stone_radiobutton = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON(surf_metal_radiobutton), "Stone"); + gtk_widget_show (surf_stone_radiobutton); + gtk_box_pack_start (GTK_BOX (hbox4), surf_stone_radiobutton, TRUE, FALSE, 0); + + surf_wood_radiobutton = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON(surf_stone_radiobutton), "Wood"); + gtk_widget_show (surf_wood_radiobutton); + gtk_box_pack_start (GTK_BOX (hbox4), surf_wood_radiobutton, TRUE, FALSE, 0); + + label4 = gtk_label_new ("Material"); + gtk_widget_show (label4); + gtk_frame_set_label_widget (GTK_FRAME (frame2), label4); + gtk_label_set_justify (GTK_LABEL (label4), GTK_JUSTIFY_LEFT); + + table3 = gtk_table_new (1, 4, FALSE); + gtk_widget_show (table3); + gtk_box_pack_start (GTK_BOX (vbox3), table3, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (table3), 3); + + hbox1 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox1); + gtk_table_attach (GTK_TABLE (table3), hbox1, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label5 = gtk_label_new ("Value: "); + gtk_widget_show (label5); + gtk_table_attach (GTK_TABLE (table3), label5, 1, 2, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label5), 0, 0); + gtk_label_set_justify (GTK_LABEL (label5), GTK_JUSTIFY_RIGHT); + + surf_value_entry = gtk_entry_new (); + gtk_widget_show (surf_value_entry); + gtk_table_attach (GTK_TABLE (table3), surf_value_entry, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + hbox2 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox2); + gtk_table_attach (GTK_TABLE (table3), hbox2, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label2 = gtk_label_new ("Surface Flags"); + gtk_widget_show (label2); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 0), label2); + gtk_label_set_justify (GTK_LABEL (label2), GTK_JUSTIFY_LEFT); + + table2 = gtk_table_new (5, 4, TRUE); + gtk_widget_show (table2); + gtk_container_add (GTK_CONTAINER (notebook1), table2); + + content_solidbutton = gtk_toggle_button_new_with_mnemonic ("Solid"); + gtk_widget_show (content_solidbutton); + gtk_table_attach (GTK_TABLE (table2), content_solidbutton, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_windowbutton = gtk_toggle_button_new_with_mnemonic ("Window"); + gtk_widget_show (content_windowbutton); + gtk_table_attach (GTK_TABLE (table2), content_windowbutton, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_illusbutton = gtk_toggle_button_new_with_mnemonic ("Illusion"); + gtk_widget_show (content_illusbutton); + gtk_table_attach (GTK_TABLE (table2), content_illusbutton, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_lavabutton = gtk_toggle_button_new_with_mnemonic ("Lava"); + gtk_widget_show (content_lavabutton); + gtk_table_attach (GTK_TABLE (table2), content_lavabutton, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_slimebutton = gtk_toggle_button_new_with_mnemonic ("Slime"); + gtk_widget_show (content_slimebutton); + gtk_table_attach (GTK_TABLE (table2), content_slimebutton, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_waterbutton = gtk_toggle_button_new_with_mnemonic ("Water"); + gtk_widget_show (content_waterbutton); + gtk_table_attach (GTK_TABLE (table2), content_waterbutton, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_mistbutton = gtk_toggle_button_new_with_mnemonic ("Mist"); + gtk_widget_show (content_mistbutton); + gtk_table_attach (GTK_TABLE (table2), content_mistbutton, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_areaportalbutton = gtk_toggle_button_new_with_mnemonic ("AreaPortal"); + gtk_widget_show (content_areaportalbutton); + gtk_table_attach (GTK_TABLE (table2), content_areaportalbutton, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_playerclipbutton = gtk_toggle_button_new_with_mnemonic ("PlayerClip"); + gtk_widget_show (content_playerclipbutton); + gtk_table_attach (GTK_TABLE (table2), content_playerclipbutton, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_monsterclipbutton = gtk_toggle_button_new_with_mnemonic ("MonsterClip"); + gtk_widget_show (content_monsterclipbutton); + gtk_table_attach (GTK_TABLE (table2), content_monsterclipbutton, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_current0button = gtk_toggle_button_new_with_mnemonic ("Current 0"); + gtk_widget_show (content_current0button); + gtk_table_attach (GTK_TABLE (table2), content_current0button, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_current90button = gtk_toggle_button_new_with_mnemonic ("Current 90"); + gtk_widget_show (content_current90button); + gtk_table_attach (GTK_TABLE (table2), content_current90button, 3, 4, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_current180button = gtk_toggle_button_new_with_mnemonic ("Current 180"); + gtk_widget_show (content_current180button); + gtk_table_attach (GTK_TABLE (table2), content_current180button, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_current270button = gtk_toggle_button_new_with_mnemonic ("Current 270"); + gtk_widget_show (content_current270button); + gtk_table_attach (GTK_TABLE (table2), content_current270button, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_currentUPbutton = gtk_toggle_button_new_with_mnemonic ("Current UP"); + gtk_widget_show (content_currentUPbutton); + gtk_table_attach (GTK_TABLE (table2), content_currentUPbutton, 2, 3, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_currentDOWNbutton = gtk_toggle_button_new_with_mnemonic ("Current DOWN"); + gtk_widget_show (content_currentDOWNbutton); + gtk_table_attach (GTK_TABLE (table2), content_currentDOWNbutton, 3, 4, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_originbutton = gtk_toggle_button_new_with_mnemonic ("Origin"); + gtk_widget_show (content_originbutton); + gtk_table_attach (GTK_TABLE (table2), content_originbutton, 0, 1, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_detailbutton = gtk_toggle_button_new_with_mnemonic ("Detail"); + gtk_widget_show (content_detailbutton); + gtk_table_attach (GTK_TABLE (table2), content_detailbutton, 1, 2, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_ladderbutton = gtk_toggle_button_new_with_mnemonic ("Ladder"); + gtk_widget_show (content_ladderbutton); + gtk_table_attach (GTK_TABLE (table2), content_ladderbutton, 2, 3, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + content_camnoblockbutton = gtk_toggle_button_new_with_mnemonic ("Cam No Block"); + gtk_widget_show (content_camnoblockbutton); + gtk_table_attach (GTK_TABLE (table2), content_camnoblockbutton, 3, 4, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + label3 = gtk_label_new ("Content Flags"); + gtk_widget_show (label3); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 1), label3); + gtk_label_set_justify (GTK_LABEL (label3), GTK_JUSTIFY_LEFT); + + // Signal Connects + g_signal_connect ((gpointer) surface_lightbutton, "toggled", + G_CALLBACK (on_surface_lightbutton_toggled), + NULL); + g_signal_connect ((gpointer) surface_slickbutton, "toggled", + G_CALLBACK (on_surface_slickbutton_toggled), + NULL); + g_signal_connect ((gpointer) surface_skybutton, "toggled", + G_CALLBACK (on_surface_skybutton_toggled), + NULL); + g_signal_connect ((gpointer) surface_warpbutton, "toggled", + G_CALLBACK (on_surface_warpbutton_toggled), + NULL); + g_signal_connect ((gpointer) surface_trans33button, "toggled", + G_CALLBACK (on_surface_trans33button_toggled), + NULL); + g_signal_connect ((gpointer) surface_trans66button, "toggled", + G_CALLBACK (on_surface_trans66button_toggled), + NULL); + g_signal_connect ((gpointer) surface_flowingbutton, "toggled", + G_CALLBACK (on_surface_flowingbutton_toggled), + NULL); + g_signal_connect ((gpointer) surface_nodrawbutton, "toggled", + G_CALLBACK (on_surface_nodrawbutton_toggled), + NULL); + g_signal_connect ((gpointer) surface_tallwallbutton, "toggled", + G_CALLBACK (on_surface_tallwallbutton_toggled), + NULL); + g_signal_connect ((gpointer) surface_alphatexbutton, "toggled", + G_CALLBACK (on_surface_alphatexbutton_toggled), + NULL); + g_signal_connect ((gpointer) surface_animspeedbutton, "toggled", + G_CALLBACK (on_surface_animspeedbutton_toggled), + NULL); + g_signal_connect ((gpointer) surface_undulatebutton, "toggled", + G_CALLBACK (on_surface_undulatebutton_toggled), + NULL); + + g_signal_connect ((gpointer) surf_gravel_radiobutton, "toggled", + G_CALLBACK (on_surf_gravel_radiobutton_toggled), + NULL); + g_signal_connect ((gpointer) surf_metal_radiobutton, "toggled", + G_CALLBACK (on_surf_metal_radiobutton_toggled), + NULL); + g_signal_connect ((gpointer) surf_stone_radiobutton, "toggled", + G_CALLBACK (on_surf_stone_radiobutton_toggled), + NULL); + g_signal_connect ((gpointer) surf_wood_radiobutton, "toggled", + G_CALLBACK (on_surf_wood_radiobutton_toggled), + NULL); + + g_signal_connect ((gpointer) surf_value_entry, "changed", + G_CALLBACK (on_surf_value_entry_changed), + NULL); + g_signal_connect ((gpointer) surf_value_entry, "insert_text", + G_CALLBACK (on_surf_value_entry_insert_text), + NULL); + g_signal_connect ((gpointer) content_solidbutton, "toggled", + G_CALLBACK (on_content_solidbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_windowbutton, "toggled", + G_CALLBACK (on_content_windowbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_illusbutton, "toggled", + G_CALLBACK (on_content_illusbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_lavabutton, "toggled", + G_CALLBACK (on_content_lavabutton_toggled), + NULL); + g_signal_connect ((gpointer) content_slimebutton, "toggled", + G_CALLBACK (on_content_slimebutton_toggled), + NULL); + g_signal_connect ((gpointer) content_waterbutton, "toggled", + G_CALLBACK (on_content_waterbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_mistbutton, "toggled", + G_CALLBACK (on_content_mistbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_areaportalbutton, "toggled", + G_CALLBACK (on_content_areaportalbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_playerclipbutton, "toggled", + G_CALLBACK (on_content_playerclipbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_monsterclipbutton, "toggled", + G_CALLBACK (on_content_monsterclipbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_current0button, "toggled", + G_CALLBACK (on_content_current0button_toggled), + NULL); + g_signal_connect ((gpointer) content_current90button, "toggled", + G_CALLBACK (on_content_current90button_toggled), + NULL); + g_signal_connect ((gpointer) content_current180button, "toggled", + G_CALLBACK (on_content_current180button_toggled), + NULL); + g_signal_connect ((gpointer) content_current270button, "toggled", + G_CALLBACK (on_content_current270button_toggled), + NULL); + g_signal_connect ((gpointer) content_currentUPbutton, "toggled", + G_CALLBACK (on_content_currentUPbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_currentDOWNbutton, "toggled", + G_CALLBACK (on_content_currentDOWNbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_originbutton, "toggled", + G_CALLBACK (on_content_originbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_detailbutton, "toggled", + G_CALLBACK (on_content_detailbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_ladderbutton, "toggled", + G_CALLBACK (on_content_ladderbutton_toggled), + NULL); + g_signal_connect ((gpointer) content_camnoblockbutton, "toggled", + G_CALLBACK (on_content_camnoblockbutton_toggled), + NULL); + + + return frame1; +} + diff --git a/plugins/surface_heretic2/surfdlg_plugin.cpp b/plugins/surface_heretic2/surfdlg_plugin.cpp index baa56126..06254bcf 100644 --- a/plugins/surface_heretic2/surfdlg_plugin.cpp +++ b/plugins/surface_heretic2/surfdlg_plugin.cpp @@ -1,127 +1,127 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include -#include "surfdlg_plugin.h" -#include "surfacedialog.h" - -#include "synapse.h" - -class CSynapseClient_SurfDLG : public CSynapseClient -{ -public: - // CSynapseClient API - bool RequestAPI(APIDescriptor_t *pAPI); - const char* GetInfo(); - const char* GetName(); - bool OnActivate(); - - CSynapseClient_SurfDLG() { } - virtual ~CSynapseClient_SurfDLG() { } -}; - -// ============================================================================= -// SYNAPSE - -_QERFuncTable_1 g_FuncTable; -_QERUndoTable g_UndoTable; -_QERAppSurfaceTable g_AppSurfaceTable; -_QERSelectedFaceTable g_SelectedFaceTable; -_QERShadersTable g_ShadersTable; -_QERAppShadersTable g_AppShadersTable; -_QERAppDataTable g_AppDataTable; - -CSynapseServer* g_pSynapseServer = NULL; -CSynapseClient_SurfDLG 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(SURFACEDIALOG_MAJOR, "heretic2", sizeof(_QERPlugSurfaceTable)); - g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); - g_SynapseClient.AddAPI(UNDO_MAJOR, NULL, sizeof(_QERUndoTable), SYN_REQUIRE, &g_UndoTable); - g_SynapseClient.AddAPI(APPSURFACEDIALOG_MAJOR, NULL, sizeof(_QERAppSurfaceTable), SYN_REQUIRE, &g_AppSurfaceTable); - g_SynapseClient.AddAPI(SELECTEDFACE_MAJOR, NULL, sizeof(_QERSelectedFaceTable), SYN_REQUIRE, &g_SelectedFaceTable); - g_SynapseClient.AddAPI(SHADERS_MAJOR, "quake2", sizeof(_QERShadersTable), SYN_REQUIRE, &g_ShadersTable); - g_SynapseClient.AddAPI(APPSHADERS_MAJOR, NULL, sizeof(_QERAppShadersTable), SYN_REQUIRE, &g_AppShadersTable); - g_SynapseClient.AddAPI(DATA_MAJOR, NULL, sizeof(_QERAppDataTable), SYN_REQUIRE, &g_AppDataTable); - - return &g_SynapseClient; -} - -bool CSynapseClient_SurfDLG::RequestAPI(APIDescriptor_t *pAPI) -{ - if (!strcmp(pAPI->major_name, SURFACEDIALOG_MAJOR)) - { - _QERPlugSurfaceTable* pSurfDialogTable= static_cast<_QERPlugSurfaceTable*>(pAPI->mpTable); - if (!strcmp(pAPI->minor_name, "heretic2")) - { - pSurfDialogTable->m_pfnToggleSurface = &ToggleSurface; - pSurfDialogTable->m_pfnDoSurface = &DoSurface; - pSurfDialogTable->m_pfnUpdateSurfaceDialog = &UpdateSurfaceDialog; - pSurfDialogTable->m_pfnSurfaceDlgFitAll = &SurfaceDlgFitAll; - pSurfDialogTable->m_pfnGet_SI_Module_Widget = &Get_SI_Module_Widget; - return true; - } - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -#include "version.h" - -const char* CSynapseClient_SurfDLG::GetInfo() -{ - return "Surface Dialog (Heretic 2) module built " __DATE__ " " RADIANT_VERSION; -} - -const char* CSynapseClient_SurfDLG::GetName() -{ - return "surface"; -} - -bool CSynapseClient_SurfDLG::OnActivate() -{ - return true; -} +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include "surfdlg_plugin.h" +#include "surfacedialog.h" + +#include "synapse.h" + +class CSynapseClient_SurfDLG : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + const char* GetName(); + bool OnActivate(); + + CSynapseClient_SurfDLG() { } + virtual ~CSynapseClient_SurfDLG() { } +}; + +// ============================================================================= +// SYNAPSE + +_QERFuncTable_1 g_FuncTable; +_QERUndoTable g_UndoTable; +_QERAppSurfaceTable g_AppSurfaceTable; +_QERSelectedFaceTable g_SelectedFaceTable; +_QERShadersTable g_ShadersTable; +_QERAppShadersTable g_AppShadersTable; +_QERAppDataTable g_AppDataTable; + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClient_SurfDLG 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(SURFACEDIALOG_MAJOR, "heretic2", sizeof(_QERPlugSurfaceTable)); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(UNDO_MAJOR, NULL, sizeof(_QERUndoTable), SYN_REQUIRE, &g_UndoTable); + g_SynapseClient.AddAPI(APPSURFACEDIALOG_MAJOR, NULL, sizeof(_QERAppSurfaceTable), SYN_REQUIRE, &g_AppSurfaceTable); + g_SynapseClient.AddAPI(SELECTEDFACE_MAJOR, NULL, sizeof(_QERSelectedFaceTable), SYN_REQUIRE, &g_SelectedFaceTable); + g_SynapseClient.AddAPI(SHADERS_MAJOR, "quake2", sizeof(_QERShadersTable), SYN_REQUIRE, &g_ShadersTable); + g_SynapseClient.AddAPI(APPSHADERS_MAJOR, NULL, sizeof(_QERAppShadersTable), SYN_REQUIRE, &g_AppShadersTable); + g_SynapseClient.AddAPI(DATA_MAJOR, NULL, sizeof(_QERAppDataTable), SYN_REQUIRE, &g_AppDataTable); + + return &g_SynapseClient; +} + +bool CSynapseClient_SurfDLG::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, SURFACEDIALOG_MAJOR)) + { + _QERPlugSurfaceTable* pSurfDialogTable= static_cast<_QERPlugSurfaceTable*>(pAPI->mpTable); + if (!strcmp(pAPI->minor_name, "heretic2")) + { + pSurfDialogTable->m_pfnToggleSurface = &ToggleSurface; + pSurfDialogTable->m_pfnDoSurface = &DoSurface; + pSurfDialogTable->m_pfnUpdateSurfaceDialog = &UpdateSurfaceDialog; + pSurfDialogTable->m_pfnSurfaceDlgFitAll = &SurfaceDlgFitAll; + pSurfDialogTable->m_pfnGet_SI_Module_Widget = &Get_SI_Module_Widget; + return true; + } + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClient_SurfDLG::GetInfo() +{ + return "Surface Dialog (Heretic 2) module built " __DATE__ " " RADIANT_VERSION; +} + +const char* CSynapseClient_SurfDLG::GetName() +{ + return "surface"; +} + +bool CSynapseClient_SurfDLG::OnActivate() +{ + return true; +} diff --git a/plugins/surface_quake2/surfacedialog.cpp b/plugins/surface_quake2/surfacedialog.cpp index bbf42271..45749c6d 100644 --- a/plugins/surface_quake2/surfacedialog.cpp +++ b/plugins/surface_quake2/surfacedialog.cpp @@ -1,1939 +1,1939 @@ -/* -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 -*/ - -// -// Surface Dialog Module -// - -// -// Nurail: Implemented to Module from the main Radiant Surface Dialog code -// - - -#include -#include - -#include "surfdlg_plugin.h" - - - -#ifdef _DEBUG -//#define DBG_SI 1 -#endif - -#include "gtkr_vector.h" - -std::vector g_texdef_face_vector; - -inline texdef_to_face_t* get_texdef_face_list() -{ - return &(*g_texdef_face_vector.begin()); -} - -inline unsigned int texdef_face_list_empty() -{ - return g_texdef_face_vector.empty(); -} - -inline unsigned int texdef_face_list_size() -{ - return g_texdef_face_vector.size(); -} - -// For different faces having different values -bool is_HShift_conflicting; -bool is_VShift_conflicting; -bool is_HScale_conflicting; -bool is_VScale_conflicting; -bool is_Rotate_conflicting; -bool is_TextureName_conflicting; - -void ShowDlg(); -void HideDlg(); -void SetTexMods(); -void GetTexMods(bool b_SetUndoPoint = FALSE); -void BuildDialog(); -void FitAll(); -void InitDefaultIncrement(texdef_t *); -void DoSnapTToGrid(float hscale, float vscale); -// called to perform a fitting from the outside (shortcut key) -void SurfaceDialogFitAll(); - -// Quake2 Flags Functions -void SetFlagButtons_Quake2(texdef_to_face_t *texdef_face_list, bool b_isListEmpty); -void SetChangeInFlags_Face_Quake2 (texdef_to_face_t *texdef_face_list); -GtkWidget* Create_Quake2FlagsDialog (GtkWidget* surfacedialog_widget); - - -// Dialog Data -int m_nHeight; -int m_nWidth; - -// 0 is invalid, otherwise it's the Id of the last 'do' we are responsible for -int m_nUndoId; - - -texturewin_t *texturewin; -texdef_t *l_pIncrement; -texdef_t texdef_offset; -texdef_t texdef_SI_values; - -// For Texture Entry, activate only on entry change -char old_texture_entry[128]; - -// the texdef to switch back to when the OnCancel is called -texdef_t g_old_texdef; - -// when TRUE, this thing means the surface inspector is currently being displayed -bool g_surfwin = FALSE; -// turn on/off processing of the "changed" "value_changed" messages -// (need to turn off when we are feeding data in) -bool g_bListenChanged = true; -// turn on/off listening of the update messages -bool g_bListenUpdate = true; - -GtkWidget* create_SurfaceInspector (void); -GtkWidget *SurfaceInspector = NULL; - -GtkWidget *m_pWidget; -GtkWidget *GetWidget () { return SurfaceInspector; } -GtkWidget *Get_SI_Module_Widget () { return SurfaceInspector; } -void SetWidget(GtkWidget *new_widget) { m_pWidget = new_widget; } -GtkWidget *GetDlgWidget (const char* name) - { return GTK_WIDGET (g_object_get_data (G_OBJECT (SurfaceInspector), name)); } - -// Spins for FitTexture -GtkWidget *spin_width; -GtkWidget *spin_height; - - -GtkWidget *texture_combo; -GtkWidget *texture_combo_entry; - -GtkWidget *match_grid_button; -GtkWidget *lock_valuechange_togglebutton; - -GtkObject *hshift_value_spinbutton_adj; -GtkWidget *hshift_value_spinbutton; -GtkObject *vshift_value_spinbutton_adj; -GtkWidget *vshift_value_spinbutton; -GtkObject *hscale_value_spinbutton_adj; -GtkWidget *hscale_value_spinbutton; -GtkObject *vscale_value_spinbutton_adj; -GtkWidget *vscale_value_spinbutton; -GtkObject *rotate_value_spinbutton_adj; -GtkWidget *rotate_value_spinbutton; - -GtkObject *hshift_offset_spinbutton_adj; -GtkWidget *hshift_offset_spinbutton; -GtkObject *vshift_offset_spinbutton_adj; -GtkWidget *vshift_offset_spinbutton; -GtkObject *hscale_offset_spinbutton_adj; -GtkWidget *hscale_offset_spinbutton; -GtkObject *vscale_offset_spinbutton_adj; -GtkWidget *vscale_offset_spinbutton; -GtkObject *rotate_offset_spinbutton_adj; -GtkWidget *rotate_offset_spinbutton; - -GtkObject *hshift_step_spinbutton_adj; -GtkWidget *hshift_step_spinbutton; -GtkObject *vshift_step_spinbutton_adj; -GtkWidget *vshift_step_spinbutton; -GtkObject *hscale_step_spinbutton_adj; -GtkWidget *hscale_step_spinbutton; -GtkObject *vscale_step_spinbutton_adj; -GtkWidget *vscale_step_spinbutton; -GtkObject *rotate_step_spinbutton_adj; -GtkWidget *rotate_step_spinbutton; - -GtkObject *fit_width_spinbutton_adj; -GtkWidget *fit_width_spinbutton; -GtkObject *fit_height_spinbutton_adj; -GtkWidget *fit_height_spinbutton; -GtkWidget *fit_button; -GtkWidget *axial_button; - -GtkWidget *done_button; -GtkWidget *apply_button; -GtkWidget *cancel_button; - -// Callbacks -gboolean on_texture_combo_entry_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data); -void on_texture_combo_entry_activate (GtkEntry *entry, gpointer user_data); - -static void on_match_grid_button_clicked (GtkButton *button, gpointer user_data); -static void on_lock_valuechange_togglebutton_toggled (GtkToggleButton *togglebutton, gpointer user_data); - -static void on_hshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_vshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_hscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_vscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_rotate_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); - -static void on_hshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_vshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_hscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_vscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_rotate_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); - -static void on_hshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_vshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_hscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_vscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_rotate_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); - -static void on_fit_width_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_fit_height_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); -static void on_fit_button_clicked (GtkButton *button, gpointer user_data); -static void on_axial_button_clicked (GtkButton *button, gpointer user_data); - -static void on_done_button_clicked (GtkButton *button, gpointer user_data); -static void on_apply_button_clicked (GtkButton *button, gpointer user_data); -static void on_cancel_button_clicked (GtkButton *button, gpointer user_data); - - -/* -=================================================== - - SURFACE INSPECTOR - -=================================================== -*/ - - -void IsFaceConflicting() -{ - texdef_t* tmp_texdef; - texdef_to_face_t* temp_texdef_face_list; - char buf[12]; - char texture_name[128]; - - if (texdef_face_list_empty()) - { - gtk_entry_set_text( GTK_ENTRY (hshift_value_spinbutton), ""); - gtk_entry_set_text( GTK_ENTRY (vshift_value_spinbutton), ""); - gtk_entry_set_text( GTK_ENTRY (hscale_value_spinbutton), ""); - gtk_entry_set_text( GTK_ENTRY (vscale_value_spinbutton), ""); - gtk_entry_set_text( GTK_ENTRY (rotate_value_spinbutton), ""); - gtk_entry_set_text( GTK_ENTRY (texture_combo_entry), ""); - return; - } - - g_bListenChanged = FALSE; - - tmp_texdef = &get_texdef_face_list()->texdef; - - strcpy(texture_name, tmp_texdef->GetName() ); - - texdef_SI_values.shift[0] = tmp_texdef->shift[0]; - texdef_SI_values.shift[1] = tmp_texdef->shift[1]; - texdef_SI_values.scale[0] = tmp_texdef->scale[0]; - texdef_SI_values.scale[1] = tmp_texdef->scale[1]; - texdef_SI_values.rotate = tmp_texdef->rotate; - texdef_SI_values.SetName( texture_name ); - - is_HShift_conflicting = FALSE; - is_VShift_conflicting = FALSE; - is_HScale_conflicting = FALSE; - is_VScale_conflicting = FALSE; - is_Rotate_conflicting = FALSE; - is_TextureName_conflicting = FALSE; - - if (texdef_face_list_size() > 1) - { - temp_texdef_face_list = get_texdef_face_list()->next; - - for (temp_texdef_face_list; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = &temp_texdef_face_list->texdef; - if ( texdef_SI_values.shift[0] != tmp_texdef->shift[0] ) - is_HShift_conflicting = TRUE; - - if ( texdef_SI_values.shift[1] != tmp_texdef->shift[1] ) - is_VShift_conflicting = TRUE; - - if ( texdef_SI_values.scale[0] != tmp_texdef->scale[0] ) - is_HScale_conflicting = TRUE; - - if ( texdef_SI_values.scale[1] != tmp_texdef->scale[1] ) - is_VScale_conflicting = TRUE; - - if ( texdef_SI_values.rotate != tmp_texdef->rotate ) - is_Rotate_conflicting = TRUE; - - if ( strcmp( texture_name, tmp_texdef->GetName() ) ) - is_TextureName_conflicting = TRUE; - } - } - - if(is_HShift_conflicting) - gtk_entry_set_text( GTK_ENTRY (hshift_value_spinbutton), ""); - else - gtk_spin_button_set_value( GTK_SPIN_BUTTON(hshift_value_spinbutton) , texdef_SI_values.shift[0] ); - - if(is_VShift_conflicting) - gtk_entry_set_text( GTK_ENTRY (vshift_value_spinbutton), ""); - else - gtk_spin_button_set_value( GTK_SPIN_BUTTON(vshift_value_spinbutton) , texdef_SI_values.shift[1] ); - - if(is_HScale_conflicting) - gtk_entry_set_text( GTK_ENTRY (hscale_value_spinbutton), ""); - else - gtk_spin_button_set_value( GTK_SPIN_BUTTON(hscale_value_spinbutton) , texdef_SI_values.scale[0] ); - - if(is_VScale_conflicting) - gtk_entry_set_text( GTK_ENTRY (vscale_value_spinbutton), ""); - else - gtk_spin_button_set_value( GTK_SPIN_BUTTON(vscale_value_spinbutton) , texdef_SI_values.scale[1] ); - - if(is_Rotate_conflicting) - gtk_entry_set_text( GTK_ENTRY (rotate_value_spinbutton), ""); - else - gtk_spin_button_set_value( GTK_SPIN_BUTTON(rotate_value_spinbutton) , texdef_SI_values.rotate ); - - g_bListenChanged = TRUE; -} - -#define MAX_NUM_LIST_ITEMS 15 -static void PopulateTextureComboList() -{ - texdef_t* tmp_texdef; - texdef_to_face_t* temp_texdef_face_list; - char blank[1]; - GList *items = NULL; - GList *tmp_item; - int num_of_list_items = 0; - - blank[0] = 0; - - if (texdef_face_list_empty()) - { - items = g_list_append (items, (gpointer) blank); - // For Texture Entry, activate only on entry change - strcpy (old_texture_entry, blank); - } - else if ( !is_TextureName_conflicting ) - { - temp_texdef_face_list = get_texdef_face_list(); - tmp_texdef = (texdef_t *) &get_texdef_face_list()->texdef; - items = g_list_append( items, (gpointer) tmp_texdef->GetName() ); - // For Texture Entry, activate only on entry change - strcpy (old_texture_entry, tmp_texdef->GetName()); - } - else - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - // Need to do a string compare, hence the custom search - if (!( g_list_find_custom (items, tmp_texdef->GetName(), (GCompareFunc) strcmp ) )) - { - items = g_list_append( items, (gpointer) tmp_texdef->GetName() ); - num_of_list_items++; - } - // Make sure the combo list isn't too long - if (num_of_list_items >= MAX_NUM_LIST_ITEMS) - break; - } - // If this isn't added last (to the top of the list), g_list_find freaks. - items = g_list_prepend (items, (gpointer) blank); - // For Texture Entry, activate only on entry change - strcpy (old_texture_entry, blank); - } - - gtk_combo_set_popdown_strings (GTK_COMBO (texture_combo), items); - g_list_free(items); - -} - -static void ZeroOffsetValues() -{ - texdef_offset.shift[0] = 0.0; - texdef_offset.shift[1] = 0.0; - texdef_offset.scale[0] = 0.0; - texdef_offset.scale[1] = 0.0; - texdef_offset.rotate = 0.0; -} - -static void GetTexdefInfo_from_Radiant() -{ - g_texdef_face_vector.clear(); - - unsigned int count = GetSelectedFaceCountfromBrushes(); - if(count == 0) - count = GetSelectedFaceCount(); - - g_texdef_face_vector.resize(count); - - if (!texdef_face_list_empty()) - { - texdef_to_face_t* p = get_texdef_face_list(); - GetSelFacesTexdef( get_texdef_face_list() ); - } - - IsFaceConflicting(); - PopulateTextureComboList(); - ZeroOffsetValues(); - if ( texdef_face_list_empty() ) - SetFlagButtons_Quake2( get_texdef_face_list() , TRUE); - else - SetFlagButtons_Quake2( get_texdef_face_list() , FALSE); -} - -static gint delete_event_callback(GtkWidget *widget, GdkEvent* event, gpointer data) -{ - HideDlg(); - return TRUE; -} - -// make the shift increments match the grid settings -// the objective being that the shift+arrows shortcuts move the texture by the corresponding grid size -// this depends on a scale value if you have selected a particular texture on which you want it to work: -// we move the textures in pixels, not world units. (i.e. increment values are in pixel) -// depending on the texture scale it doesn't take the same amount of pixels to move of g_qeglobals.d_gridsize -// increment * scale = gridsize -// hscale and vscale are optional parameters, if they are zero they will be set to the default scale -// NOTE: the default scale depends if you are using BP mode or regular. -// For regular it's 0.5f (128 pixels cover 64 world units), for BP it's simply 1.0f -// see fenris #2810 -void DoSnapTToGrid(float hscale, float vscale) -{ - l_pIncrement = Get_SI_Inc(); - - if (hscale == 0.0f) - { - hscale = 0.5f; - } - if (vscale == 0.0f) - { - vscale = 0.5f; - } -#ifdef _DEBUG - Sys_Printf ("DoSnapTToGrid: hscale %g vscale %g\n", hscale, vscale); -#endif - l_pIncrement->shift[0] = GridSize() / hscale; - l_pIncrement->shift[1] = GridSize() / vscale; - // now some update work - // FIXME: doesn't look good here, seems to be called several times - SetTexMods(); -} - -void UpdateSurfaceDialog() -{ - if (!g_bListenUpdate) - return; - - if (!SurfaceInspector) - return; - - // avoid long delays on slow computers - while (gtk_events_pending ()) - gtk_main_iteration (); - - if (g_surfwin) - { -#ifdef DBG_SI - Sys_Printf("UpdateSurfaceDialog\n"); -#endif - GetTexdefInfo_from_Radiant(); - SetTexMods(); - } - -} - -// DoSurface will always try to show the surface inspector -// or update it because something new has been selected -void DoSurface (void) -{ -#ifdef DBG_SI - Sys_Printf("DoSurface\n"); -#endif - if (!SurfaceInspector) - create_SurfaceInspector (); - - ShowDlg(); - SetTexMods (); -} - -void ToggleSurface() -{ -#ifdef DBG_SI - Sys_Printf("ToggleSurface Module\n"); -#endif - if (!g_surfwin) - DoSurface (); - else - on_cancel_button_clicked(NULL, NULL); -} - -// NOTE: will raise and show the Surface inspector and exec fit for patches and brushes -void SurfaceDlgFitAll() -{ - DoSurface(); - FitAll(); -} - -// ============================================================================= -// SurfaceDialog class - -void ShowDlg() -{ - - if(!SurfaceInspector) - create_SurfaceInspector(); - else - gtk_widget_show (SurfaceInspector); - - GetTexdefInfo_from_Radiant(); - GetTexMods(TRUE); // Set Initial Undo Point - g_surfwin = TRUE; -} - -void HideDlg() -{ - g_surfwin = FALSE; - gtk_widget_hide (SurfaceInspector); -} - - -// set default values for increments (shift scale and rot) -// this is called by the prefs code if can't find the values -void InitDefaultIncrement(texdef_t *tex) -{ - tex->SetName("foo"); - tex->shift[0] = 8; - tex->shift[1] = 8; - tex->scale[0] = 0.25; - tex->scale[1] = 0.25; - tex->rotate = 10; -} - -void BuildDialog () -{ - if ( !SurfaceInspector ) - create_SurfaceInspector(); -} - -/* -============== -SetTexMods - -Set the fields to the current texdef (i.e. map/texdef -> dialog widgets) -=============== -*/ - -void SetTexMods() -{ - texdef_t *pt; - GtkSpinButton *spin; - GtkAdjustment *adjust; - - texturewin = Texturewin (); - l_pIncrement = Get_SI_Inc(); - -#ifdef DBG_SI - Sys_Printf("SurfaceDlg SetTexMods\n"); -#endif - - if (!g_surfwin) - return; - - pt = &texturewin->texdef; - - g_bListenChanged = false; - - if(strncmp(pt->GetName(), "textures/", 9) != 0) - texdef_offset.SetName(SHADER_NOT_FOUND); - - - spin = GTK_SPIN_BUTTON (hshift_offset_spinbutton); - gtk_spin_button_set_value (spin, texdef_offset.shift[0]); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->shift[0]; - gtk_spin_button_set_value (GTK_SPIN_BUTTON(hshift_step_spinbutton), l_pIncrement->shift[0]); - - spin = GTK_SPIN_BUTTON (hshift_value_spinbutton); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->shift[0]; - - - spin = GTK_SPIN_BUTTON (vshift_offset_spinbutton); - gtk_spin_button_set_value (spin, texdef_offset.shift[1]); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->shift[1]; - gtk_spin_button_set_value (GTK_SPIN_BUTTON(vshift_step_spinbutton), l_pIncrement->shift[1]); - - spin = GTK_SPIN_BUTTON (vshift_value_spinbutton); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->shift[1]; - - - spin = GTK_SPIN_BUTTON (hscale_offset_spinbutton); - gtk_spin_button_set_value (spin, texdef_offset.scale[0]); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->scale[0]; - gtk_spin_button_set_value (GTK_SPIN_BUTTON(hscale_step_spinbutton), l_pIncrement->scale[0]); - - spin = GTK_SPIN_BUTTON (hscale_value_spinbutton); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->scale[0]; - - - spin = GTK_SPIN_BUTTON (vscale_offset_spinbutton); - gtk_spin_button_set_value (spin, texdef_offset.scale[1]); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->scale[1]; - gtk_spin_button_set_value (GTK_SPIN_BUTTON(vscale_step_spinbutton), l_pIncrement->scale[1]); - - spin = GTK_SPIN_BUTTON (vscale_value_spinbutton); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->scale[1]; - - - spin = GTK_SPIN_BUTTON (rotate_offset_spinbutton); - gtk_spin_button_set_value (spin, texdef_offset.rotate); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->rotate; - gtk_spin_button_set_value (GTK_SPIN_BUTTON(rotate_step_spinbutton), l_pIncrement->rotate); - - spin = GTK_SPIN_BUTTON (rotate_value_spinbutton); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->rotate; - - - g_bListenChanged = true; - - // store the current texdef as our escape route if user hits OnCancel - g_old_texdef = texturewin->texdef; -} - -/* -============== -GetTexMods - -Shows any changes to the main Radiant windows -=============== -*/ -void GetTexMods(bool b_SetUndoPoint) -{ - -#ifdef DBG_SI - Sys_Printf("SurfaceDlg GetTexMods\n"); -#endif - - if ( !texdef_face_list_empty() ) - { - g_bListenUpdate=FALSE; - SetChangeInFlags_Face_Quake2 ( get_texdef_face_list() ); - SetTexdef_FaceList( get_texdef_face_list(), b_SetUndoPoint ); - g_bListenUpdate=TRUE; - - if (b_SetUndoPoint) - m_nUndoId = Undo_GetUndoId(); - } -} - -void FitAll() -{ - on_fit_button_clicked(NULL, NULL); -} - - -//////////////////////////////////////////////////////////////////// -// -// GUI Section -// -//////////////////////////////////////////////////////////////////// - -GtkWidget* create_SurfaceInspector (void) -{ - - GtkWidget *label; - GtkWidget *hseparator; - GtkWidget *eventbox; - - GtkWidget *viewport8; - GtkWidget *viewport9; - GtkWidget *viewport2; - GtkWidget *viewport7; - GtkWidget *viewport5; - GtkWidget *viewport6; - GtkWidget *viewport10; - - GtkWidget *table1; - GtkWidget *table4; - GtkWidget *table5; - GtkWidget *table7; - - GtkWidget *alignment1; - GtkWidget *alignment2; - GtkWidget *alignment3; - - GtkWidget *vbox7; - - GtkWidget *hbox1; - GtkWidget *hbox2; - GtkWidget *hbox3; - GtkWidget *hbox4; - - GtkWidget *image1; - GtkWidget *image2; - GtkWidget *image3; - - GtkWidget *hbuttonbox1; - - SurfaceInspector = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_container_set_border_width (GTK_CONTAINER (SurfaceInspector), 4); - gtk_window_set_title (GTK_WINDOW (SurfaceInspector), "Surface Inspector"); - - SetWinPos_from_Prefs(SurfaceInspector); - - viewport8 = gtk_viewport_new (NULL, NULL); - gtk_widget_show (viewport8); - gtk_container_add (GTK_CONTAINER (SurfaceInspector), viewport8); - gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport8), GTK_SHADOW_NONE); - - vbox7 = gtk_vbox_new (FALSE, 0); - gtk_widget_show (vbox7); - gtk_container_add (GTK_CONTAINER (viewport8), vbox7); - - viewport9 = gtk_viewport_new (NULL, NULL); - gtk_widget_show (viewport9); - gtk_box_pack_start (GTK_BOX (vbox7), viewport9, FALSE, FALSE, 0); - gtk_container_set_border_width (GTK_CONTAINER (viewport9), 2); - gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport9), GTK_SHADOW_ETCHED_IN); - - hbox1 = gtk_hbox_new (FALSE, 0); - gtk_widget_show (hbox1); - gtk_container_add (GTK_CONTAINER (viewport9), hbox1); - gtk_container_set_border_width (GTK_CONTAINER (hbox1), 4); - - label = gtk_label_new ("Texture: "); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox1), label, FALSE, FALSE, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - texture_combo = gtk_combo_new (); - g_object_set_data (G_OBJECT (GTK_COMBO (texture_combo)->popwin), - "KeepMeAround", texture_combo); - gtk_combo_disable_activate ( (GtkCombo*) texture_combo); - gtk_widget_show (texture_combo); - gtk_box_pack_start (GTK_BOX (hbox1), texture_combo, TRUE, TRUE, 0); - - texture_combo_entry = GTK_COMBO (texture_combo)->entry; - gtk_widget_show (texture_combo_entry); - gtk_entry_set_max_length (GTK_ENTRY (texture_combo_entry), 128); - - viewport2 = gtk_viewport_new (NULL, NULL); - gtk_widget_show (viewport2); - gtk_box_pack_start (GTK_BOX (vbox7), viewport2, FALSE, TRUE, 0); - gtk_container_set_border_width (GTK_CONTAINER (viewport2), 2); - gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport2), GTK_SHADOW_ETCHED_IN); - - table1 = gtk_table_new (13, 4, FALSE); - gtk_widget_show (table1); - gtk_container_add (GTK_CONTAINER (viewport2), table1); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 3, 4, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 3, 4, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 3, 4, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 5, 6, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 5, 6, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 5, 6, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 7, 8, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 7, 8, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 7, 8, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 9, 10, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 9, 10, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 9, 10, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 11, 12, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 11, 12, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 11, 12, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label = gtk_label_new ("Offset"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table1), label, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - label = gtk_label_new ("Step"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table1), label, 3, 4, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 3, 4, 12, 13, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - match_grid_button = gtk_button_new_with_mnemonic ("Match Grid"); - gtk_widget_show (match_grid_button); - gtk_container_add (GTK_CONTAINER (eventbox), match_grid_button); - - label = gtk_label_new ("Value"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table1), label, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 3, 4, - (GtkAttachOptions) (GTK_SHRINK | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 5, 6, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 7, 8, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 9, 10, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 11, 12, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 4, 5, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label = gtk_label_new ("V Shift: "); - gtk_widget_show (label); - gtk_container_add (GTK_CONTAINER (eventbox), label); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 6, 7, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label = gtk_label_new (" H Scale: "); - gtk_widget_show (label); - gtk_container_add (GTK_CONTAINER (eventbox), label); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 8, 9, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label = gtk_label_new ("V Scale: "); - gtk_widget_show (label); - gtk_container_add (GTK_CONTAINER (eventbox), label); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 10, 11, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label = gtk_label_new ("Rotate: "); - gtk_widget_show (label); - gtk_container_add (GTK_CONTAINER (eventbox), label); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - label = gtk_label_new ("H Shift: "); - gtk_widget_show (label); - gtk_container_add (GTK_CONTAINER (eventbox), label); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - hseparator = gtk_hseparator_new (); - gtk_widget_show (hseparator); - gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 1, 2, 12, 13, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - lock_valuechange_togglebutton = gtk_toggle_button_new_with_mnemonic ("UNLOCK"); - gtk_widget_show (lock_valuechange_togglebutton); - gtk_container_add (GTK_CONTAINER (eventbox), lock_valuechange_togglebutton); - - // Value Spins - hshift_value_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); - hshift_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_value_spinbutton_adj), 1, 2); - gtk_widget_show (hshift_value_spinbutton); - gtk_table_attach (GTK_TABLE (table1), hshift_value_spinbutton, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_value_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hshift_value_spinbutton), TRUE); - gtk_widget_set_sensitive( GTK_WIDGET( hshift_value_spinbutton ), FALSE ); - - vshift_value_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); - vshift_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_value_spinbutton_adj), 1, 2); - gtk_widget_show (vshift_value_spinbutton); - gtk_table_attach (GTK_TABLE (table1), vshift_value_spinbutton, 1, 2, 4, 5, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_value_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vshift_value_spinbutton), TRUE); - gtk_widget_set_sensitive( GTK_WIDGET( vshift_value_spinbutton ), FALSE ); - - hscale_value_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); - hscale_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_value_spinbutton_adj), 1, 4); - gtk_widget_show (hscale_value_spinbutton); - gtk_table_attach (GTK_TABLE (table1), hscale_value_spinbutton, 1, 2, 6, 7, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_value_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hscale_value_spinbutton), TRUE); - gtk_widget_set_sensitive( GTK_WIDGET( hscale_value_spinbutton ), FALSE ); - - vscale_value_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); - vscale_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_value_spinbutton_adj), 1, 4); - gtk_widget_show (vscale_value_spinbutton); - gtk_table_attach (GTK_TABLE (table1), vscale_value_spinbutton, 1, 2, 8, 9, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_value_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vscale_value_spinbutton), TRUE); - gtk_widget_set_sensitive( GTK_WIDGET( vscale_value_spinbutton ), FALSE ); - - rotate_value_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); - rotate_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_value_spinbutton_adj), 1, 0); - gtk_widget_show (rotate_value_spinbutton); - gtk_table_attach (GTK_TABLE (table1), rotate_value_spinbutton, 1, 2, 10, 11, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_value_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (rotate_value_spinbutton), TRUE); - gtk_widget_set_sensitive( GTK_WIDGET( rotate_value_spinbutton ), FALSE ); - - // Offset Spins - hshift_offset_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); - hshift_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_offset_spinbutton_adj), 0, 2); - gtk_widget_show (hshift_offset_spinbutton); - gtk_table_attach (GTK_TABLE (table1), hshift_offset_spinbutton, 2, 3, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 4, 0); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (hshift_offset_spinbutton), TRUE); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_offset_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hshift_offset_spinbutton), TRUE); - - vshift_offset_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); - vshift_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_offset_spinbutton_adj), 0, 2); - gtk_widget_show (vshift_offset_spinbutton); - gtk_table_attach (GTK_TABLE (table1), vshift_offset_spinbutton, 2, 3, 4, 5, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 4, 0); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (vshift_offset_spinbutton), TRUE); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_offset_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vshift_offset_spinbutton), TRUE); - - hscale_offset_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); - hscale_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_offset_spinbutton_adj), 0, 4); - gtk_widget_show (hscale_offset_spinbutton); - gtk_table_attach (GTK_TABLE (table1), hscale_offset_spinbutton, 2, 3, 6, 7, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 4, 0); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (hscale_offset_spinbutton), TRUE); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_offset_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hscale_offset_spinbutton), TRUE); - - vscale_offset_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); - vscale_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_offset_spinbutton_adj), 0, 4); - gtk_widget_show (vscale_offset_spinbutton); - gtk_table_attach (GTK_TABLE (table1), vscale_offset_spinbutton, 2, 3, 8, 9, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 4, 0); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (vscale_offset_spinbutton), TRUE); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_offset_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vscale_offset_spinbutton), TRUE); - - rotate_offset_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); - rotate_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_offset_spinbutton_adj), 0, 2); - gtk_widget_show (rotate_offset_spinbutton); - gtk_table_attach (GTK_TABLE (table1), rotate_offset_spinbutton, 2, 3, 10, 11, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 4, 0); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (rotate_offset_spinbutton), TRUE); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_offset_spinbutton), GTK_UPDATE_IF_VALID); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (rotate_offset_spinbutton), TRUE); - - // Step Spins - hshift_step_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); - hshift_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_step_spinbutton_adj), 1, 2); - gtk_widget_show (hshift_step_spinbutton); - gtk_table_attach (GTK_TABLE (table1), hshift_step_spinbutton, 3, 4, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_step_spinbutton), GTK_UPDATE_IF_VALID); - - vshift_step_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); - vshift_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_step_spinbutton_adj), 1, 2); - gtk_widget_show (vshift_step_spinbutton); - gtk_table_attach (GTK_TABLE (table1), vshift_step_spinbutton, 3, 4, 4, 5, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_step_spinbutton), GTK_UPDATE_IF_VALID); - - hscale_step_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); - hscale_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_step_spinbutton_adj), 1, 4); - gtk_widget_show (hscale_step_spinbutton); - gtk_table_attach (GTK_TABLE (table1), hscale_step_spinbutton, 3, 4, 6, 7, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_step_spinbutton), GTK_UPDATE_IF_VALID); - - vscale_step_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); - vscale_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_step_spinbutton_adj), 1, 4); - gtk_widget_show (vscale_step_spinbutton); - gtk_table_attach (GTK_TABLE (table1), vscale_step_spinbutton, 3, 4, 8, 9, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_step_spinbutton), GTK_UPDATE_IF_VALID); - - rotate_step_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); - rotate_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_step_spinbutton_adj), 1, 2); - gtk_widget_show (rotate_step_spinbutton); - gtk_table_attach (GTK_TABLE (table1), rotate_step_spinbutton, 3, 4, 10, 11, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_step_spinbutton), GTK_UPDATE_IF_VALID); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 2, 3, 12, 13, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 12, 13, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - viewport7 = gtk_viewport_new (NULL, NULL); - gtk_widget_show (viewport7); - gtk_box_pack_start (GTK_BOX (vbox7), viewport7, FALSE, TRUE, 0); - gtk_container_set_border_width (GTK_CONTAINER (viewport7), 2); - gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport7), GTK_SHADOW_ETCHED_IN); - - table4 = gtk_table_new (4, 7, FALSE); - gtk_widget_show (table4); - gtk_container_add (GTK_CONTAINER (viewport7), table4); - - viewport5 = gtk_viewport_new (NULL, NULL); - gtk_widget_show (viewport5); - gtk_table_attach (GTK_TABLE (table4), viewport5, 1, 7, 0, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (viewport5), 6); - gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport5), GTK_SHADOW_ETCHED_OUT); - - table5 = gtk_table_new (2, 3, FALSE); - gtk_widget_show (table5); - gtk_container_add (GTK_CONTAINER (viewport5), table5); - gtk_container_set_border_width (GTK_CONTAINER (table5), 5); - gtk_table_set_col_spacings (GTK_TABLE (table5), 2); - - label = gtk_label_new ("Height"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table5), label, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); - - label = gtk_label_new ("Width"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table5), label, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); - - fit_width_spinbutton_adj = gtk_adjustment_new (1, 1, 32, 1, 10, 10); - fit_width_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (fit_width_spinbutton_adj), 1, 0); - gtk_widget_show (fit_width_spinbutton); - gtk_table_attach (GTK_TABLE (table5), fit_width_spinbutton, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (fit_width_spinbutton), TRUE); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (fit_width_spinbutton), GTK_UPDATE_IF_VALID); - - fit_height_spinbutton_adj = gtk_adjustment_new (1, 1, 32, 1, 10, 10); - fit_height_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (fit_height_spinbutton_adj), 1, 0); - gtk_widget_show (fit_height_spinbutton); - gtk_table_attach (GTK_TABLE (table5), fit_height_spinbutton, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 3, 0); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (fit_height_spinbutton), TRUE); - gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (fit_height_spinbutton), GTK_UPDATE_IF_VALID); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table5), eventbox, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table5), eventbox, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 4, 0); - - fit_button = gtk_button_new_with_mnemonic (" Fit "); - gtk_widget_show (fit_button); - gtk_container_add (GTK_CONTAINER (eventbox), fit_button); - - viewport6 = gtk_viewport_new (NULL, NULL); - gtk_widget_show (viewport6); - gtk_table_attach (GTK_TABLE (table4), viewport6, 0, 1, 0, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (viewport6), 4); - gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport6), GTK_SHADOW_NONE); - - table7 = gtk_table_new (2, 1, FALSE); - gtk_widget_show (table7); - gtk_container_add (GTK_CONTAINER (viewport6), table7); - - eventbox = gtk_event_box_new (); - gtk_widget_show (eventbox); - gtk_table_attach (GTK_TABLE (table7), eventbox, 0, 1, 0, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - axial_button = gtk_button_new_with_mnemonic ("Axial"); - gtk_widget_show (axial_button); - gtk_container_add (GTK_CONTAINER (eventbox), axial_button); - gtk_widget_set_size_request (axial_button, 56, 29); - gtk_container_set_border_width (GTK_CONTAINER (axial_button), 4); - - // Fit in Flags sub-dialog - Create_Quake2FlagsDialog(vbox7); - - viewport10 = gtk_viewport_new (NULL, NULL); - gtk_widget_show (viewport10); - gtk_box_pack_start (GTK_BOX (vbox7), viewport10, FALSE, TRUE, 0); - gtk_container_set_border_width (GTK_CONTAINER (viewport10), 2); - gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport10), GTK_SHADOW_ETCHED_IN); - - hbuttonbox1 = gtk_hbutton_box_new (); - gtk_widget_show (hbuttonbox1); - gtk_container_add (GTK_CONTAINER (viewport10), hbuttonbox1); - gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox1), 4); - gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_SPREAD); - - done_button = gtk_button_new (); - gtk_widget_show (done_button); - gtk_container_add (GTK_CONTAINER (hbuttonbox1), done_button); - GTK_WIDGET_SET_FLAGS (done_button, GTK_CAN_DEFAULT); - - alignment1 = gtk_alignment_new (0.5, 0.5, 0, 0); - gtk_widget_show (alignment1); - gtk_container_add (GTK_CONTAINER (done_button), alignment1); - - hbox2 = gtk_hbox_new (FALSE, 2); - gtk_widget_show (hbox2); - gtk_container_add (GTK_CONTAINER (alignment1), hbox2); - - image1 = gtk_image_new_from_stock ("gtk-yes", GTK_ICON_SIZE_BUTTON); - gtk_widget_show (image1); - gtk_box_pack_start (GTK_BOX (hbox2), image1, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic ("Done"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - - apply_button = gtk_button_new (); - gtk_widget_show (apply_button); - gtk_container_add (GTK_CONTAINER (hbuttonbox1), apply_button); - GTK_WIDGET_SET_FLAGS (apply_button, GTK_CAN_DEFAULT); - - alignment3 = gtk_alignment_new (0.5, 0.5, 0, 0); - gtk_widget_show (alignment3); - gtk_container_add (GTK_CONTAINER (apply_button), alignment3); - - hbox4 = gtk_hbox_new (FALSE, 2); - gtk_widget_show (hbox4); - gtk_container_add (GTK_CONTAINER (alignment3), hbox4); - - image3 = gtk_image_new_from_stock ("gtk-apply", GTK_ICON_SIZE_BUTTON); - gtk_widget_show (image3); - gtk_box_pack_start (GTK_BOX (hbox4), image3, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic ("Apply"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox4), label, FALSE, FALSE, 0); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - - cancel_button = gtk_button_new (); - gtk_widget_show (cancel_button); - gtk_container_add (GTK_CONTAINER (hbuttonbox1), cancel_button); - GTK_WIDGET_SET_FLAGS (cancel_button, GTK_CAN_DEFAULT); - - alignment2 = gtk_alignment_new (0.5, 0.5, 0, 0); - gtk_widget_show (alignment2); - gtk_container_add (GTK_CONTAINER (cancel_button), alignment2); - - hbox3 = gtk_hbox_new (FALSE, 2); - gtk_widget_show (hbox3); - gtk_container_add (GTK_CONTAINER (alignment2), hbox3); - - image2 = gtk_image_new_from_stock ("gtk-no", GTK_ICON_SIZE_BUTTON); - gtk_widget_show (image2); - gtk_box_pack_start (GTK_BOX (hbox3), image2, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic ("Cancel"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox3), label, FALSE, FALSE, 0); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - - - g_signal_connect ( (gpointer) SurfaceInspector, - "delete_event", - G_CALLBACK (delete_event_callback), - NULL ); - g_signal_connect ((gpointer) SurfaceInspector, "destroy", - G_CALLBACK (gtk_widget_destroy), - NULL); - - g_signal_connect ((gpointer) texture_combo_entry, "key_press_event", - G_CALLBACK (on_texture_combo_entry_key_press_event), - NULL); - g_signal_connect ((gpointer) texture_combo_entry, "activate", - G_CALLBACK (on_texture_combo_entry_activate), - NULL); - - - g_signal_connect ((gpointer) hshift_offset_spinbutton, "value_changed", - G_CALLBACK (on_hshift_offset_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) vshift_offset_spinbutton, "value_changed", - G_CALLBACK (on_vshift_offset_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) hscale_offset_spinbutton, "value_changed", - G_CALLBACK (on_hscale_offset_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) vscale_offset_spinbutton, "value_changed", - G_CALLBACK (on_vscale_offset_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) rotate_offset_spinbutton, "value_changed", - G_CALLBACK (on_rotate_offset_spinbutton_value_changed), - NULL); - - g_signal_connect ((gpointer) hshift_value_spinbutton, "value_changed", - G_CALLBACK (on_hshift_value_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) vshift_value_spinbutton, "value_changed", - G_CALLBACK (on_vshift_value_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) hscale_value_spinbutton, "value_changed", - G_CALLBACK (on_hscale_value_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) vscale_value_spinbutton, "value_changed", - G_CALLBACK (on_vscale_value_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) rotate_value_spinbutton, "value_changed", - G_CALLBACK (on_rotate_value_spinbutton_value_changed), - NULL); - - g_signal_connect ((gpointer) hshift_step_spinbutton, "value_changed", - G_CALLBACK (on_hshift_step_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) vshift_step_spinbutton, "value_changed", - G_CALLBACK (on_vshift_step_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) hscale_step_spinbutton, "value_changed", - G_CALLBACK (on_hscale_step_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) vscale_step_spinbutton, "value_changed", - G_CALLBACK (on_vscale_step_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) rotate_step_spinbutton, "value_changed", - G_CALLBACK (on_rotate_step_spinbutton_value_changed), - NULL); - - g_signal_connect ((gpointer) match_grid_button, "clicked", - G_CALLBACK (on_match_grid_button_clicked), - NULL); - g_signal_connect ((gpointer) lock_valuechange_togglebutton, "toggled", - G_CALLBACK (on_lock_valuechange_togglebutton_toggled), - NULL); - - g_signal_connect ((gpointer) fit_width_spinbutton, "value_changed", - G_CALLBACK (on_fit_width_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) fit_height_spinbutton, "value_changed", - G_CALLBACK (on_fit_height_spinbutton_value_changed), - NULL); - g_signal_connect ((gpointer) fit_button, "clicked", - G_CALLBACK (on_fit_button_clicked), - NULL); - - g_signal_connect ((gpointer) axial_button, "clicked", - G_CALLBACK (on_axial_button_clicked), - NULL); - - g_signal_connect ((gpointer) done_button, "clicked", - G_CALLBACK (on_done_button_clicked), - NULL); - g_signal_connect ((gpointer) apply_button, "clicked", - G_CALLBACK (on_apply_button_clicked), - NULL); - g_signal_connect ((gpointer) cancel_button, "clicked", - G_CALLBACK (on_cancel_button_clicked), - NULL); - - - return SurfaceInspector; -} - - -// Texture Combo -gboolean on_texture_combo_entry_key_press_event (GtkWidget *widget, GdkEventKey *event, - gpointer user_data) -{ - // Have Tab activate selection as well as Return - if (event->keyval == GDK_Tab) - g_signal_emit_by_name ( texture_combo_entry, "activate" ); - - return FALSE; -} - -void on_texture_combo_entry_activate (GtkEntry *entry, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - char text[128] = { 0 }; - - if (!texdef_face_list_empty() && g_bListenChanged) - { - // activate only on entry change - strcpy( text, gtk_entry_get_text(entry)); - if ( strcmp( old_texture_entry, text )) - { - // Check for spaces in shader name - if (text[0] <= ' ' || strchr(text, ' ')) - Sys_FPrintf(SYS_WRN, "WARNING: spaces in shader names are not allowed, ignoring '%s'\n", text); - else - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - strcpy( old_texture_entry, text ); - tmp_texdef->SetName( text ); - } - GetTexMods(); - } - } - } -} - -// Offset Spins -static void on_hshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_offset.shift[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_offset_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - if (is_HShift_conflicting) - tmp_texdef->shift[0] = tmp_orig_texdef->shift[0] + texdef_offset.shift[0]; - else - tmp_texdef->shift[0] = texdef_SI_values.shift[0] + texdef_offset.shift[0]; - } - GetTexMods(); - } -} - -static void on_vshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_offset.shift[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_offset_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - if (is_VShift_conflicting) - tmp_texdef->shift[1] = tmp_orig_texdef->shift[1] + texdef_offset.shift[1]; - else - tmp_texdef->shift[1] = texdef_SI_values.shift[1] + texdef_offset.shift[1]; - } - GetTexMods(); - } - -} - -static void on_hscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_offset.scale[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_offset_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - if (is_HScale_conflicting) - tmp_texdef->scale[0] = tmp_orig_texdef->scale[0] + texdef_offset.scale[0]; - else - tmp_texdef->scale[0] = texdef_SI_values.scale[0] + texdef_offset.scale[0]; - } - GetTexMods(); - } - - -} - -static void on_vscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_offset.scale[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_offset_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - if (is_VScale_conflicting) - tmp_texdef->scale[1] = tmp_orig_texdef->scale[1] + texdef_offset.scale[1]; - else - tmp_texdef->scale[1] = texdef_SI_values.scale[1] + texdef_offset.scale[1]; - } - GetTexMods(); - } - -} - -static void on_rotate_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_offset.rotate = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_offset_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - if (is_Rotate_conflicting) - tmp_texdef->rotate = tmp_orig_texdef->rotate + texdef_offset.rotate; - else - tmp_texdef->rotate = texdef_SI_values.rotate + texdef_offset.rotate; - } - GetTexMods(); - } - -} - - -// Match Grid -static void on_match_grid_button_clicked (GtkButton *button, gpointer user_data) -{ - float hscale, vscale; - - if( !strcmp(gtk_entry_get_text (GTK_ENTRY (hscale_value_spinbutton)), "") ) - hscale = 0.0; - else - hscale = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_value_spinbutton) ); - - if( !strcmp( gtk_entry_get_text (GTK_ENTRY (vscale_value_spinbutton)), "") ) - vscale = 0.0; - else - vscale = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_value_spinbutton) ); - DoSnapTToGrid (hscale, vscale); -} - - -// Lock out changes to Value -static void on_lock_valuechange_togglebutton_toggled (GtkToggleButton *togglebutton, gpointer user_data) -{ - bool is_Locked; - - is_Locked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lock_valuechange_togglebutton)); - - gtk_widget_set_sensitive( GTK_WIDGET( hscale_value_spinbutton ), is_Locked ); - gtk_widget_set_sensitive( GTK_WIDGET( vscale_value_spinbutton ), is_Locked ); - gtk_widget_set_sensitive( GTK_WIDGET( hshift_value_spinbutton ), is_Locked ); - gtk_widget_set_sensitive( GTK_WIDGET( vshift_value_spinbutton ), is_Locked ); - gtk_widget_set_sensitive( GTK_WIDGET( rotate_value_spinbutton ), is_Locked ); -} - - -// Value Spins -static void on_hshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_SI_values.shift[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_value_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - tmp_texdef->shift[0] = texdef_SI_values.shift[0] + texdef_offset.shift[0]; - is_HShift_conflicting = FALSE; - } - GetTexMods(); - } -} - -static void on_vshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_SI_values.shift[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_value_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - tmp_texdef->shift[1] = texdef_SI_values.shift[1] + texdef_offset.shift[1]; - is_VShift_conflicting = FALSE; - } - GetTexMods(); - } -} - -static void on_hscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_SI_values.scale[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_value_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - tmp_texdef->scale[0] = texdef_SI_values.scale[0] + texdef_offset.scale[0]; - is_HScale_conflicting = FALSE; - } - GetTexMods(); - } -} - -static void on_vscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_SI_values.scale[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_value_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - tmp_texdef->scale[1] = texdef_SI_values.scale[1] + texdef_offset.scale[1]; - is_VScale_conflicting = FALSE; - } - GetTexMods(); - } -} - -static void on_rotate_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - texdef_SI_values.rotate = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_value_spinbutton) ); - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; - tmp_texdef->rotate = texdef_SI_values.rotate + texdef_offset.rotate; - is_Rotate_conflicting = FALSE; - } - GetTexMods(); - } -} - - -// Step Spins -static void on_hshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - gfloat val; - GtkAdjustment * adjust; - - if (!g_bListenChanged) - return; - - l_pIncrement = Get_SI_Inc(); - -#ifdef DBG_SI - Sys_Printf("OnIncrementChanged HShift\n"); -#endif - - val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_step_spinbutton) ) ; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hshift_offset_spinbutton )); - adjust->step_increment = val; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hshift_value_spinbutton )); - adjust->step_increment = val; - l_pIncrement->shift[0] = val; -} - -static void on_vshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - gfloat val; - GtkAdjustment * adjust; - - if (!g_bListenChanged) - return; - - l_pIncrement = Get_SI_Inc(); - -#ifdef DBG_SI - Sys_Printf("OnIncrementChanged VShift\n"); -#endif - - val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_step_spinbutton) ) ; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vshift_offset_spinbutton )); - adjust->step_increment = val; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vshift_value_spinbutton )); - adjust->step_increment = val; - l_pIncrement->shift[1] = val; -} - -static void on_hscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - gfloat val; - GtkAdjustment * adjust; - - if (!g_bListenChanged) - return; - - l_pIncrement = Get_SI_Inc(); - -#ifdef DBG_SI - Sys_Printf("OnIncrementChanged HShift\n"); -#endif - - val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_step_spinbutton) ) ; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hscale_offset_spinbutton )); - adjust->step_increment = val; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hscale_value_spinbutton )); - adjust->step_increment = val; - l_pIncrement->scale[0] = val; -} - -static void on_vscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - gfloat val; - GtkAdjustment * adjust; - - if (!g_bListenChanged) - return; - - l_pIncrement = Get_SI_Inc(); - -#ifdef DBG_SI - Sys_Printf("OnIncrementChanged HShift\n"); -#endif - - val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_step_spinbutton) ) ; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vscale_offset_spinbutton )); - adjust->step_increment = val; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vscale_value_spinbutton )); - adjust->step_increment = val; - l_pIncrement->scale[1] = val; -} - -static void on_rotate_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - gfloat val; - GtkAdjustment * adjust; - - if (!g_bListenChanged) - return; - - l_pIncrement = Get_SI_Inc(); - -#ifdef DBG_SI - Sys_Printf("OnIncrementChanged HShift\n"); -#endif - - val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_step_spinbutton) ) ; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( rotate_offset_spinbutton )); - adjust->step_increment = val; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( rotate_value_spinbutton )); - adjust->step_increment = val; - l_pIncrement->rotate = val; -} - - -// Fit Texture -static void on_fit_width_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - m_nWidth = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(fit_width_spinbutton) ); -} - -static void on_fit_height_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) -{ - m_nHeight = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(fit_height_spinbutton) ); -} - -static void on_fit_button_clicked (GtkButton *button, gpointer user_data) -{ - FaceList_FitTexture(get_texdef_face_list(), m_nHeight, m_nWidth); - Sys_UpdateWindows(W_ALL); -} - - -// Axial Button -static void on_axial_button_clicked (GtkButton *button, gpointer user_data) -{ - texdef_t* tmp_texdef; - texdef_t* tmp_orig_texdef; - texdef_to_face_t* temp_texdef_face_list; - - if (!texdef_face_list_empty() && g_bListenChanged) - { - for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; - tmp_texdef->shift[0] = 0.0; - tmp_texdef->shift[1] = 0.0; - tmp_texdef->scale[0] = 0.5; - tmp_texdef->scale[1] = 0.5; - tmp_texdef->rotate = 0.0; - } - } - - SetTexdef_FaceList( get_texdef_face_list(), FALSE, TRUE ); - Sys_UpdateWindows(W_ALL); -} - - -// Action Buttons -static void on_done_button_clicked (GtkButton *button, gpointer user_data) -{ - if ( !texdef_face_list_empty() ) - GetTexMods(TRUE); - HideDlg(); - Sys_UpdateWindows(W_ALL); -} - -static void on_apply_button_clicked (GtkButton *button, gpointer user_data) -{ - if (!g_bListenChanged) - return; - - if ( !texdef_face_list_empty() ) - { - GetTexMods (TRUE); - Sys_UpdateWindows(W_CAMERA); - GetTexdefInfo_from_Radiant(); - SetTexMods(); - } -} - -static void on_cancel_button_clicked (GtkButton *button, gpointer user_data) -{ - texturewin = Texturewin (); - texturewin->texdef = g_old_texdef; - // cancel the last do if we own it - if ( (m_nUndoId == Undo_GetUndoId()) && ( m_nUndoId != 0 )) - { -#ifdef DBG_SI - Sys_Printf("OnCancel calling Undo_Undo\n"); -#endif - g_bListenUpdate = false; - Undo_Undo(TRUE); - g_bListenUpdate = true; - m_nUndoId = 0; - } - HideDlg(); -} - - +/* +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 +*/ + +// +// Surface Dialog Module +// + +// +// Nurail: Implemented to Module from the main Radiant Surface Dialog code +// + + +#include +#include + +#include "surfdlg_plugin.h" + + + +#ifdef _DEBUG +//#define DBG_SI 1 +#endif + +#include "gtkr_vector.h" + +std::vector g_texdef_face_vector; + +inline texdef_to_face_t* get_texdef_face_list() +{ + return &(*g_texdef_face_vector.begin()); +} + +inline unsigned int texdef_face_list_empty() +{ + return g_texdef_face_vector.empty(); +} + +inline unsigned int texdef_face_list_size() +{ + return g_texdef_face_vector.size(); +} + +// For different faces having different values +bool is_HShift_conflicting; +bool is_VShift_conflicting; +bool is_HScale_conflicting; +bool is_VScale_conflicting; +bool is_Rotate_conflicting; +bool is_TextureName_conflicting; + +void ShowDlg(); +void HideDlg(); +void SetTexMods(); +void GetTexMods(bool b_SetUndoPoint = FALSE); +void BuildDialog(); +void FitAll(); +void InitDefaultIncrement(texdef_t *); +void DoSnapTToGrid(float hscale, float vscale); +// called to perform a fitting from the outside (shortcut key) +void SurfaceDialogFitAll(); + +// Quake2 Flags Functions +void SetFlagButtons_Quake2(texdef_to_face_t *texdef_face_list, bool b_isListEmpty); +void SetChangeInFlags_Face_Quake2 (texdef_to_face_t *texdef_face_list); +GtkWidget* Create_Quake2FlagsDialog (GtkWidget* surfacedialog_widget); + + +// Dialog Data +int m_nHeight; +int m_nWidth; + +// 0 is invalid, otherwise it's the Id of the last 'do' we are responsible for +int m_nUndoId; + + +texturewin_t *texturewin; +texdef_t *l_pIncrement; +texdef_t texdef_offset; +texdef_t texdef_SI_values; + +// For Texture Entry, activate only on entry change +char old_texture_entry[128]; + +// the texdef to switch back to when the OnCancel is called +texdef_t g_old_texdef; + +// when TRUE, this thing means the surface inspector is currently being displayed +bool g_surfwin = FALSE; +// turn on/off processing of the "changed" "value_changed" messages +// (need to turn off when we are feeding data in) +bool g_bListenChanged = true; +// turn on/off listening of the update messages +bool g_bListenUpdate = true; + +GtkWidget* create_SurfaceInspector (void); +GtkWidget *SurfaceInspector = NULL; + +GtkWidget *m_pWidget; +GtkWidget *GetWidget () { return SurfaceInspector; } +GtkWidget *Get_SI_Module_Widget () { return SurfaceInspector; } +void SetWidget(GtkWidget *new_widget) { m_pWidget = new_widget; } +GtkWidget *GetDlgWidget (const char* name) + { return GTK_WIDGET (g_object_get_data (G_OBJECT (SurfaceInspector), name)); } + +// Spins for FitTexture +GtkWidget *spin_width; +GtkWidget *spin_height; + + +GtkWidget *texture_combo; +GtkWidget *texture_combo_entry; + +GtkWidget *match_grid_button; +GtkWidget *lock_valuechange_togglebutton; + +GtkObject *hshift_value_spinbutton_adj; +GtkWidget *hshift_value_spinbutton; +GtkObject *vshift_value_spinbutton_adj; +GtkWidget *vshift_value_spinbutton; +GtkObject *hscale_value_spinbutton_adj; +GtkWidget *hscale_value_spinbutton; +GtkObject *vscale_value_spinbutton_adj; +GtkWidget *vscale_value_spinbutton; +GtkObject *rotate_value_spinbutton_adj; +GtkWidget *rotate_value_spinbutton; + +GtkObject *hshift_offset_spinbutton_adj; +GtkWidget *hshift_offset_spinbutton; +GtkObject *vshift_offset_spinbutton_adj; +GtkWidget *vshift_offset_spinbutton; +GtkObject *hscale_offset_spinbutton_adj; +GtkWidget *hscale_offset_spinbutton; +GtkObject *vscale_offset_spinbutton_adj; +GtkWidget *vscale_offset_spinbutton; +GtkObject *rotate_offset_spinbutton_adj; +GtkWidget *rotate_offset_spinbutton; + +GtkObject *hshift_step_spinbutton_adj; +GtkWidget *hshift_step_spinbutton; +GtkObject *vshift_step_spinbutton_adj; +GtkWidget *vshift_step_spinbutton; +GtkObject *hscale_step_spinbutton_adj; +GtkWidget *hscale_step_spinbutton; +GtkObject *vscale_step_spinbutton_adj; +GtkWidget *vscale_step_spinbutton; +GtkObject *rotate_step_spinbutton_adj; +GtkWidget *rotate_step_spinbutton; + +GtkObject *fit_width_spinbutton_adj; +GtkWidget *fit_width_spinbutton; +GtkObject *fit_height_spinbutton_adj; +GtkWidget *fit_height_spinbutton; +GtkWidget *fit_button; +GtkWidget *axial_button; + +GtkWidget *done_button; +GtkWidget *apply_button; +GtkWidget *cancel_button; + +// Callbacks +gboolean on_texture_combo_entry_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data); +void on_texture_combo_entry_activate (GtkEntry *entry, gpointer user_data); + +static void on_match_grid_button_clicked (GtkButton *button, gpointer user_data); +static void on_lock_valuechange_togglebutton_toggled (GtkToggleButton *togglebutton, gpointer user_data); + +static void on_hshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_hscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_rotate_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); + +static void on_hshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_hscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_rotate_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); + +static void on_hshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_hscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_vscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_rotate_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); + +static void on_fit_width_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_fit_height_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data); +static void on_fit_button_clicked (GtkButton *button, gpointer user_data); +static void on_axial_button_clicked (GtkButton *button, gpointer user_data); + +static void on_done_button_clicked (GtkButton *button, gpointer user_data); +static void on_apply_button_clicked (GtkButton *button, gpointer user_data); +static void on_cancel_button_clicked (GtkButton *button, gpointer user_data); + + +/* +=================================================== + + SURFACE INSPECTOR + +=================================================== +*/ + + +void IsFaceConflicting() +{ + texdef_t* tmp_texdef; + texdef_to_face_t* temp_texdef_face_list; + char buf[12]; + char texture_name[128]; + + if (texdef_face_list_empty()) + { + gtk_entry_set_text( GTK_ENTRY (hshift_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (vshift_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (hscale_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (vscale_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (rotate_value_spinbutton), ""); + gtk_entry_set_text( GTK_ENTRY (texture_combo_entry), ""); + return; + } + + g_bListenChanged = FALSE; + + tmp_texdef = &get_texdef_face_list()->texdef; + + strcpy(texture_name, tmp_texdef->GetName() ); + + texdef_SI_values.shift[0] = tmp_texdef->shift[0]; + texdef_SI_values.shift[1] = tmp_texdef->shift[1]; + texdef_SI_values.scale[0] = tmp_texdef->scale[0]; + texdef_SI_values.scale[1] = tmp_texdef->scale[1]; + texdef_SI_values.rotate = tmp_texdef->rotate; + texdef_SI_values.SetName( texture_name ); + + is_HShift_conflicting = FALSE; + is_VShift_conflicting = FALSE; + is_HScale_conflicting = FALSE; + is_VScale_conflicting = FALSE; + is_Rotate_conflicting = FALSE; + is_TextureName_conflicting = FALSE; + + if (texdef_face_list_size() > 1) + { + temp_texdef_face_list = get_texdef_face_list()->next; + + for (temp_texdef_face_list; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = &temp_texdef_face_list->texdef; + if ( texdef_SI_values.shift[0] != tmp_texdef->shift[0] ) + is_HShift_conflicting = TRUE; + + if ( texdef_SI_values.shift[1] != tmp_texdef->shift[1] ) + is_VShift_conflicting = TRUE; + + if ( texdef_SI_values.scale[0] != tmp_texdef->scale[0] ) + is_HScale_conflicting = TRUE; + + if ( texdef_SI_values.scale[1] != tmp_texdef->scale[1] ) + is_VScale_conflicting = TRUE; + + if ( texdef_SI_values.rotate != tmp_texdef->rotate ) + is_Rotate_conflicting = TRUE; + + if ( strcmp( texture_name, tmp_texdef->GetName() ) ) + is_TextureName_conflicting = TRUE; + } + } + + if(is_HShift_conflicting) + gtk_entry_set_text( GTK_ENTRY (hshift_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(hshift_value_spinbutton) , texdef_SI_values.shift[0] ); + + if(is_VShift_conflicting) + gtk_entry_set_text( GTK_ENTRY (vshift_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(vshift_value_spinbutton) , texdef_SI_values.shift[1] ); + + if(is_HScale_conflicting) + gtk_entry_set_text( GTK_ENTRY (hscale_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(hscale_value_spinbutton) , texdef_SI_values.scale[0] ); + + if(is_VScale_conflicting) + gtk_entry_set_text( GTK_ENTRY (vscale_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(vscale_value_spinbutton) , texdef_SI_values.scale[1] ); + + if(is_Rotate_conflicting) + gtk_entry_set_text( GTK_ENTRY (rotate_value_spinbutton), ""); + else + gtk_spin_button_set_value( GTK_SPIN_BUTTON(rotate_value_spinbutton) , texdef_SI_values.rotate ); + + g_bListenChanged = TRUE; +} + +#define MAX_NUM_LIST_ITEMS 15 +static void PopulateTextureComboList() +{ + texdef_t* tmp_texdef; + texdef_to_face_t* temp_texdef_face_list; + char blank[1]; + GList *items = NULL; + GList *tmp_item; + int num_of_list_items = 0; + + blank[0] = 0; + + if (texdef_face_list_empty()) + { + items = g_list_append (items, (gpointer) blank); + // For Texture Entry, activate only on entry change + strcpy (old_texture_entry, blank); + } + else if ( !is_TextureName_conflicting ) + { + temp_texdef_face_list = get_texdef_face_list(); + tmp_texdef = (texdef_t *) &get_texdef_face_list()->texdef; + items = g_list_append( items, (gpointer) tmp_texdef->GetName() ); + // For Texture Entry, activate only on entry change + strcpy (old_texture_entry, tmp_texdef->GetName()); + } + else + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + // Need to do a string compare, hence the custom search + if (!( g_list_find_custom (items, tmp_texdef->GetName(), (GCompareFunc) strcmp ) )) + { + items = g_list_append( items, (gpointer) tmp_texdef->GetName() ); + num_of_list_items++; + } + // Make sure the combo list isn't too long + if (num_of_list_items >= MAX_NUM_LIST_ITEMS) + break; + } + // If this isn't added last (to the top of the list), g_list_find freaks. + items = g_list_prepend (items, (gpointer) blank); + // For Texture Entry, activate only on entry change + strcpy (old_texture_entry, blank); + } + + gtk_combo_set_popdown_strings (GTK_COMBO (texture_combo), items); + g_list_free(items); + +} + +static void ZeroOffsetValues() +{ + texdef_offset.shift[0] = 0.0; + texdef_offset.shift[1] = 0.0; + texdef_offset.scale[0] = 0.0; + texdef_offset.scale[1] = 0.0; + texdef_offset.rotate = 0.0; +} + +static void GetTexdefInfo_from_Radiant() +{ + g_texdef_face_vector.clear(); + + unsigned int count = GetSelectedFaceCountfromBrushes(); + if(count == 0) + count = GetSelectedFaceCount(); + + g_texdef_face_vector.resize(count); + + if (!texdef_face_list_empty()) + { + texdef_to_face_t* p = get_texdef_face_list(); + GetSelFacesTexdef( get_texdef_face_list() ); + } + + IsFaceConflicting(); + PopulateTextureComboList(); + ZeroOffsetValues(); + if ( texdef_face_list_empty() ) + SetFlagButtons_Quake2( get_texdef_face_list() , TRUE); + else + SetFlagButtons_Quake2( get_texdef_face_list() , FALSE); +} + +static gint delete_event_callback(GtkWidget *widget, GdkEvent* event, gpointer data) +{ + HideDlg(); + return TRUE; +} + +// make the shift increments match the grid settings +// the objective being that the shift+arrows shortcuts move the texture by the corresponding grid size +// this depends on a scale value if you have selected a particular texture on which you want it to work: +// we move the textures in pixels, not world units. (i.e. increment values are in pixel) +// depending on the texture scale it doesn't take the same amount of pixels to move of g_qeglobals.d_gridsize +// increment * scale = gridsize +// hscale and vscale are optional parameters, if they are zero they will be set to the default scale +// NOTE: the default scale depends if you are using BP mode or regular. +// For regular it's 0.5f (128 pixels cover 64 world units), for BP it's simply 1.0f +// see fenris #2810 +void DoSnapTToGrid(float hscale, float vscale) +{ + l_pIncrement = Get_SI_Inc(); + + if (hscale == 0.0f) + { + hscale = 0.5f; + } + if (vscale == 0.0f) + { + vscale = 0.5f; + } +#ifdef _DEBUG + Sys_Printf ("DoSnapTToGrid: hscale %g vscale %g\n", hscale, vscale); +#endif + l_pIncrement->shift[0] = GridSize() / hscale; + l_pIncrement->shift[1] = GridSize() / vscale; + // now some update work + // FIXME: doesn't look good here, seems to be called several times + SetTexMods(); +} + +void UpdateSurfaceDialog() +{ + if (!g_bListenUpdate) + return; + + if (!SurfaceInspector) + return; + + // avoid long delays on slow computers + while (gtk_events_pending ()) + gtk_main_iteration (); + + if (g_surfwin) + { +#ifdef DBG_SI + Sys_Printf("UpdateSurfaceDialog\n"); +#endif + GetTexdefInfo_from_Radiant(); + SetTexMods(); + } + +} + +// DoSurface will always try to show the surface inspector +// or update it because something new has been selected +void DoSurface (void) +{ +#ifdef DBG_SI + Sys_Printf("DoSurface\n"); +#endif + if (!SurfaceInspector) + create_SurfaceInspector (); + + ShowDlg(); + SetTexMods (); +} + +void ToggleSurface() +{ +#ifdef DBG_SI + Sys_Printf("ToggleSurface Module\n"); +#endif + if (!g_surfwin) + DoSurface (); + else + on_cancel_button_clicked(NULL, NULL); +} + +// NOTE: will raise and show the Surface inspector and exec fit for patches and brushes +void SurfaceDlgFitAll() +{ + DoSurface(); + FitAll(); +} + +// ============================================================================= +// SurfaceDialog class + +void ShowDlg() +{ + + if(!SurfaceInspector) + create_SurfaceInspector(); + else + gtk_widget_show (SurfaceInspector); + + GetTexdefInfo_from_Radiant(); + GetTexMods(TRUE); // Set Initial Undo Point + g_surfwin = TRUE; +} + +void HideDlg() +{ + g_surfwin = FALSE; + gtk_widget_hide (SurfaceInspector); +} + + +// set default values for increments (shift scale and rot) +// this is called by the prefs code if can't find the values +void InitDefaultIncrement(texdef_t *tex) +{ + tex->SetName("foo"); + tex->shift[0] = 8; + tex->shift[1] = 8; + tex->scale[0] = 0.25; + tex->scale[1] = 0.25; + tex->rotate = 10; +} + +void BuildDialog () +{ + if ( !SurfaceInspector ) + create_SurfaceInspector(); +} + +/* +============== +SetTexMods + +Set the fields to the current texdef (i.e. map/texdef -> dialog widgets) +=============== +*/ + +void SetTexMods() +{ + texdef_t *pt; + GtkSpinButton *spin; + GtkAdjustment *adjust; + + texturewin = Texturewin (); + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("SurfaceDlg SetTexMods\n"); +#endif + + if (!g_surfwin) + return; + + pt = &texturewin->texdef; + + g_bListenChanged = false; + + if(strncmp(pt->GetName(), "textures/", 9) != 0) + texdef_offset.SetName(SHADER_NOT_FOUND); + + + spin = GTK_SPIN_BUTTON (hshift_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.shift[0]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[0]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(hshift_step_spinbutton), l_pIncrement->shift[0]); + + spin = GTK_SPIN_BUTTON (hshift_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[0]; + + + spin = GTK_SPIN_BUTTON (vshift_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.shift[1]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[1]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(vshift_step_spinbutton), l_pIncrement->shift[1]); + + spin = GTK_SPIN_BUTTON (vshift_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[1]; + + + spin = GTK_SPIN_BUTTON (hscale_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.scale[0]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[0]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(hscale_step_spinbutton), l_pIncrement->scale[0]); + + spin = GTK_SPIN_BUTTON (hscale_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[0]; + + + spin = GTK_SPIN_BUTTON (vscale_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.scale[1]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[1]; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(vscale_step_spinbutton), l_pIncrement->scale[1]); + + spin = GTK_SPIN_BUTTON (vscale_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[1]; + + + spin = GTK_SPIN_BUTTON (rotate_offset_spinbutton); + gtk_spin_button_set_value (spin, texdef_offset.rotate); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->rotate; + gtk_spin_button_set_value (GTK_SPIN_BUTTON(rotate_step_spinbutton), l_pIncrement->rotate); + + spin = GTK_SPIN_BUTTON (rotate_value_spinbutton); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->rotate; + + + g_bListenChanged = true; + + // store the current texdef as our escape route if user hits OnCancel + g_old_texdef = texturewin->texdef; +} + +/* +============== +GetTexMods + +Shows any changes to the main Radiant windows +=============== +*/ +void GetTexMods(bool b_SetUndoPoint) +{ + +#ifdef DBG_SI + Sys_Printf("SurfaceDlg GetTexMods\n"); +#endif + + if ( !texdef_face_list_empty() ) + { + g_bListenUpdate=FALSE; + SetChangeInFlags_Face_Quake2 ( get_texdef_face_list() ); + SetTexdef_FaceList( get_texdef_face_list(), b_SetUndoPoint ); + g_bListenUpdate=TRUE; + + if (b_SetUndoPoint) + m_nUndoId = Undo_GetUndoId(); + } +} + +void FitAll() +{ + on_fit_button_clicked(NULL, NULL); +} + + +//////////////////////////////////////////////////////////////////// +// +// GUI Section +// +//////////////////////////////////////////////////////////////////// + +GtkWidget* create_SurfaceInspector (void) +{ + + GtkWidget *label; + GtkWidget *hseparator; + GtkWidget *eventbox; + + GtkWidget *viewport8; + GtkWidget *viewport9; + GtkWidget *viewport2; + GtkWidget *viewport7; + GtkWidget *viewport5; + GtkWidget *viewport6; + GtkWidget *viewport10; + + GtkWidget *table1; + GtkWidget *table4; + GtkWidget *table5; + GtkWidget *table7; + + GtkWidget *alignment1; + GtkWidget *alignment2; + GtkWidget *alignment3; + + GtkWidget *vbox7; + + GtkWidget *hbox1; + GtkWidget *hbox2; + GtkWidget *hbox3; + GtkWidget *hbox4; + + GtkWidget *image1; + GtkWidget *image2; + GtkWidget *image3; + + GtkWidget *hbuttonbox1; + + SurfaceInspector = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (SurfaceInspector), 4); + gtk_window_set_title (GTK_WINDOW (SurfaceInspector), "Surface Inspector"); + + SetWinPos_from_Prefs(SurfaceInspector); + + viewport8 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport8); + gtk_container_add (GTK_CONTAINER (SurfaceInspector), viewport8); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport8), GTK_SHADOW_NONE); + + vbox7 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox7); + gtk_container_add (GTK_CONTAINER (viewport8), vbox7); + + viewport9 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport9); + gtk_box_pack_start (GTK_BOX (vbox7), viewport9, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport9), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport9), GTK_SHADOW_ETCHED_IN); + + hbox1 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox1); + gtk_container_add (GTK_CONTAINER (viewport9), hbox1); + gtk_container_set_border_width (GTK_CONTAINER (hbox1), 4); + + label = gtk_label_new ("Texture: "); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox1), label, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + texture_combo = gtk_combo_new (); + g_object_set_data (G_OBJECT (GTK_COMBO (texture_combo)->popwin), + "KeepMeAround", texture_combo); + gtk_combo_disable_activate ( (GtkCombo*) texture_combo); + gtk_widget_show (texture_combo); + gtk_box_pack_start (GTK_BOX (hbox1), texture_combo, TRUE, TRUE, 0); + + texture_combo_entry = GTK_COMBO (texture_combo)->entry; + gtk_widget_show (texture_combo_entry); + gtk_entry_set_max_length (GTK_ENTRY (texture_combo_entry), 128); + + viewport2 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport2); + gtk_box_pack_start (GTK_BOX (vbox7), viewport2, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport2), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport2), GTK_SHADOW_ETCHED_IN); + + table1 = gtk_table_new (13, 4, FALSE); + gtk_widget_show (table1); + gtk_container_add (GTK_CONTAINER (viewport2), table1); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 1, 2, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 2, 3, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 3, 4, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Offset"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table1), label, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("Step"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table1), label, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 3, 4, 12, 13, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + match_grid_button = gtk_button_new_with_mnemonic ("Match Grid"); + gtk_widget_show (match_grid_button); + gtk_container_add (GTK_CONTAINER (eventbox), match_grid_button); + + label = gtk_label_new ("Value"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table1), label, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_SHRINK | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 5, 6, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 9, 10, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 11, 12, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("V Shift: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 6, 7, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new (" H Scale: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 8, 9, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("V Scale: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 10, 11, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Rotate: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("H Shift: "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + hseparator = gtk_hseparator_new (); + gtk_widget_show (hseparator); + gtk_table_attach (GTK_TABLE (table1), hseparator, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 1, 2, 12, 13, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + lock_valuechange_togglebutton = gtk_toggle_button_new_with_mnemonic ("UNLOCK"); + gtk_widget_show (lock_valuechange_togglebutton); + gtk_container_add (GTK_CONTAINER (eventbox), lock_valuechange_togglebutton); + + // Value Spins + hshift_value_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + hshift_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_value_spinbutton_adj), 1, 2); + gtk_widget_show (hshift_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hshift_value_spinbutton, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hshift_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( hshift_value_spinbutton ), FALSE ); + + vshift_value_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + vshift_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_value_spinbutton_adj), 1, 2); + gtk_widget_show (vshift_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vshift_value_spinbutton, 1, 2, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vshift_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( vshift_value_spinbutton ), FALSE ); + + hscale_value_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + hscale_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_value_spinbutton_adj), 1, 4); + gtk_widget_show (hscale_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hscale_value_spinbutton, 1, 2, 6, 7, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hscale_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( hscale_value_spinbutton ), FALSE ); + + vscale_value_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + vscale_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_value_spinbutton_adj), 1, 4); + gtk_widget_show (vscale_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vscale_value_spinbutton, 1, 2, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vscale_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( vscale_value_spinbutton ), FALSE ); + + rotate_value_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); + rotate_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_value_spinbutton_adj), 1, 0); + gtk_widget_show (rotate_value_spinbutton); + gtk_table_attach (GTK_TABLE (table1), rotate_value_spinbutton, 1, 2, 10, 11, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_value_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (rotate_value_spinbutton), TRUE); + gtk_widget_set_sensitive( GTK_WIDGET( rotate_value_spinbutton ), FALSE ); + + // Offset Spins + hshift_offset_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + hshift_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_offset_spinbutton_adj), 0, 2); + gtk_widget_show (hshift_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hshift_offset_spinbutton, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (hshift_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hshift_offset_spinbutton), TRUE); + + vshift_offset_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + vshift_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_offset_spinbutton_adj), 0, 2); + gtk_widget_show (vshift_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vshift_offset_spinbutton, 2, 3, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (vshift_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vshift_offset_spinbutton), TRUE); + + hscale_offset_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + hscale_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_offset_spinbutton_adj), 0, 4); + gtk_widget_show (hscale_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hscale_offset_spinbutton, 2, 3, 6, 7, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (hscale_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (hscale_offset_spinbutton), TRUE); + + vscale_offset_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + vscale_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_offset_spinbutton_adj), 0, 4); + gtk_widget_show (vscale_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vscale_offset_spinbutton, 2, 3, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (vscale_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vscale_offset_spinbutton), TRUE); + + rotate_offset_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); + rotate_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_offset_spinbutton_adj), 0, 2); + gtk_widget_show (rotate_offset_spinbutton); + gtk_table_attach (GTK_TABLE (table1), rotate_offset_spinbutton, 2, 3, 10, 11, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 4, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (rotate_offset_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_offset_spinbutton), GTK_UPDATE_IF_VALID); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (rotate_offset_spinbutton), TRUE); + + // Step Spins + hshift_step_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + hshift_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hshift_step_spinbutton_adj), 1, 2); + gtk_widget_show (hshift_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hshift_step_spinbutton, 3, 4, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hshift_step_spinbutton), GTK_UPDATE_IF_VALID); + + vshift_step_spinbutton_adj = gtk_adjustment_new (0.0, -8192.0, 8192.0, 2.0, 8.0, 8.0); + vshift_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vshift_step_spinbutton_adj), 1, 2); + gtk_widget_show (vshift_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vshift_step_spinbutton, 3, 4, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vshift_step_spinbutton), GTK_UPDATE_IF_VALID); + + hscale_step_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + hscale_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (hscale_step_spinbutton_adj), 1, 4); + gtk_widget_show (hscale_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), hscale_step_spinbutton, 3, 4, 6, 7, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (hscale_step_spinbutton), GTK_UPDATE_IF_VALID); + + vscale_step_spinbutton_adj = gtk_adjustment_new (0.0, -1024.0, 1024.0, 1.0, 4.0, 4.0); + vscale_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (vscale_step_spinbutton_adj), 1, 4); + gtk_widget_show (vscale_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), vscale_step_spinbutton, 3, 4, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_step_spinbutton), GTK_UPDATE_IF_VALID); + + rotate_step_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0); + rotate_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_step_spinbutton_adj), 1, 2); + gtk_widget_show (rotate_step_spinbutton); + gtk_table_attach (GTK_TABLE (table1), rotate_step_spinbutton, 3, 4, 10, 11, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (rotate_step_spinbutton), GTK_UPDATE_IF_VALID); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 2, 3, 12, 13, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 12, 13, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table1), eventbox, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + viewport7 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport7); + gtk_box_pack_start (GTK_BOX (vbox7), viewport7, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport7), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport7), GTK_SHADOW_ETCHED_IN); + + table4 = gtk_table_new (4, 7, FALSE); + gtk_widget_show (table4); + gtk_container_add (GTK_CONTAINER (viewport7), table4); + + viewport5 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport5); + gtk_table_attach (GTK_TABLE (table4), viewport5, 1, 7, 0, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport5), 6); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport5), GTK_SHADOW_ETCHED_OUT); + + table5 = gtk_table_new (2, 3, FALSE); + gtk_widget_show (table5); + gtk_container_add (GTK_CONTAINER (viewport5), table5); + gtk_container_set_border_width (GTK_CONTAINER (table5), 5); + gtk_table_set_col_spacings (GTK_TABLE (table5), 2); + + label = gtk_label_new ("Height"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table5), label, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); + + label = gtk_label_new ("Width"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table5), label, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 1); + + fit_width_spinbutton_adj = gtk_adjustment_new (1, 1, 32, 1, 10, 10); + fit_width_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (fit_width_spinbutton_adj), 1, 0); + gtk_widget_show (fit_width_spinbutton); + gtk_table_attach (GTK_TABLE (table5), fit_width_spinbutton, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (fit_width_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (fit_width_spinbutton), GTK_UPDATE_IF_VALID); + + fit_height_spinbutton_adj = gtk_adjustment_new (1, 1, 32, 1, 10, 10); + fit_height_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (fit_height_spinbutton_adj), 1, 0); + gtk_widget_show (fit_height_spinbutton); + gtk_table_attach (GTK_TABLE (table5), fit_height_spinbutton, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 3, 0); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (fit_height_spinbutton), TRUE); + gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (fit_height_spinbutton), GTK_UPDATE_IF_VALID); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table5), eventbox, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table5), eventbox, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 4, 0); + + fit_button = gtk_button_new_with_mnemonic (" Fit "); + gtk_widget_show (fit_button); + gtk_container_add (GTK_CONTAINER (eventbox), fit_button); + + viewport6 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport6); + gtk_table_attach (GTK_TABLE (table4), viewport6, 0, 1, 0, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport6), 4); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport6), GTK_SHADOW_NONE); + + table7 = gtk_table_new (2, 1, FALSE); + gtk_widget_show (table7); + gtk_container_add (GTK_CONTAINER (viewport6), table7); + + eventbox = gtk_event_box_new (); + gtk_widget_show (eventbox); + gtk_table_attach (GTK_TABLE (table7), eventbox, 0, 1, 0, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + axial_button = gtk_button_new_with_mnemonic ("Axial"); + gtk_widget_show (axial_button); + gtk_container_add (GTK_CONTAINER (eventbox), axial_button); + gtk_widget_set_size_request (axial_button, 56, 29); + gtk_container_set_border_width (GTK_CONTAINER (axial_button), 4); + + // Fit in Flags sub-dialog + Create_Quake2FlagsDialog(vbox7); + + viewport10 = gtk_viewport_new (NULL, NULL); + gtk_widget_show (viewport10); + gtk_box_pack_start (GTK_BOX (vbox7), viewport10, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (viewport10), 2); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport10), GTK_SHADOW_ETCHED_IN); + + hbuttonbox1 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox1); + gtk_container_add (GTK_CONTAINER (viewport10), hbuttonbox1); + gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox1), 4); + gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_SPREAD); + + done_button = gtk_button_new (); + gtk_widget_show (done_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), done_button); + GTK_WIDGET_SET_FLAGS (done_button, GTK_CAN_DEFAULT); + + alignment1 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment1); + gtk_container_add (GTK_CONTAINER (done_button), alignment1); + + hbox2 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox2); + gtk_container_add (GTK_CONTAINER (alignment1), hbox2); + + image1 = gtk_image_new_from_stock ("gtk-yes", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image1); + gtk_box_pack_start (GTK_BOX (hbox2), image1, FALSE, FALSE, 0); + + label = gtk_label_new_with_mnemonic ("Done"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + apply_button = gtk_button_new (); + gtk_widget_show (apply_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), apply_button); + GTK_WIDGET_SET_FLAGS (apply_button, GTK_CAN_DEFAULT); + + alignment3 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment3); + gtk_container_add (GTK_CONTAINER (apply_button), alignment3); + + hbox4 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox4); + gtk_container_add (GTK_CONTAINER (alignment3), hbox4); + + image3 = gtk_image_new_from_stock ("gtk-apply", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image3); + gtk_box_pack_start (GTK_BOX (hbox4), image3, FALSE, FALSE, 0); + + label = gtk_label_new_with_mnemonic ("Apply"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox4), label, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + cancel_button = gtk_button_new (); + gtk_widget_show (cancel_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), cancel_button); + GTK_WIDGET_SET_FLAGS (cancel_button, GTK_CAN_DEFAULT); + + alignment2 = gtk_alignment_new (0.5, 0.5, 0, 0); + gtk_widget_show (alignment2); + gtk_container_add (GTK_CONTAINER (cancel_button), alignment2); + + hbox3 = gtk_hbox_new (FALSE, 2); + gtk_widget_show (hbox3); + gtk_container_add (GTK_CONTAINER (alignment2), hbox3); + + image2 = gtk_image_new_from_stock ("gtk-no", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image2); + gtk_box_pack_start (GTK_BOX (hbox3), image2, FALSE, FALSE, 0); + + label = gtk_label_new_with_mnemonic ("Cancel"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox3), label, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + + g_signal_connect ( (gpointer) SurfaceInspector, + "delete_event", + G_CALLBACK (delete_event_callback), + NULL ); + g_signal_connect ((gpointer) SurfaceInspector, "destroy", + G_CALLBACK (gtk_widget_destroy), + NULL); + + g_signal_connect ((gpointer) texture_combo_entry, "key_press_event", + G_CALLBACK (on_texture_combo_entry_key_press_event), + NULL); + g_signal_connect ((gpointer) texture_combo_entry, "activate", + G_CALLBACK (on_texture_combo_entry_activate), + NULL); + + + g_signal_connect ((gpointer) hshift_offset_spinbutton, "value_changed", + G_CALLBACK (on_hshift_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vshift_offset_spinbutton, "value_changed", + G_CALLBACK (on_vshift_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) hscale_offset_spinbutton, "value_changed", + G_CALLBACK (on_hscale_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vscale_offset_spinbutton, "value_changed", + G_CALLBACK (on_vscale_offset_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) rotate_offset_spinbutton, "value_changed", + G_CALLBACK (on_rotate_offset_spinbutton_value_changed), + NULL); + + g_signal_connect ((gpointer) hshift_value_spinbutton, "value_changed", + G_CALLBACK (on_hshift_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vshift_value_spinbutton, "value_changed", + G_CALLBACK (on_vshift_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) hscale_value_spinbutton, "value_changed", + G_CALLBACK (on_hscale_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vscale_value_spinbutton, "value_changed", + G_CALLBACK (on_vscale_value_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) rotate_value_spinbutton, "value_changed", + G_CALLBACK (on_rotate_value_spinbutton_value_changed), + NULL); + + g_signal_connect ((gpointer) hshift_step_spinbutton, "value_changed", + G_CALLBACK (on_hshift_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vshift_step_spinbutton, "value_changed", + G_CALLBACK (on_vshift_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) hscale_step_spinbutton, "value_changed", + G_CALLBACK (on_hscale_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) vscale_step_spinbutton, "value_changed", + G_CALLBACK (on_vscale_step_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) rotate_step_spinbutton, "value_changed", + G_CALLBACK (on_rotate_step_spinbutton_value_changed), + NULL); + + g_signal_connect ((gpointer) match_grid_button, "clicked", + G_CALLBACK (on_match_grid_button_clicked), + NULL); + g_signal_connect ((gpointer) lock_valuechange_togglebutton, "toggled", + G_CALLBACK (on_lock_valuechange_togglebutton_toggled), + NULL); + + g_signal_connect ((gpointer) fit_width_spinbutton, "value_changed", + G_CALLBACK (on_fit_width_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) fit_height_spinbutton, "value_changed", + G_CALLBACK (on_fit_height_spinbutton_value_changed), + NULL); + g_signal_connect ((gpointer) fit_button, "clicked", + G_CALLBACK (on_fit_button_clicked), + NULL); + + g_signal_connect ((gpointer) axial_button, "clicked", + G_CALLBACK (on_axial_button_clicked), + NULL); + + g_signal_connect ((gpointer) done_button, "clicked", + G_CALLBACK (on_done_button_clicked), + NULL); + g_signal_connect ((gpointer) apply_button, "clicked", + G_CALLBACK (on_apply_button_clicked), + NULL); + g_signal_connect ((gpointer) cancel_button, "clicked", + G_CALLBACK (on_cancel_button_clicked), + NULL); + + + return SurfaceInspector; +} + + +// Texture Combo +gboolean on_texture_combo_entry_key_press_event (GtkWidget *widget, GdkEventKey *event, + gpointer user_data) +{ + // Have Tab activate selection as well as Return + if (event->keyval == GDK_Tab) + g_signal_emit_by_name ( texture_combo_entry, "activate" ); + + return FALSE; +} + +void on_texture_combo_entry_activate (GtkEntry *entry, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + char text[128] = { 0 }; + + if (!texdef_face_list_empty() && g_bListenChanged) + { + // activate only on entry change + strcpy( text, gtk_entry_get_text(entry)); + if ( strcmp( old_texture_entry, text )) + { + // Check for spaces in shader name + if (text[0] <= ' ' || strchr(text, ' ')) + Sys_FPrintf(SYS_WRN, "WARNING: spaces in shader names are not allowed, ignoring '%s'\n", text); + else + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + strcpy( old_texture_entry, text ); + tmp_texdef->SetName( text ); + } + GetTexMods(); + } + } + } +} + +// Offset Spins +static void on_hshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.shift[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_HShift_conflicting) + tmp_texdef->shift[0] = tmp_orig_texdef->shift[0] + texdef_offset.shift[0]; + else + tmp_texdef->shift[0] = texdef_SI_values.shift[0] + texdef_offset.shift[0]; + } + GetTexMods(); + } +} + +static void on_vshift_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.shift[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_VShift_conflicting) + tmp_texdef->shift[1] = tmp_orig_texdef->shift[1] + texdef_offset.shift[1]; + else + tmp_texdef->shift[1] = texdef_SI_values.shift[1] + texdef_offset.shift[1]; + } + GetTexMods(); + } + +} + +static void on_hscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.scale[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_HScale_conflicting) + tmp_texdef->scale[0] = tmp_orig_texdef->scale[0] + texdef_offset.scale[0]; + else + tmp_texdef->scale[0] = texdef_SI_values.scale[0] + texdef_offset.scale[0]; + } + GetTexMods(); + } + + +} + +static void on_vscale_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.scale[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_VScale_conflicting) + tmp_texdef->scale[1] = tmp_orig_texdef->scale[1] + texdef_offset.scale[1]; + else + tmp_texdef->scale[1] = texdef_SI_values.scale[1] + texdef_offset.scale[1]; + } + GetTexMods(); + } + +} + +static void on_rotate_offset_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_offset.rotate = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_offset_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + if (is_Rotate_conflicting) + tmp_texdef->rotate = tmp_orig_texdef->rotate + texdef_offset.rotate; + else + tmp_texdef->rotate = texdef_SI_values.rotate + texdef_offset.rotate; + } + GetTexMods(); + } + +} + + +// Match Grid +static void on_match_grid_button_clicked (GtkButton *button, gpointer user_data) +{ + float hscale, vscale; + + if( !strcmp(gtk_entry_get_text (GTK_ENTRY (hscale_value_spinbutton)), "") ) + hscale = 0.0; + else + hscale = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_value_spinbutton) ); + + if( !strcmp( gtk_entry_get_text (GTK_ENTRY (vscale_value_spinbutton)), "") ) + vscale = 0.0; + else + vscale = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_value_spinbutton) ); + DoSnapTToGrid (hscale, vscale); +} + + +// Lock out changes to Value +static void on_lock_valuechange_togglebutton_toggled (GtkToggleButton *togglebutton, gpointer user_data) +{ + bool is_Locked; + + is_Locked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lock_valuechange_togglebutton)); + + gtk_widget_set_sensitive( GTK_WIDGET( hscale_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( vscale_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( hshift_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( vshift_value_spinbutton ), is_Locked ); + gtk_widget_set_sensitive( GTK_WIDGET( rotate_value_spinbutton ), is_Locked ); +} + + +// Value Spins +static void on_hshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.shift[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->shift[0] = texdef_SI_values.shift[0] + texdef_offset.shift[0]; + is_HShift_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_vshift_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.shift[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->shift[1] = texdef_SI_values.shift[1] + texdef_offset.shift[1]; + is_VShift_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_hscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.scale[0] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->scale[0] = texdef_SI_values.scale[0] + texdef_offset.scale[0]; + is_HScale_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_vscale_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.scale[1] = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->scale[1] = texdef_SI_values.scale[1] + texdef_offset.scale[1]; + is_VScale_conflicting = FALSE; + } + GetTexMods(); + } +} + +static void on_rotate_value_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + texdef_SI_values.rotate = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_value_spinbutton) ); + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_orig_texdef = (texdef_t *) &temp_texdef_face_list->orig_texdef; + tmp_texdef->rotate = texdef_SI_values.rotate + texdef_offset.rotate; + is_Rotate_conflicting = FALSE; + } + GetTexMods(); + } +} + + +// Step Spins +static void on_hshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hshift_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hshift_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hshift_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->shift[0] = val; +} + +static void on_vshift_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged VShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vshift_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vshift_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vshift_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->shift[1] = val; +} + +static void on_hscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(hscale_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hscale_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( hscale_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->scale[0] = val; +} + +static void on_vscale_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(vscale_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vscale_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( vscale_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->scale[1] = val; +} + +static void on_rotate_step_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + gfloat val; + GtkAdjustment * adjust; + + if (!g_bListenChanged) + return; + + l_pIncrement = Get_SI_Inc(); + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged HShift\n"); +#endif + + val = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(rotate_step_spinbutton) ) ; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( rotate_offset_spinbutton )); + adjust->step_increment = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON ( rotate_value_spinbutton )); + adjust->step_increment = val; + l_pIncrement->rotate = val; +} + + +// Fit Texture +static void on_fit_width_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + m_nWidth = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(fit_width_spinbutton) ); +} + +static void on_fit_height_spinbutton_value_changed (GtkSpinButton *spinbutton, gpointer user_data) +{ + m_nHeight = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(fit_height_spinbutton) ); +} + +static void on_fit_button_clicked (GtkButton *button, gpointer user_data) +{ + FaceList_FitTexture(get_texdef_face_list(), m_nHeight, m_nWidth); + Sys_UpdateWindows(W_ALL); +} + + +// Axial Button +static void on_axial_button_clicked (GtkButton *button, gpointer user_data) +{ + texdef_t* tmp_texdef; + texdef_t* tmp_orig_texdef; + texdef_to_face_t* temp_texdef_face_list; + + if (!texdef_face_list_empty() && g_bListenChanged) + { + for (temp_texdef_face_list = get_texdef_face_list(); temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = (texdef_t *) &temp_texdef_face_list->texdef; + tmp_texdef->shift[0] = 0.0; + tmp_texdef->shift[1] = 0.0; + tmp_texdef->scale[0] = 0.5; + tmp_texdef->scale[1] = 0.5; + tmp_texdef->rotate = 0.0; + } + } + + SetTexdef_FaceList( get_texdef_face_list(), FALSE, TRUE ); + Sys_UpdateWindows(W_ALL); +} + + +// Action Buttons +static void on_done_button_clicked (GtkButton *button, gpointer user_data) +{ + if ( !texdef_face_list_empty() ) + GetTexMods(TRUE); + HideDlg(); + Sys_UpdateWindows(W_ALL); +} + +static void on_apply_button_clicked (GtkButton *button, gpointer user_data) +{ + if (!g_bListenChanged) + return; + + if ( !texdef_face_list_empty() ) + { + GetTexMods (TRUE); + Sys_UpdateWindows(W_CAMERA); + GetTexdefInfo_from_Radiant(); + SetTexMods(); + } +} + +static void on_cancel_button_clicked (GtkButton *button, gpointer user_data) +{ + texturewin = Texturewin (); + texturewin->texdef = g_old_texdef; + // cancel the last do if we own it + if ( (m_nUndoId == Undo_GetUndoId()) && ( m_nUndoId != 0 )) + { +#ifdef DBG_SI + Sys_Printf("OnCancel calling Undo_Undo\n"); +#endif + g_bListenUpdate = false; + Undo_Undo(TRUE); + g_bListenUpdate = true; + m_nUndoId = 0; + } + HideDlg(); +} + + diff --git a/plugins/surface_quake2/surfaceflagsdialog_quake2.cpp b/plugins/surface_quake2/surfaceflagsdialog_quake2.cpp index 6386d1e3..5978b4d5 100644 --- a/plugins/surface_quake2/surfaceflagsdialog_quake2.cpp +++ b/plugins/surface_quake2/surfaceflagsdialog_quake2.cpp @@ -1,1168 +1,1168 @@ -/* -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 -*/ - -#include -#include - -#include "surfdlg_plugin.h" - -#include "surfaceflagsdialog_quake2.h" - - GtkWidget *notebook1; - - GtkWidget *surface_lightbutton; - GtkWidget *surface_slickbutton; - GtkWidget *surface_skybutton; - GtkWidget *surface_warpbutton; - GtkWidget *surface_trans33button; - GtkWidget *surface_trans66button; - GtkWidget *surface_flowingbutton; - GtkWidget *surface_nodrawbutton; - GtkWidget *surface_hintbutton; - GtkWidget *surface_skipbutton; - - GtkWidget *content_solidbutton; - GtkWidget *content_windowbutton; - GtkWidget *content_auxbutton; - GtkWidget *content_lavabutton; - GtkWidget *content_slimebutton; - GtkWidget *content_waterbutton; - GtkWidget *content_mistbutton; - GtkWidget *content_areaportalbutton; - GtkWidget *content_playerclipbutton; - GtkWidget *content_monsterclipbutton; - GtkWidget *content_current0button; - GtkWidget *content_current90button; - GtkWidget *content_current180button; - GtkWidget *content_current270button; - GtkWidget *content_currentUPbutton; - GtkWidget *content_currentDOWNbutton; - GtkWidget *content_originbutton; - GtkWidget *content_detailbutton; - GtkWidget *content_translucentbutton; - GtkWidget *content_ladderbutton; - - GtkWidget *surfacebutton; - GtkWidget *contentbutton; - - GtkWidget *value_entry; - gboolean setup_buttons = TRUE; - - int working_surface_flags; - int surface_mask; - int working_content_flags; - int content_mask; - int working_value; - -inline void set_inconsistent(GtkWidget *toggle_button) -{ - gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON (toggle_button), TRUE); -} - -inline void clear_inconsistent(GtkWidget *toggle_button) -{ - GtkWidget *button_label; - - if ( gtk_toggle_button_get_inconsistent(GTK_TOGGLE_BUTTON (toggle_button)) ) - { - gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON (toggle_button), FALSE); - } - -} - -void clear_all_inconsistent(void) -{ - clear_inconsistent( surface_lightbutton ); - clear_inconsistent( surface_slickbutton ); - clear_inconsistent( surface_skybutton ); - clear_inconsistent( surface_warpbutton ); - clear_inconsistent( surface_trans33button ); - clear_inconsistent( surface_trans66button ); - clear_inconsistent( surface_flowingbutton ); - clear_inconsistent( surface_nodrawbutton ); - clear_inconsistent( surface_hintbutton ); - clear_inconsistent( surface_skipbutton ); - - clear_inconsistent( content_solidbutton ); - clear_inconsistent( content_windowbutton ); - clear_inconsistent( content_auxbutton ); - clear_inconsistent( content_lavabutton ); - clear_inconsistent( content_slimebutton ); - clear_inconsistent( content_waterbutton ); - clear_inconsistent( content_mistbutton ); - clear_inconsistent( content_areaportalbutton ); - clear_inconsistent( content_playerclipbutton ); - clear_inconsistent( content_monsterclipbutton ); - clear_inconsistent( content_current0button ); - clear_inconsistent( content_current90button ); - clear_inconsistent( content_current180button ); - clear_inconsistent( content_current270button ); - clear_inconsistent( content_currentUPbutton ); - clear_inconsistent( content_currentDOWNbutton ); - clear_inconsistent( content_originbutton ); - clear_inconsistent( content_detailbutton ); - clear_inconsistent( content_translucentbutton ); - clear_inconsistent( content_ladderbutton ); -} - -void clear_all_buttons_and_values() -{ - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_lightbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_slickbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skybutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_warpbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans33button ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans66button ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_flowingbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_nodrawbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_hintbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skipbutton ), FALSE); - - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_solidbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_windowbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_auxbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_lavabutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_slimebutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_waterbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_mistbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_areaportalbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_playerclipbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_monsterclipbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current0button ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current90button ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current180button ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current270button ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentUPbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentDOWNbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_originbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_detailbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_translucentbutton ), FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_ladderbutton ), FALSE); - - gtk_entry_set_text( (GtkEntry *)value_entry, ""); -} - -void SetFlagButtons_Quake2(texdef_to_face_t *texdef_face_list, bool b_isListEmpty) -{ - int i; - int contents = 0; - int flags = 0; - int value = 0; - int diff_contents = 0; - int diff_flags = 0; - gboolean diff_value = FALSE; - char tex_buff[11]; - texdef_t* tmp_texdef; - texdef_to_face_t* temp_texdef_face_list; - - - setup_buttons = TRUE; - working_surface_flags = 0; - surface_mask = 0; - working_content_flags = 0; - content_mask = 0; - working_value = 0; - - if(!b_isListEmpty) - { - tmp_texdef = &texdef_face_list->texdef; - contents = tmp_texdef->contents; - flags = tmp_texdef->flags; - value = tmp_texdef->value; - - Sys_Printf("Surface: %d\tContents: %d\tValue: %d\ttmp_texdef\n",tmp_texdef->flags,tmp_texdef->contents,tmp_texdef->value); - Sys_Printf("Surface: %d\tContents: %d\tValue: %d\n",flags,contents,value); - - for (temp_texdef_face_list = texdef_face_list->next; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = &temp_texdef_face_list->texdef; - diff_contents |= contents ^ tmp_texdef->contents; // Figure out which buttons are inconsistent - diff_flags |= flags ^ tmp_texdef->flags; - if (tmp_texdef->value != value) - diff_value = TRUE; - - Sys_Printf("Surface: %d\tContents: %d\tValue: %d\ttmp_texdef\n",tmp_texdef->flags,tmp_texdef->contents,tmp_texdef->value); - Sys_Printf("Surface: %d\tContents: %d\tValue: %d\n",flags,contents,value); - - } - } - - - - clear_all_inconsistent(); - - // If no faces/brushes are selected, clear everything and bail - if(b_isListEmpty) - { - clear_all_buttons_and_values(); - setup_buttons = FALSE; - return; - } - - // Set surface buttons to reflect brush/face flags, contents, and values - if(diff_flags & QUAKE2_SURF_LIGHT) - set_inconsistent(surface_lightbutton); - else if(flags & QUAKE2_SURF_LIGHT) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (surface_lightbutton), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (surface_lightbutton), FALSE); - - if(diff_flags & QUAKE2_SURF_SLICK) - set_inconsistent(surface_slickbutton); - else if(flags & QUAKE2_SURF_SLICK) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_slickbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_slickbutton ), FALSE); - - if(diff_flags & QUAKE2_SURF_SKY) - set_inconsistent(surface_skybutton); - else if(flags & QUAKE2_SURF_SKY) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skybutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skybutton ), FALSE); - - if(diff_flags & QUAKE2_SURF_WARP) - set_inconsistent(surface_warpbutton); - else if(flags & QUAKE2_SURF_WARP) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_warpbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_warpbutton ), FALSE); - - if(diff_flags & QUAKE2_SURF_TRANS33) - set_inconsistent(surface_trans33button); - else if(flags & QUAKE2_SURF_TRANS33) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans33button ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans33button ), FALSE); - - if(diff_flags & QUAKE2_SURF_TRANS66) - set_inconsistent(surface_trans66button); - else if(flags & QUAKE2_SURF_TRANS66) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans66button ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans66button ), FALSE); - - if(diff_flags & QUAKE2_SURF_FLOWING) - set_inconsistent(surface_flowingbutton); - else if(flags & QUAKE2_SURF_FLOWING) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_flowingbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_flowingbutton ), FALSE); - - if(diff_flags & QUAKE2_SURF_NODRAW) - set_inconsistent(surface_nodrawbutton); - else if(flags & QUAKE2_SURF_NODRAW) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_nodrawbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_nodrawbutton ), FALSE); - - if(diff_flags & QUAKE2_SURF_HINT) - set_inconsistent(surface_hintbutton); - else if(flags & QUAKE2_SURF_HINT) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_hintbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_hintbutton ), FALSE); - - if(diff_flags & QUAKE2_SURF_SKIP) - set_inconsistent(surface_skipbutton); - else if(flags & QUAKE2_SURF_SKIP) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skipbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skipbutton ), FALSE); - - // Set content buttons to reflect brush values - if(diff_contents & QUAKE2_CONTENTS_SOLID) - set_inconsistent(content_solidbutton); - else if(contents & QUAKE2_CONTENTS_SOLID) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_solidbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_solidbutton ), FALSE); - - if(diff_contents & QUAKE2_CONTENTS_WINDOW) - set_inconsistent(content_windowbutton); - else if(contents & QUAKE2_CONTENTS_WINDOW) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_windowbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_windowbutton ), FALSE); - - if(diff_contents & QUAKE2_CONTENTS_AUX) - set_inconsistent(content_auxbutton); - else if(contents & QUAKE2_CONTENTS_AUX) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_auxbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_auxbutton ), FALSE); - - if(diff_contents & QUAKE2_CONTENTS_LAVA) - set_inconsistent(content_lavabutton); - else if(contents & QUAKE2_CONTENTS_LAVA) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_lavabutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_lavabutton ), FALSE); - - if(diff_contents & QUAKE2_CONTENTS_SLIME) - set_inconsistent(content_slimebutton); - else if(contents & QUAKE2_CONTENTS_SLIME) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_slimebutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_slimebutton ), FALSE); - - if(diff_contents & QUAKE2_CONTENTS_WATER) - set_inconsistent(content_waterbutton); - else if(contents & QUAKE2_CONTENTS_WATER) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_waterbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_waterbutton ), FALSE); - - if(diff_contents & QUAKE2_CONTENTS_MIST) - set_inconsistent(content_mistbutton); - else if(contents & QUAKE2_CONTENTS_MIST) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_mistbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_mistbutton ), FALSE); - - if(diff_contents & QUAKE2_CONTENTS_AREAPORTAL) - set_inconsistent(content_areaportalbutton); - else if(contents & QUAKE2_CONTENTS_AREAPORTAL) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_areaportalbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_areaportalbutton ), FALSE); - - if(diff_contents & QUAKE2_CONTENTS_PLAYERCLIP) - set_inconsistent(content_playerclipbutton); - else if(contents & QUAKE2_CONTENTS_PLAYERCLIP) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_playerclipbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_playerclipbutton ), FALSE); - - if(diff_contents & QUAKE2_CONTENTS_MONSTERCLIP) - set_inconsistent(content_monsterclipbutton); - else if(contents & QUAKE2_CONTENTS_MONSTERCLIP) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_monsterclipbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_monsterclipbutton ), FALSE); - - if(diff_contents & QUAKE2_CONTENTS_CURRENT_0) - set_inconsistent(content_current0button); - else if(contents & QUAKE2_CONTENTS_CURRENT_0) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current0button ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current0button ), FALSE); - - if(diff_contents & QUAKE2_CONTENTS_CURRENT_90) - set_inconsistent(content_current90button); - else if(contents & QUAKE2_CONTENTS_CURRENT_90) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current90button ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current90button ), FALSE); - - if(diff_contents & QUAKE2_CONTENTS_CURRENT_180) - set_inconsistent(content_current180button); - else if(contents & QUAKE2_CONTENTS_CURRENT_180) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current180button ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current180button ), FALSE); - - if(diff_contents & QUAKE2_CONTENTS_CURRENT_270) - set_inconsistent(content_current270button); - else if(contents & QUAKE2_CONTENTS_CURRENT_270) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current270button ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current270button ), FALSE); - - if(diff_contents & QUAKE2_CONTENTS_CURRENT_UP) - set_inconsistent(content_currentUPbutton); - else if(contents & QUAKE2_CONTENTS_CURRENT_UP) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentUPbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentUPbutton ), FALSE); - - if(diff_contents & QUAKE2_CONTENTS_CURRENT_DOWN) - set_inconsistent(content_currentDOWNbutton); - else if(contents & QUAKE2_CONTENTS_CURRENT_DOWN) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentDOWNbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentDOWNbutton ), FALSE); - - if(diff_contents & QUAKE2_CONTENTS_ORIGIN) - set_inconsistent(content_originbutton); - else if(contents & QUAKE2_CONTENTS_ORIGIN) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_originbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_originbutton ), FALSE); - - if(diff_contents & QUAKE2_CONTENTS_DETAIL) - set_inconsistent(content_detailbutton); - else if(contents & QUAKE2_CONTENTS_DETAIL) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_detailbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_detailbutton ), FALSE); - - if(diff_contents & QUAKE2_CONTENTS_TRANSLUCENT) - set_inconsistent(content_translucentbutton); - else if(contents & QUAKE2_CONTENTS_TRANSLUCENT) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_translucentbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_translucentbutton ), FALSE); - - if(diff_contents & QUAKE2_CONTENTS_LADDER) - set_inconsistent(content_ladderbutton); - else if(contents & QUAKE2_CONTENTS_LADDER) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_ladderbutton ), TRUE); - else - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_ladderbutton ), FALSE); - - // Set Value - if(diff_value) - gtk_entry_set_text( (GtkEntry *)value_entry, ""); - else - { - working_value = value; - sprintf( tex_buff, "%d", value); - gtk_entry_set_text( (GtkEntry *)value_entry, tex_buff); - } - - setup_buttons = FALSE; -} - -void SetChangeInFlags_Face_Quake2 (texdef_to_face_t *texdef_face_list) -{ - texdef_to_face_t *temp_texdef_face_list; - texdef_t *tmp_texdef; - - for (temp_texdef_face_list = texdef_face_list; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - tmp_texdef = &temp_texdef_face_list->texdef; - tmp_texdef->flags = (tmp_texdef->flags & ~surface_mask) | working_surface_flags; - tmp_texdef->contents = (tmp_texdef->contents & ~content_mask) | working_content_flags; - tmp_texdef->value = working_value; - Sys_Printf("content_flag: %d content_mask: %d\n",working_content_flags,content_mask); - Sys_Printf("content: %d\n",tmp_texdef->contents); - } -} - -inline void change_surfaceflag (GtkWidget *togglebutton, int sur_flag, gboolean change_flag_to) -{ - - if (!setup_buttons) // If we're setting up the buttons, we really don't need to - { // set flags that are already set - - if (gtk_toggle_button_get_inconsistent(GTK_TOGGLE_BUTTON (togglebutton))) // Clear out inconsistent, if set - clear_inconsistent(GTK_WIDGET (togglebutton)); - - surface_mask |= sur_flag; - - if (change_flag_to) - working_surface_flags |= sur_flag; - else - working_surface_flags &= ~sur_flag; - } -} - -inline void change_contentflag (GtkWidget *togglebutton, int content_flag, gboolean change_flag_to) -{ - - if ( (!setup_buttons) ) // If we're setting up the buttons, we really don't need to - { // set flags that are already set - - if (gtk_toggle_button_get_inconsistent(GTK_TOGGLE_BUTTON (togglebutton))) - clear_inconsistent(togglebutton); - //if (g_ptrSelectedFaces.GetSize() == 0) // Only changing content flags on whole brushes, not faces. - //{ - content_mask |= content_flag; - - if (change_flag_to) - working_content_flags |= content_flag; - else - working_content_flags &= ~content_flag; - //} - Sys_Printf("content_flag: %d content_mask: %d\n",content_flag,content_mask); - } -} - -// Surface Flags Callbacks -void -on_surface_lightbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_surfaceflag(surface_lightbutton, QUAKE2_SURF_LIGHT, (GTK_TOGGLE_BUTTON (surface_lightbutton)->active)); - -} - -void -on_surface_slickbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_surfaceflag(surface_slickbutton, QUAKE2_SURF_SLICK, (GTK_TOGGLE_BUTTON (surface_slickbutton)->active)); - -} - -void -on_surface_skybutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_surfaceflag(surface_skybutton, QUAKE2_SURF_SKY, (GTK_TOGGLE_BUTTON (surface_skybutton)->active)); -} - -void -on_surface_warpbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_surfaceflag(surface_warpbutton, QUAKE2_SURF_WARP, (GTK_TOGGLE_BUTTON (surface_warpbutton)->active)); -} - -void -on_surface_trans33button_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_surfaceflag(surface_trans33button, QUAKE2_SURF_TRANS33, (GTK_TOGGLE_BUTTON (surface_trans33button)->active)); -} - -void -on_surface_trans66button_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_surfaceflag(surface_trans66button, QUAKE2_SURF_TRANS66, (GTK_TOGGLE_BUTTON (surface_trans66button)->active)); -} - -void -on_surface_flowingbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_surfaceflag(surface_flowingbutton, QUAKE2_SURF_FLOWING, (GTK_TOGGLE_BUTTON (surface_flowingbutton)->active)); -} - -void -on_surface_nodrawbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_surfaceflag(surface_nodrawbutton, QUAKE2_SURF_NODRAW, (GTK_TOGGLE_BUTTON (surface_nodrawbutton)->active)); -} - -void -on_surface_hintbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_surfaceflag(surface_hintbutton, QUAKE2_SURF_HINT, (GTK_TOGGLE_BUTTON (surface_hintbutton)->active)); -} - -void -on_surface_skipbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_surfaceflag(surface_skipbutton, QUAKE2_SURF_SKIP, (GTK_TOGGLE_BUTTON (surface_skipbutton)->active)); -} - -// Content Flags Callbacks -void -on_content_solidbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_solidbutton, QUAKE2_CONTENTS_SOLID, (GTK_TOGGLE_BUTTON (content_solidbutton)->active)); -} - -void -on_content_windowbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_windowbutton, QUAKE2_CONTENTS_WINDOW, (GTK_TOGGLE_BUTTON (content_windowbutton)->active)); -} - -void -on_content_auxbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_auxbutton, QUAKE2_CONTENTS_AUX, (GTK_TOGGLE_BUTTON (content_auxbutton)->active)); -} - -void -on_content_lavabutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_lavabutton, QUAKE2_CONTENTS_LAVA, (GTK_TOGGLE_BUTTON (content_lavabutton)->active)); -} - -void -on_content_slimebutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_slimebutton, QUAKE2_CONTENTS_SLIME, (GTK_TOGGLE_BUTTON (content_slimebutton)->active)); -} - -void -on_content_waterbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_waterbutton, QUAKE2_CONTENTS_WATER, (GTK_TOGGLE_BUTTON (content_waterbutton)->active)); -} - -void -on_content_mistbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_mistbutton, QUAKE2_CONTENTS_MIST, (GTK_TOGGLE_BUTTON (content_mistbutton)->active)); -} - -void -on_content_areaportalbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_areaportalbutton, QUAKE2_CONTENTS_AREAPORTAL, (GTK_TOGGLE_BUTTON (content_areaportalbutton)->active)); -} - -void -on_content_playerclipbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_playerclipbutton, QUAKE2_CONTENTS_PLAYERCLIP, (GTK_TOGGLE_BUTTON (content_playerclipbutton)->active)); -} - -void -on_content_monsterclipbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_monsterclipbutton, QUAKE2_CONTENTS_MONSTERCLIP, (GTK_TOGGLE_BUTTON (content_monsterclipbutton)->active)); -} - -void -on_content_current0button_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_current0button, QUAKE2_CONTENTS_CURRENT_0, (GTK_TOGGLE_BUTTON (content_current0button)->active)); -} - -void -on_content_current90button_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_current90button, QUAKE2_CONTENTS_CURRENT_90, (GTK_TOGGLE_BUTTON (content_current90button)->active)); -} - -void -on_content_current180button_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_current180button, QUAKE2_CONTENTS_CURRENT_180, (GTK_TOGGLE_BUTTON (content_current180button)->active)); -} - -void -on_content_current270button_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_current270button, QUAKE2_CONTENTS_CURRENT_270, (GTK_TOGGLE_BUTTON (content_current270button)->active)); -} - -void -on_content_currentUPbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_currentUPbutton, QUAKE2_CONTENTS_CURRENT_UP, (GTK_TOGGLE_BUTTON (content_currentUPbutton)->active)); -} - -void -on_content_currentDOWNbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_currentDOWNbutton, QUAKE2_CONTENTS_CURRENT_DOWN, (GTK_TOGGLE_BUTTON (content_currentDOWNbutton)->active)); -} - -void -on_content_originbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_originbutton, QUAKE2_CONTENTS_ORIGIN, (GTK_TOGGLE_BUTTON (content_originbutton)->active)); -} - -void -on_content_detailbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_detailbutton, QUAKE2_CONTENTS_DETAIL, (GTK_TOGGLE_BUTTON (content_detailbutton)->active)); -} - -void -on_content_translucentbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_translucentbutton, QUAKE2_CONTENTS_TRANSLUCENT, (GTK_TOGGLE_BUTTON (content_translucentbutton)->active)); -} - -void -on_content_ladderbutton_toggled (GtkToggleButton *togglebutton, - gpointer user_data) -{ - change_contentflag(content_ladderbutton, QUAKE2_CONTENTS_LADDER, (GTK_TOGGLE_BUTTON (content_ladderbutton)->active)); -} - -// Value Entry Callback -void -on_value_entry_changed (GtkEditable *editable, - gpointer user_data) -{ - if ( (!setup_buttons) ) // If we're setting up the buttons, don't change value - working_value = atoi( gtk_entry_get_text( (GtkEntry*)editable) ); -} - -void -on_value_entry_insert_text (GtkEditable *editable, - gchar *new_text, - gint new_text_length, - gint *position, - gpointer user_data) -{ - int i, count=0; - gchar *result; - int entry_value; - texdef_t *pt; - brush_t *b; - face_t *f; - - // Limit input to digits, throwing out anything else - // Modified from Gtk FAQ for text filtering of GtkEntry - result = g_new (gchar, new_text_length); - - for (i=0; i < new_text_length; i++) { - if (!isdigit(new_text[i])) - continue; - result[count++] = new_text[i]; - } - - if (count > 0) { - gtk_signal_handler_block_by_func (GTK_OBJECT (editable), - GTK_SIGNAL_FUNC (on_value_entry_insert_text), - user_data); - gtk_editable_insert_text (editable, result, count, position); - gtk_signal_handler_unblock_by_func (GTK_OBJECT (editable), - GTK_SIGNAL_FUNC (on_value_entry_insert_text), - user_data); - } - gtk_signal_emit_stop_by_name (GTK_OBJECT (editable), "insert_text"); - - g_free (result); -} - -void -on_surfacebutton_clicked (GtkButton *button, - gpointer user_data) -{ - gtk_notebook_set_page (GTK_NOTEBOOK(notebook1), 0); -} - -void -on_contentbutton_clicked (GtkButton *button, - gpointer user_data) -{ - gtk_notebook_set_page (GTK_NOTEBOOK(notebook1), 1); -} - - -#define QUAKE2_FLAG_BUTTON_BORDER 3 - -GtkWidget* Create_Quake2FlagsDialog (GtkWidget* surfacedialog_widget) -{ - GtkWidget *frame1; - GtkWidget *vbox1; - GtkWidget *vbox2; - GtkWidget *vbox3; - GtkWidget *vbox4; - GtkWidget *table4; - GtkWidget *hbox2; - GtkWidget *hbox3; - GtkWidget *hseparator1; - GtkWidget *value_label; - GtkWidget *label5; - GtkWidget *table3; - GtkWidget *label6; - GtkWidget *table1; - - - frame1 = gtk_frame_new ("Flags"); - gtk_widget_show (frame1); - gtk_container_add (GTK_CONTAINER (surfacedialog_widget), frame1); - - vbox1 = gtk_vbox_new (FALSE, 0); - gtk_widget_show (vbox1); - gtk_container_add (GTK_CONTAINER (frame1), vbox1); - - notebook1 = gtk_notebook_new (); - gtk_widget_show (notebook1); - gtk_box_pack_start (GTK_BOX (vbox1), notebook1, TRUE, TRUE, 0); - gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook1), TRUE); - gtk_container_set_border_width (GTK_CONTAINER (notebook1), 5); - - vbox2 = gtk_vbox_new (FALSE, 0); - gtk_widget_show (vbox2); - gtk_container_add (GTK_CONTAINER (notebook1), vbox2); - - table4 = gtk_table_new (3, 4, FALSE); - gtk_widget_show (table4); - gtk_box_pack_start (GTK_BOX (vbox2), table4, TRUE, TRUE, 0); - - surface_lightbutton = gtk_toggle_button_new_with_label ("Light"); - gtk_signal_connect (GTK_OBJECT (surface_lightbutton), "toggled", - GTK_SIGNAL_FUNC (on_surface_lightbutton_toggled), - NULL); - gtk_widget_show (surface_lightbutton); - gtk_table_attach (GTK_TABLE (table4), surface_lightbutton, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (surface_lightbutton), QUAKE2_FLAG_BUTTON_BORDER); - - surface_slickbutton = gtk_toggle_button_new_with_label ("Slick"); - gtk_signal_connect (GTK_OBJECT (surface_slickbutton), "toggled", - GTK_SIGNAL_FUNC (on_surface_slickbutton_toggled), - NULL); - gtk_widget_show (surface_slickbutton); - gtk_table_attach (GTK_TABLE (table4), surface_slickbutton, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (surface_slickbutton), QUAKE2_FLAG_BUTTON_BORDER); - - surface_skybutton = gtk_toggle_button_new_with_label ("Sky"); - gtk_signal_connect (GTK_OBJECT (surface_skybutton), "toggled", - GTK_SIGNAL_FUNC (on_surface_skybutton_toggled), - NULL); - gtk_widget_show (surface_skybutton); - gtk_table_attach (GTK_TABLE (table4), surface_skybutton, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (surface_skybutton), QUAKE2_FLAG_BUTTON_BORDER); - - surface_warpbutton = gtk_toggle_button_new_with_label ("Warp"); - gtk_signal_connect (GTK_OBJECT (surface_warpbutton), "toggled", - GTK_SIGNAL_FUNC (on_surface_warpbutton_toggled), - NULL); - gtk_widget_show (surface_warpbutton); - gtk_table_attach (GTK_TABLE (table4), surface_warpbutton, 3, 4, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (surface_warpbutton), QUAKE2_FLAG_BUTTON_BORDER); - - surface_trans33button = gtk_toggle_button_new_with_label ("Trans 33"); - gtk_signal_connect (GTK_OBJECT (surface_trans33button), "toggled", - GTK_SIGNAL_FUNC (on_surface_trans33button_toggled), - NULL); - gtk_widget_show (surface_trans33button); - gtk_table_attach (GTK_TABLE (table4), surface_trans33button, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (surface_trans33button), QUAKE2_FLAG_BUTTON_BORDER); - - surface_trans66button = gtk_toggle_button_new_with_label ("Trans 66"); - gtk_signal_connect (GTK_OBJECT (surface_trans66button), "toggled", - GTK_SIGNAL_FUNC (on_surface_trans66button_toggled), - NULL); - gtk_widget_show (surface_trans66button); - gtk_table_attach (GTK_TABLE (table4), surface_trans66button, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (surface_trans66button), QUAKE2_FLAG_BUTTON_BORDER); - - surface_flowingbutton = gtk_toggle_button_new_with_label ("Flowing"); - gtk_signal_connect (GTK_OBJECT (surface_flowingbutton), "toggled", - GTK_SIGNAL_FUNC (on_surface_flowingbutton_toggled), - NULL); - gtk_widget_show (surface_flowingbutton); - gtk_table_attach (GTK_TABLE (table4), surface_flowingbutton, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (surface_flowingbutton), QUAKE2_FLAG_BUTTON_BORDER); - - surface_nodrawbutton = gtk_toggle_button_new_with_label ("NoDraw"); - gtk_signal_connect (GTK_OBJECT (surface_nodrawbutton), "toggled", - GTK_SIGNAL_FUNC (on_surface_nodrawbutton_toggled), - NULL); - gtk_widget_show (surface_nodrawbutton); - gtk_table_attach (GTK_TABLE (table4), surface_nodrawbutton, 3, 4, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (surface_nodrawbutton), QUAKE2_FLAG_BUTTON_BORDER); - - surface_hintbutton = gtk_toggle_button_new_with_label ("Hint"); - gtk_signal_connect (GTK_OBJECT (surface_hintbutton), "toggled", - GTK_SIGNAL_FUNC (on_surface_hintbutton_toggled), - NULL); - gtk_widget_show (surface_hintbutton); - gtk_table_attach (GTK_TABLE (table4), surface_hintbutton, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (surface_hintbutton), QUAKE2_FLAG_BUTTON_BORDER); - - surface_skipbutton = gtk_toggle_button_new_with_label ("Skip"); - gtk_signal_connect (GTK_OBJECT (surface_skipbutton), "toggled", - GTK_SIGNAL_FUNC (on_surface_skipbutton_toggled), - NULL); - gtk_widget_show (surface_skipbutton); - gtk_table_attach (GTK_TABLE (table4), surface_skipbutton, 3, 4, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (surface_skipbutton), QUAKE2_FLAG_BUTTON_BORDER); - - hseparator1 = gtk_hseparator_new (); - gtk_widget_show (hseparator1); - gtk_box_pack_start (GTK_BOX (vbox2), hseparator1, FALSE, FALSE, 0); - gtk_widget_set_usize (hseparator1, -2, 5); - - hbox2 = gtk_hbox_new (FALSE, 0); - gtk_widget_show (hbox2); - gtk_box_pack_start (GTK_BOX (vbox2), hbox2, FALSE, FALSE, 0); - - hbox3 = gtk_hbox_new (FALSE, 0); - gtk_widget_show (hbox3); - gtk_box_pack_start (GTK_BOX (hbox2), hbox3, TRUE, TRUE, 0); - - vbox4 = gtk_vbox_new (FALSE, 0); - gtk_widget_show (vbox4); - gtk_box_pack_start (GTK_BOX (hbox3), vbox4, TRUE, TRUE, 0); - - value_label = gtk_label_new (" Value: "); - gtk_widget_show (value_label); - gtk_box_pack_start (GTK_BOX (hbox3), value_label, FALSE, FALSE, 0); - - value_entry = gtk_entry_new (); - gtk_signal_connect (GTK_OBJECT (value_entry), "changed", - GTK_SIGNAL_FUNC (on_value_entry_changed), - NULL); - gtk_signal_connect (GTK_OBJECT (value_entry), "insert_text", - GTK_SIGNAL_FUNC (on_value_entry_insert_text), - NULL); - gtk_entry_set_max_length( (GtkEntry *)value_entry, 11); - gtk_widget_show (value_entry); - gtk_box_pack_start (GTK_BOX (hbox3), value_entry, TRUE, TRUE, 0); - - vbox3 = gtk_vbox_new (FALSE, 0); - gtk_widget_show (vbox3); - gtk_box_pack_start (GTK_BOX (hbox3), vbox3, TRUE, TRUE, 0); - - label5 = gtk_label_new ("Surface Flags"); - gtk_widget_show (label5); - gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 0), label5); - - table3 = gtk_table_new (5, 4, FALSE); - gtk_widget_show (table3); - gtk_container_add (GTK_CONTAINER (notebook1), table3); - - content_solidbutton = gtk_toggle_button_new_with_label ("Solid"); - gtk_signal_connect (GTK_OBJECT (content_solidbutton), "toggled", - GTK_SIGNAL_FUNC (on_content_solidbutton_toggled), - NULL); - gtk_widget_show (content_solidbutton); - gtk_table_attach (GTK_TABLE (table3), content_solidbutton, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (content_solidbutton), QUAKE2_FLAG_BUTTON_BORDER); - - content_windowbutton = gtk_toggle_button_new_with_label ("Window"); - gtk_signal_connect (GTK_OBJECT (content_windowbutton), "toggled", - GTK_SIGNAL_FUNC (on_content_windowbutton_toggled), - NULL); - gtk_widget_show (content_windowbutton); - gtk_table_attach (GTK_TABLE (table3), content_windowbutton, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (content_windowbutton), QUAKE2_FLAG_BUTTON_BORDER); - - content_auxbutton = gtk_toggle_button_new_with_label ("Aux"); - gtk_signal_connect (GTK_OBJECT (content_auxbutton), "toggled", - GTK_SIGNAL_FUNC (on_content_auxbutton_toggled), - NULL); - gtk_widget_show (content_auxbutton); - gtk_table_attach (GTK_TABLE (table3), content_auxbutton, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (content_auxbutton), QUAKE2_FLAG_BUTTON_BORDER); - - content_lavabutton = gtk_toggle_button_new_with_label ("Lava"); - gtk_signal_connect (GTK_OBJECT (content_lavabutton), "toggled", - GTK_SIGNAL_FUNC (on_content_lavabutton_toggled), - NULL); - gtk_widget_show (content_lavabutton); - gtk_table_attach (GTK_TABLE (table3), content_lavabutton, 3, 4, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (content_lavabutton), QUAKE2_FLAG_BUTTON_BORDER); - - content_slimebutton = gtk_toggle_button_new_with_label ("Slime"); - gtk_signal_connect (GTK_OBJECT (content_slimebutton), "toggled", - GTK_SIGNAL_FUNC (on_content_slimebutton_toggled), - NULL); - gtk_widget_show (content_slimebutton); - gtk_table_attach (GTK_TABLE (table3), content_slimebutton, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (content_slimebutton), QUAKE2_FLAG_BUTTON_BORDER); - - content_waterbutton = gtk_toggle_button_new_with_label ("Water"); - gtk_signal_connect (GTK_OBJECT (content_waterbutton), "toggled", - GTK_SIGNAL_FUNC (on_content_waterbutton_toggled), - NULL); - gtk_widget_show (content_waterbutton); - gtk_table_attach (GTK_TABLE (table3), content_waterbutton, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (content_waterbutton), QUAKE2_FLAG_BUTTON_BORDER); - - content_mistbutton = gtk_toggle_button_new_with_label ("Mist"); - gtk_signal_connect (GTK_OBJECT (content_mistbutton), "toggled", - GTK_SIGNAL_FUNC (on_content_mistbutton_toggled), - NULL); - gtk_widget_show (content_mistbutton); - gtk_table_attach (GTK_TABLE (table3), content_mistbutton, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (content_mistbutton), QUAKE2_FLAG_BUTTON_BORDER); - - content_areaportalbutton = gtk_toggle_button_new_with_label ("AreaPortal"); - gtk_signal_connect (GTK_OBJECT (content_areaportalbutton), "toggled", - GTK_SIGNAL_FUNC (on_content_areaportalbutton_toggled), - NULL); - gtk_widget_show (content_areaportalbutton); - gtk_table_attach (GTK_TABLE (table3), content_areaportalbutton, 3, 4, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (content_areaportalbutton), QUAKE2_FLAG_BUTTON_BORDER); - - content_playerclipbutton = gtk_toggle_button_new_with_label ("PlayerClip"); - gtk_signal_connect (GTK_OBJECT (content_playerclipbutton), "toggled", - GTK_SIGNAL_FUNC (on_content_playerclipbutton_toggled), - NULL); - gtk_widget_show (content_playerclipbutton); - gtk_table_attach (GTK_TABLE (table3), content_playerclipbutton, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (content_playerclipbutton), QUAKE2_FLAG_BUTTON_BORDER); - - content_monsterclipbutton = gtk_toggle_button_new_with_label ("MonsterClip"); - gtk_signal_connect (GTK_OBJECT (content_monsterclipbutton), "toggled", - GTK_SIGNAL_FUNC (on_content_monsterclipbutton_toggled), - NULL); - gtk_widget_show (content_monsterclipbutton); - gtk_table_attach (GTK_TABLE (table3), content_monsterclipbutton, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (content_monsterclipbutton), QUAKE2_FLAG_BUTTON_BORDER); - - content_current0button = gtk_toggle_button_new_with_label ("Current 0"); - gtk_signal_connect (GTK_OBJECT (content_current0button), "toggled", - GTK_SIGNAL_FUNC (on_content_current0button_toggled), - NULL); - gtk_widget_show (content_current0button); - gtk_table_attach (GTK_TABLE (table3), content_current0button, 2, 3, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (content_current0button), QUAKE2_FLAG_BUTTON_BORDER); - - content_current90button = gtk_toggle_button_new_with_label ("Current 90"); - gtk_signal_connect (GTK_OBJECT (content_current90button), "toggled", - GTK_SIGNAL_FUNC (on_content_current90button_toggled), - NULL); - gtk_widget_show (content_current90button); - gtk_table_attach (GTK_TABLE (table3), content_current90button, 3, 4, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (content_current90button), QUAKE2_FLAG_BUTTON_BORDER); - - content_current180button = gtk_toggle_button_new_with_label ("Current 180"); - gtk_signal_connect (GTK_OBJECT (content_current180button), "toggled", - GTK_SIGNAL_FUNC (on_content_current180button_toggled), - NULL); - gtk_widget_show (content_current180button); - gtk_table_attach (GTK_TABLE (table3), content_current180button, 0, 1, 3, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (content_current180button), QUAKE2_FLAG_BUTTON_BORDER); - - content_current270button = gtk_toggle_button_new_with_label ("Current 270"); - gtk_signal_connect (GTK_OBJECT (content_current270button), "toggled", - GTK_SIGNAL_FUNC (on_content_current270button_toggled), - NULL); - gtk_widget_show (content_current270button); - gtk_table_attach (GTK_TABLE (table3), content_current270button, 1, 2, 3, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (content_current270button), QUAKE2_FLAG_BUTTON_BORDER); - - content_currentUPbutton = gtk_toggle_button_new_with_label ("Current UP"); - gtk_signal_connect (GTK_OBJECT (content_currentUPbutton), "toggled", - GTK_SIGNAL_FUNC (on_content_currentUPbutton_toggled), - NULL); - gtk_widget_show (content_currentUPbutton); - gtk_table_attach (GTK_TABLE (table3), content_currentUPbutton, 2, 3, 3, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (content_currentUPbutton), QUAKE2_FLAG_BUTTON_BORDER); - - content_currentDOWNbutton = gtk_toggle_button_new_with_label ("Current DOWN"); - gtk_signal_connect (GTK_OBJECT (content_currentDOWNbutton), "toggled", - GTK_SIGNAL_FUNC (on_content_currentDOWNbutton_toggled), - NULL); - gtk_widget_show (content_currentDOWNbutton); - gtk_table_attach (GTK_TABLE (table3), content_currentDOWNbutton, 3, 4, 3, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (content_currentDOWNbutton), QUAKE2_FLAG_BUTTON_BORDER); - - content_originbutton = gtk_toggle_button_new_with_label ("Origin"); - gtk_signal_connect (GTK_OBJECT (content_originbutton), "toggled", - GTK_SIGNAL_FUNC (on_content_originbutton_toggled), - NULL); - gtk_widget_show (content_originbutton); - gtk_table_attach (GTK_TABLE (table3), content_originbutton, 0, 1, 4, 5, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (content_originbutton), QUAKE2_FLAG_BUTTON_BORDER); - - content_detailbutton = gtk_toggle_button_new_with_label ("Detail"); - gtk_signal_connect (GTK_OBJECT (content_detailbutton), "toggled", - GTK_SIGNAL_FUNC (on_content_detailbutton_toggled), - NULL); - gtk_widget_show (content_detailbutton); - gtk_table_attach (GTK_TABLE (table3), content_detailbutton, 1, 2, 4, 5, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (content_detailbutton), QUAKE2_FLAG_BUTTON_BORDER); - - content_translucentbutton = gtk_toggle_button_new_with_label ("Translucent"); - gtk_signal_connect (GTK_OBJECT (content_translucentbutton), "toggled", - GTK_SIGNAL_FUNC (on_content_translucentbutton_toggled), - NULL); - gtk_widget_show (content_translucentbutton); - gtk_table_attach (GTK_TABLE (table3), content_translucentbutton, 2, 3, 4, 5, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (content_translucentbutton), QUAKE2_FLAG_BUTTON_BORDER); - - content_ladderbutton = gtk_toggle_button_new_with_label ("Ladder"); - gtk_signal_connect (GTK_OBJECT (content_ladderbutton), "toggled", - GTK_SIGNAL_FUNC (on_content_ladderbutton_toggled), - NULL); - gtk_widget_show (content_ladderbutton); - gtk_table_attach (GTK_TABLE (table3), content_ladderbutton, 3, 4, 4, 5, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (content_ladderbutton), QUAKE2_FLAG_BUTTON_BORDER); - - label6 = gtk_label_new ("Content Flags"); - gtk_widget_show (label6); - gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 1), label6); - - return frame1; -} - +/* +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 +*/ + +#include +#include + +#include "surfdlg_plugin.h" + +#include "surfaceflagsdialog_quake2.h" + + GtkWidget *notebook1; + + GtkWidget *surface_lightbutton; + GtkWidget *surface_slickbutton; + GtkWidget *surface_skybutton; + GtkWidget *surface_warpbutton; + GtkWidget *surface_trans33button; + GtkWidget *surface_trans66button; + GtkWidget *surface_flowingbutton; + GtkWidget *surface_nodrawbutton; + GtkWidget *surface_hintbutton; + GtkWidget *surface_skipbutton; + + GtkWidget *content_solidbutton; + GtkWidget *content_windowbutton; + GtkWidget *content_auxbutton; + GtkWidget *content_lavabutton; + GtkWidget *content_slimebutton; + GtkWidget *content_waterbutton; + GtkWidget *content_mistbutton; + GtkWidget *content_areaportalbutton; + GtkWidget *content_playerclipbutton; + GtkWidget *content_monsterclipbutton; + GtkWidget *content_current0button; + GtkWidget *content_current90button; + GtkWidget *content_current180button; + GtkWidget *content_current270button; + GtkWidget *content_currentUPbutton; + GtkWidget *content_currentDOWNbutton; + GtkWidget *content_originbutton; + GtkWidget *content_detailbutton; + GtkWidget *content_translucentbutton; + GtkWidget *content_ladderbutton; + + GtkWidget *surfacebutton; + GtkWidget *contentbutton; + + GtkWidget *value_entry; + gboolean setup_buttons = TRUE; + + int working_surface_flags; + int surface_mask; + int working_content_flags; + int content_mask; + int working_value; + +inline void set_inconsistent(GtkWidget *toggle_button) +{ + gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON (toggle_button), TRUE); +} + +inline void clear_inconsistent(GtkWidget *toggle_button) +{ + GtkWidget *button_label; + + if ( gtk_toggle_button_get_inconsistent(GTK_TOGGLE_BUTTON (toggle_button)) ) + { + gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON (toggle_button), FALSE); + } + +} + +void clear_all_inconsistent(void) +{ + clear_inconsistent( surface_lightbutton ); + clear_inconsistent( surface_slickbutton ); + clear_inconsistent( surface_skybutton ); + clear_inconsistent( surface_warpbutton ); + clear_inconsistent( surface_trans33button ); + clear_inconsistent( surface_trans66button ); + clear_inconsistent( surface_flowingbutton ); + clear_inconsistent( surface_nodrawbutton ); + clear_inconsistent( surface_hintbutton ); + clear_inconsistent( surface_skipbutton ); + + clear_inconsistent( content_solidbutton ); + clear_inconsistent( content_windowbutton ); + clear_inconsistent( content_auxbutton ); + clear_inconsistent( content_lavabutton ); + clear_inconsistent( content_slimebutton ); + clear_inconsistent( content_waterbutton ); + clear_inconsistent( content_mistbutton ); + clear_inconsistent( content_areaportalbutton ); + clear_inconsistent( content_playerclipbutton ); + clear_inconsistent( content_monsterclipbutton ); + clear_inconsistent( content_current0button ); + clear_inconsistent( content_current90button ); + clear_inconsistent( content_current180button ); + clear_inconsistent( content_current270button ); + clear_inconsistent( content_currentUPbutton ); + clear_inconsistent( content_currentDOWNbutton ); + clear_inconsistent( content_originbutton ); + clear_inconsistent( content_detailbutton ); + clear_inconsistent( content_translucentbutton ); + clear_inconsistent( content_ladderbutton ); +} + +void clear_all_buttons_and_values() +{ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_lightbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_slickbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skybutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_warpbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans33button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans66button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_flowingbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_nodrawbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_hintbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skipbutton ), FALSE); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_solidbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_windowbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_auxbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_lavabutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_slimebutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_waterbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_mistbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_areaportalbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_playerclipbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_monsterclipbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current0button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current90button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current180button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current270button ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentUPbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentDOWNbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_originbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_detailbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_translucentbutton ), FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_ladderbutton ), FALSE); + + gtk_entry_set_text( (GtkEntry *)value_entry, ""); +} + +void SetFlagButtons_Quake2(texdef_to_face_t *texdef_face_list, bool b_isListEmpty) +{ + int i; + int contents = 0; + int flags = 0; + int value = 0; + int diff_contents = 0; + int diff_flags = 0; + gboolean diff_value = FALSE; + char tex_buff[11]; + texdef_t* tmp_texdef; + texdef_to_face_t* temp_texdef_face_list; + + + setup_buttons = TRUE; + working_surface_flags = 0; + surface_mask = 0; + working_content_flags = 0; + content_mask = 0; + working_value = 0; + + if(!b_isListEmpty) + { + tmp_texdef = &texdef_face_list->texdef; + contents = tmp_texdef->contents; + flags = tmp_texdef->flags; + value = tmp_texdef->value; + + Sys_Printf("Surface: %d\tContents: %d\tValue: %d\ttmp_texdef\n",tmp_texdef->flags,tmp_texdef->contents,tmp_texdef->value); + Sys_Printf("Surface: %d\tContents: %d\tValue: %d\n",flags,contents,value); + + for (temp_texdef_face_list = texdef_face_list->next; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = &temp_texdef_face_list->texdef; + diff_contents |= contents ^ tmp_texdef->contents; // Figure out which buttons are inconsistent + diff_flags |= flags ^ tmp_texdef->flags; + if (tmp_texdef->value != value) + diff_value = TRUE; + + Sys_Printf("Surface: %d\tContents: %d\tValue: %d\ttmp_texdef\n",tmp_texdef->flags,tmp_texdef->contents,tmp_texdef->value); + Sys_Printf("Surface: %d\tContents: %d\tValue: %d\n",flags,contents,value); + + } + } + + + + clear_all_inconsistent(); + + // If no faces/brushes are selected, clear everything and bail + if(b_isListEmpty) + { + clear_all_buttons_and_values(); + setup_buttons = FALSE; + return; + } + + // Set surface buttons to reflect brush/face flags, contents, and values + if(diff_flags & QUAKE2_SURF_LIGHT) + set_inconsistent(surface_lightbutton); + else if(flags & QUAKE2_SURF_LIGHT) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (surface_lightbutton), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (surface_lightbutton), FALSE); + + if(diff_flags & QUAKE2_SURF_SLICK) + set_inconsistent(surface_slickbutton); + else if(flags & QUAKE2_SURF_SLICK) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_slickbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_slickbutton ), FALSE); + + if(diff_flags & QUAKE2_SURF_SKY) + set_inconsistent(surface_skybutton); + else if(flags & QUAKE2_SURF_SKY) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skybutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skybutton ), FALSE); + + if(diff_flags & QUAKE2_SURF_WARP) + set_inconsistent(surface_warpbutton); + else if(flags & QUAKE2_SURF_WARP) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_warpbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_warpbutton ), FALSE); + + if(diff_flags & QUAKE2_SURF_TRANS33) + set_inconsistent(surface_trans33button); + else if(flags & QUAKE2_SURF_TRANS33) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans33button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans33button ), FALSE); + + if(diff_flags & QUAKE2_SURF_TRANS66) + set_inconsistent(surface_trans66button); + else if(flags & QUAKE2_SURF_TRANS66) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans66button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_trans66button ), FALSE); + + if(diff_flags & QUAKE2_SURF_FLOWING) + set_inconsistent(surface_flowingbutton); + else if(flags & QUAKE2_SURF_FLOWING) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_flowingbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_flowingbutton ), FALSE); + + if(diff_flags & QUAKE2_SURF_NODRAW) + set_inconsistent(surface_nodrawbutton); + else if(flags & QUAKE2_SURF_NODRAW) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_nodrawbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_nodrawbutton ), FALSE); + + if(diff_flags & QUAKE2_SURF_HINT) + set_inconsistent(surface_hintbutton); + else if(flags & QUAKE2_SURF_HINT) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_hintbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_hintbutton ), FALSE); + + if(diff_flags & QUAKE2_SURF_SKIP) + set_inconsistent(surface_skipbutton); + else if(flags & QUAKE2_SURF_SKIP) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skipbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( surface_skipbutton ), FALSE); + + // Set content buttons to reflect brush values + if(diff_contents & QUAKE2_CONTENTS_SOLID) + set_inconsistent(content_solidbutton); + else if(contents & QUAKE2_CONTENTS_SOLID) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_solidbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_solidbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_WINDOW) + set_inconsistent(content_windowbutton); + else if(contents & QUAKE2_CONTENTS_WINDOW) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_windowbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_windowbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_AUX) + set_inconsistent(content_auxbutton); + else if(contents & QUAKE2_CONTENTS_AUX) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_auxbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_auxbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_LAVA) + set_inconsistent(content_lavabutton); + else if(contents & QUAKE2_CONTENTS_LAVA) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_lavabutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_lavabutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_SLIME) + set_inconsistent(content_slimebutton); + else if(contents & QUAKE2_CONTENTS_SLIME) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_slimebutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_slimebutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_WATER) + set_inconsistent(content_waterbutton); + else if(contents & QUAKE2_CONTENTS_WATER) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_waterbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_waterbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_MIST) + set_inconsistent(content_mistbutton); + else if(contents & QUAKE2_CONTENTS_MIST) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_mistbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_mistbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_AREAPORTAL) + set_inconsistent(content_areaportalbutton); + else if(contents & QUAKE2_CONTENTS_AREAPORTAL) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_areaportalbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_areaportalbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_PLAYERCLIP) + set_inconsistent(content_playerclipbutton); + else if(contents & QUAKE2_CONTENTS_PLAYERCLIP) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_playerclipbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_playerclipbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_MONSTERCLIP) + set_inconsistent(content_monsterclipbutton); + else if(contents & QUAKE2_CONTENTS_MONSTERCLIP) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_monsterclipbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_monsterclipbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_CURRENT_0) + set_inconsistent(content_current0button); + else if(contents & QUAKE2_CONTENTS_CURRENT_0) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current0button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current0button ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_CURRENT_90) + set_inconsistent(content_current90button); + else if(contents & QUAKE2_CONTENTS_CURRENT_90) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current90button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current90button ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_CURRENT_180) + set_inconsistent(content_current180button); + else if(contents & QUAKE2_CONTENTS_CURRENT_180) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current180button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current180button ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_CURRENT_270) + set_inconsistent(content_current270button); + else if(contents & QUAKE2_CONTENTS_CURRENT_270) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current270button ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_current270button ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_CURRENT_UP) + set_inconsistent(content_currentUPbutton); + else if(contents & QUAKE2_CONTENTS_CURRENT_UP) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentUPbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentUPbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_CURRENT_DOWN) + set_inconsistent(content_currentDOWNbutton); + else if(contents & QUAKE2_CONTENTS_CURRENT_DOWN) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentDOWNbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_currentDOWNbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_ORIGIN) + set_inconsistent(content_originbutton); + else if(contents & QUAKE2_CONTENTS_ORIGIN) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_originbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_originbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_DETAIL) + set_inconsistent(content_detailbutton); + else if(contents & QUAKE2_CONTENTS_DETAIL) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_detailbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_detailbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_TRANSLUCENT) + set_inconsistent(content_translucentbutton); + else if(contents & QUAKE2_CONTENTS_TRANSLUCENT) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_translucentbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_translucentbutton ), FALSE); + + if(diff_contents & QUAKE2_CONTENTS_LADDER) + set_inconsistent(content_ladderbutton); + else if(contents & QUAKE2_CONTENTS_LADDER) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_ladderbutton ), TRUE); + else + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON ( content_ladderbutton ), FALSE); + + // Set Value + if(diff_value) + gtk_entry_set_text( (GtkEntry *)value_entry, ""); + else + { + working_value = value; + sprintf( tex_buff, "%d", value); + gtk_entry_set_text( (GtkEntry *)value_entry, tex_buff); + } + + setup_buttons = FALSE; +} + +void SetChangeInFlags_Face_Quake2 (texdef_to_face_t *texdef_face_list) +{ + texdef_to_face_t *temp_texdef_face_list; + texdef_t *tmp_texdef; + + for (temp_texdef_face_list = texdef_face_list; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + tmp_texdef = &temp_texdef_face_list->texdef; + tmp_texdef->flags = (tmp_texdef->flags & ~surface_mask) | working_surface_flags; + tmp_texdef->contents = (tmp_texdef->contents & ~content_mask) | working_content_flags; + tmp_texdef->value = working_value; + Sys_Printf("content_flag: %d content_mask: %d\n",working_content_flags,content_mask); + Sys_Printf("content: %d\n",tmp_texdef->contents); + } +} + +inline void change_surfaceflag (GtkWidget *togglebutton, int sur_flag, gboolean change_flag_to) +{ + + if (!setup_buttons) // If we're setting up the buttons, we really don't need to + { // set flags that are already set + + if (gtk_toggle_button_get_inconsistent(GTK_TOGGLE_BUTTON (togglebutton))) // Clear out inconsistent, if set + clear_inconsistent(GTK_WIDGET (togglebutton)); + + surface_mask |= sur_flag; + + if (change_flag_to) + working_surface_flags |= sur_flag; + else + working_surface_flags &= ~sur_flag; + } +} + +inline void change_contentflag (GtkWidget *togglebutton, int content_flag, gboolean change_flag_to) +{ + + if ( (!setup_buttons) ) // If we're setting up the buttons, we really don't need to + { // set flags that are already set + + if (gtk_toggle_button_get_inconsistent(GTK_TOGGLE_BUTTON (togglebutton))) + clear_inconsistent(togglebutton); + //if (g_ptrSelectedFaces.GetSize() == 0) // Only changing content flags on whole brushes, not faces. + //{ + content_mask |= content_flag; + + if (change_flag_to) + working_content_flags |= content_flag; + else + working_content_flags &= ~content_flag; + //} + Sys_Printf("content_flag: %d content_mask: %d\n",content_flag,content_mask); + } +} + +// Surface Flags Callbacks +void +on_surface_lightbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_lightbutton, QUAKE2_SURF_LIGHT, (GTK_TOGGLE_BUTTON (surface_lightbutton)->active)); + +} + +void +on_surface_slickbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_slickbutton, QUAKE2_SURF_SLICK, (GTK_TOGGLE_BUTTON (surface_slickbutton)->active)); + +} + +void +on_surface_skybutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_skybutton, QUAKE2_SURF_SKY, (GTK_TOGGLE_BUTTON (surface_skybutton)->active)); +} + +void +on_surface_warpbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_warpbutton, QUAKE2_SURF_WARP, (GTK_TOGGLE_BUTTON (surface_warpbutton)->active)); +} + +void +on_surface_trans33button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_trans33button, QUAKE2_SURF_TRANS33, (GTK_TOGGLE_BUTTON (surface_trans33button)->active)); +} + +void +on_surface_trans66button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_trans66button, QUAKE2_SURF_TRANS66, (GTK_TOGGLE_BUTTON (surface_trans66button)->active)); +} + +void +on_surface_flowingbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_flowingbutton, QUAKE2_SURF_FLOWING, (GTK_TOGGLE_BUTTON (surface_flowingbutton)->active)); +} + +void +on_surface_nodrawbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_nodrawbutton, QUAKE2_SURF_NODRAW, (GTK_TOGGLE_BUTTON (surface_nodrawbutton)->active)); +} + +void +on_surface_hintbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_hintbutton, QUAKE2_SURF_HINT, (GTK_TOGGLE_BUTTON (surface_hintbutton)->active)); +} + +void +on_surface_skipbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_surfaceflag(surface_skipbutton, QUAKE2_SURF_SKIP, (GTK_TOGGLE_BUTTON (surface_skipbutton)->active)); +} + +// Content Flags Callbacks +void +on_content_solidbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_solidbutton, QUAKE2_CONTENTS_SOLID, (GTK_TOGGLE_BUTTON (content_solidbutton)->active)); +} + +void +on_content_windowbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_windowbutton, QUAKE2_CONTENTS_WINDOW, (GTK_TOGGLE_BUTTON (content_windowbutton)->active)); +} + +void +on_content_auxbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_auxbutton, QUAKE2_CONTENTS_AUX, (GTK_TOGGLE_BUTTON (content_auxbutton)->active)); +} + +void +on_content_lavabutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_lavabutton, QUAKE2_CONTENTS_LAVA, (GTK_TOGGLE_BUTTON (content_lavabutton)->active)); +} + +void +on_content_slimebutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_slimebutton, QUAKE2_CONTENTS_SLIME, (GTK_TOGGLE_BUTTON (content_slimebutton)->active)); +} + +void +on_content_waterbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_waterbutton, QUAKE2_CONTENTS_WATER, (GTK_TOGGLE_BUTTON (content_waterbutton)->active)); +} + +void +on_content_mistbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_mistbutton, QUAKE2_CONTENTS_MIST, (GTK_TOGGLE_BUTTON (content_mistbutton)->active)); +} + +void +on_content_areaportalbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_areaportalbutton, QUAKE2_CONTENTS_AREAPORTAL, (GTK_TOGGLE_BUTTON (content_areaportalbutton)->active)); +} + +void +on_content_playerclipbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_playerclipbutton, QUAKE2_CONTENTS_PLAYERCLIP, (GTK_TOGGLE_BUTTON (content_playerclipbutton)->active)); +} + +void +on_content_monsterclipbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_monsterclipbutton, QUAKE2_CONTENTS_MONSTERCLIP, (GTK_TOGGLE_BUTTON (content_monsterclipbutton)->active)); +} + +void +on_content_current0button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_current0button, QUAKE2_CONTENTS_CURRENT_0, (GTK_TOGGLE_BUTTON (content_current0button)->active)); +} + +void +on_content_current90button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_current90button, QUAKE2_CONTENTS_CURRENT_90, (GTK_TOGGLE_BUTTON (content_current90button)->active)); +} + +void +on_content_current180button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_current180button, QUAKE2_CONTENTS_CURRENT_180, (GTK_TOGGLE_BUTTON (content_current180button)->active)); +} + +void +on_content_current270button_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_current270button, QUAKE2_CONTENTS_CURRENT_270, (GTK_TOGGLE_BUTTON (content_current270button)->active)); +} + +void +on_content_currentUPbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_currentUPbutton, QUAKE2_CONTENTS_CURRENT_UP, (GTK_TOGGLE_BUTTON (content_currentUPbutton)->active)); +} + +void +on_content_currentDOWNbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_currentDOWNbutton, QUAKE2_CONTENTS_CURRENT_DOWN, (GTK_TOGGLE_BUTTON (content_currentDOWNbutton)->active)); +} + +void +on_content_originbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_originbutton, QUAKE2_CONTENTS_ORIGIN, (GTK_TOGGLE_BUTTON (content_originbutton)->active)); +} + +void +on_content_detailbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_detailbutton, QUAKE2_CONTENTS_DETAIL, (GTK_TOGGLE_BUTTON (content_detailbutton)->active)); +} + +void +on_content_translucentbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_translucentbutton, QUAKE2_CONTENTS_TRANSLUCENT, (GTK_TOGGLE_BUTTON (content_translucentbutton)->active)); +} + +void +on_content_ladderbutton_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + change_contentflag(content_ladderbutton, QUAKE2_CONTENTS_LADDER, (GTK_TOGGLE_BUTTON (content_ladderbutton)->active)); +} + +// Value Entry Callback +void +on_value_entry_changed (GtkEditable *editable, + gpointer user_data) +{ + if ( (!setup_buttons) ) // If we're setting up the buttons, don't change value + working_value = atoi( gtk_entry_get_text( (GtkEntry*)editable) ); +} + +void +on_value_entry_insert_text (GtkEditable *editable, + gchar *new_text, + gint new_text_length, + gint *position, + gpointer user_data) +{ + int i, count=0; + gchar *result; + int entry_value; + texdef_t *pt; + brush_t *b; + face_t *f; + + // Limit input to digits, throwing out anything else + // Modified from Gtk FAQ for text filtering of GtkEntry + result = g_new (gchar, new_text_length); + + for (i=0; i < new_text_length; i++) { + if (!isdigit(new_text[i])) + continue; + result[count++] = new_text[i]; + } + + if (count > 0) { + gtk_signal_handler_block_by_func (GTK_OBJECT (editable), + GTK_SIGNAL_FUNC (on_value_entry_insert_text), + user_data); + gtk_editable_insert_text (editable, result, count, position); + gtk_signal_handler_unblock_by_func (GTK_OBJECT (editable), + GTK_SIGNAL_FUNC (on_value_entry_insert_text), + user_data); + } + gtk_signal_emit_stop_by_name (GTK_OBJECT (editable), "insert_text"); + + g_free (result); +} + +void +on_surfacebutton_clicked (GtkButton *button, + gpointer user_data) +{ + gtk_notebook_set_page (GTK_NOTEBOOK(notebook1), 0); +} + +void +on_contentbutton_clicked (GtkButton *button, + gpointer user_data) +{ + gtk_notebook_set_page (GTK_NOTEBOOK(notebook1), 1); +} + + +#define QUAKE2_FLAG_BUTTON_BORDER 3 + +GtkWidget* Create_Quake2FlagsDialog (GtkWidget* surfacedialog_widget) +{ + GtkWidget *frame1; + GtkWidget *vbox1; + GtkWidget *vbox2; + GtkWidget *vbox3; + GtkWidget *vbox4; + GtkWidget *table4; + GtkWidget *hbox2; + GtkWidget *hbox3; + GtkWidget *hseparator1; + GtkWidget *value_label; + GtkWidget *label5; + GtkWidget *table3; + GtkWidget *label6; + GtkWidget *table1; + + + frame1 = gtk_frame_new ("Flags"); + gtk_widget_show (frame1); + gtk_container_add (GTK_CONTAINER (surfacedialog_widget), frame1); + + vbox1 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox1); + gtk_container_add (GTK_CONTAINER (frame1), vbox1); + + notebook1 = gtk_notebook_new (); + gtk_widget_show (notebook1); + gtk_box_pack_start (GTK_BOX (vbox1), notebook1, TRUE, TRUE, 0); + gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook1), TRUE); + gtk_container_set_border_width (GTK_CONTAINER (notebook1), 5); + + vbox2 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (notebook1), vbox2); + + table4 = gtk_table_new (3, 4, FALSE); + gtk_widget_show (table4); + gtk_box_pack_start (GTK_BOX (vbox2), table4, TRUE, TRUE, 0); + + surface_lightbutton = gtk_toggle_button_new_with_label ("Light"); + gtk_signal_connect (GTK_OBJECT (surface_lightbutton), "toggled", + GTK_SIGNAL_FUNC (on_surface_lightbutton_toggled), + NULL); + gtk_widget_show (surface_lightbutton); + gtk_table_attach (GTK_TABLE (table4), surface_lightbutton, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (surface_lightbutton), QUAKE2_FLAG_BUTTON_BORDER); + + surface_slickbutton = gtk_toggle_button_new_with_label ("Slick"); + gtk_signal_connect (GTK_OBJECT (surface_slickbutton), "toggled", + GTK_SIGNAL_FUNC (on_surface_slickbutton_toggled), + NULL); + gtk_widget_show (surface_slickbutton); + gtk_table_attach (GTK_TABLE (table4), surface_slickbutton, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (surface_slickbutton), QUAKE2_FLAG_BUTTON_BORDER); + + surface_skybutton = gtk_toggle_button_new_with_label ("Sky"); + gtk_signal_connect (GTK_OBJECT (surface_skybutton), "toggled", + GTK_SIGNAL_FUNC (on_surface_skybutton_toggled), + NULL); + gtk_widget_show (surface_skybutton); + gtk_table_attach (GTK_TABLE (table4), surface_skybutton, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (surface_skybutton), QUAKE2_FLAG_BUTTON_BORDER); + + surface_warpbutton = gtk_toggle_button_new_with_label ("Warp"); + gtk_signal_connect (GTK_OBJECT (surface_warpbutton), "toggled", + GTK_SIGNAL_FUNC (on_surface_warpbutton_toggled), + NULL); + gtk_widget_show (surface_warpbutton); + gtk_table_attach (GTK_TABLE (table4), surface_warpbutton, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (surface_warpbutton), QUAKE2_FLAG_BUTTON_BORDER); + + surface_trans33button = gtk_toggle_button_new_with_label ("Trans 33"); + gtk_signal_connect (GTK_OBJECT (surface_trans33button), "toggled", + GTK_SIGNAL_FUNC (on_surface_trans33button_toggled), + NULL); + gtk_widget_show (surface_trans33button); + gtk_table_attach (GTK_TABLE (table4), surface_trans33button, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (surface_trans33button), QUAKE2_FLAG_BUTTON_BORDER); + + surface_trans66button = gtk_toggle_button_new_with_label ("Trans 66"); + gtk_signal_connect (GTK_OBJECT (surface_trans66button), "toggled", + GTK_SIGNAL_FUNC (on_surface_trans66button_toggled), + NULL); + gtk_widget_show (surface_trans66button); + gtk_table_attach (GTK_TABLE (table4), surface_trans66button, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (surface_trans66button), QUAKE2_FLAG_BUTTON_BORDER); + + surface_flowingbutton = gtk_toggle_button_new_with_label ("Flowing"); + gtk_signal_connect (GTK_OBJECT (surface_flowingbutton), "toggled", + GTK_SIGNAL_FUNC (on_surface_flowingbutton_toggled), + NULL); + gtk_widget_show (surface_flowingbutton); + gtk_table_attach (GTK_TABLE (table4), surface_flowingbutton, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (surface_flowingbutton), QUAKE2_FLAG_BUTTON_BORDER); + + surface_nodrawbutton = gtk_toggle_button_new_with_label ("NoDraw"); + gtk_signal_connect (GTK_OBJECT (surface_nodrawbutton), "toggled", + GTK_SIGNAL_FUNC (on_surface_nodrawbutton_toggled), + NULL); + gtk_widget_show (surface_nodrawbutton); + gtk_table_attach (GTK_TABLE (table4), surface_nodrawbutton, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (surface_nodrawbutton), QUAKE2_FLAG_BUTTON_BORDER); + + surface_hintbutton = gtk_toggle_button_new_with_label ("Hint"); + gtk_signal_connect (GTK_OBJECT (surface_hintbutton), "toggled", + GTK_SIGNAL_FUNC (on_surface_hintbutton_toggled), + NULL); + gtk_widget_show (surface_hintbutton); + gtk_table_attach (GTK_TABLE (table4), surface_hintbutton, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (surface_hintbutton), QUAKE2_FLAG_BUTTON_BORDER); + + surface_skipbutton = gtk_toggle_button_new_with_label ("Skip"); + gtk_signal_connect (GTK_OBJECT (surface_skipbutton), "toggled", + GTK_SIGNAL_FUNC (on_surface_skipbutton_toggled), + NULL); + gtk_widget_show (surface_skipbutton); + gtk_table_attach (GTK_TABLE (table4), surface_skipbutton, 3, 4, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (surface_skipbutton), QUAKE2_FLAG_BUTTON_BORDER); + + hseparator1 = gtk_hseparator_new (); + gtk_widget_show (hseparator1); + gtk_box_pack_start (GTK_BOX (vbox2), hseparator1, FALSE, FALSE, 0); + gtk_widget_set_usize (hseparator1, -2, 5); + + hbox2 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox2), hbox2, FALSE, FALSE, 0); + + hbox3 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox3); + gtk_box_pack_start (GTK_BOX (hbox2), hbox3, TRUE, TRUE, 0); + + vbox4 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox4); + gtk_box_pack_start (GTK_BOX (hbox3), vbox4, TRUE, TRUE, 0); + + value_label = gtk_label_new (" Value: "); + gtk_widget_show (value_label); + gtk_box_pack_start (GTK_BOX (hbox3), value_label, FALSE, FALSE, 0); + + value_entry = gtk_entry_new (); + gtk_signal_connect (GTK_OBJECT (value_entry), "changed", + GTK_SIGNAL_FUNC (on_value_entry_changed), + NULL); + gtk_signal_connect (GTK_OBJECT (value_entry), "insert_text", + GTK_SIGNAL_FUNC (on_value_entry_insert_text), + NULL); + gtk_entry_set_max_length( (GtkEntry *)value_entry, 11); + gtk_widget_show (value_entry); + gtk_box_pack_start (GTK_BOX (hbox3), value_entry, TRUE, TRUE, 0); + + vbox3 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox3); + gtk_box_pack_start (GTK_BOX (hbox3), vbox3, TRUE, TRUE, 0); + + label5 = gtk_label_new ("Surface Flags"); + gtk_widget_show (label5); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 0), label5); + + table3 = gtk_table_new (5, 4, FALSE); + gtk_widget_show (table3); + gtk_container_add (GTK_CONTAINER (notebook1), table3); + + content_solidbutton = gtk_toggle_button_new_with_label ("Solid"); + gtk_signal_connect (GTK_OBJECT (content_solidbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_solidbutton_toggled), + NULL); + gtk_widget_show (content_solidbutton); + gtk_table_attach (GTK_TABLE (table3), content_solidbutton, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_solidbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_windowbutton = gtk_toggle_button_new_with_label ("Window"); + gtk_signal_connect (GTK_OBJECT (content_windowbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_windowbutton_toggled), + NULL); + gtk_widget_show (content_windowbutton); + gtk_table_attach (GTK_TABLE (table3), content_windowbutton, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_windowbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_auxbutton = gtk_toggle_button_new_with_label ("Aux"); + gtk_signal_connect (GTK_OBJECT (content_auxbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_auxbutton_toggled), + NULL); + gtk_widget_show (content_auxbutton); + gtk_table_attach (GTK_TABLE (table3), content_auxbutton, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_auxbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_lavabutton = gtk_toggle_button_new_with_label ("Lava"); + gtk_signal_connect (GTK_OBJECT (content_lavabutton), "toggled", + GTK_SIGNAL_FUNC (on_content_lavabutton_toggled), + NULL); + gtk_widget_show (content_lavabutton); + gtk_table_attach (GTK_TABLE (table3), content_lavabutton, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_lavabutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_slimebutton = gtk_toggle_button_new_with_label ("Slime"); + gtk_signal_connect (GTK_OBJECT (content_slimebutton), "toggled", + GTK_SIGNAL_FUNC (on_content_slimebutton_toggled), + NULL); + gtk_widget_show (content_slimebutton); + gtk_table_attach (GTK_TABLE (table3), content_slimebutton, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_slimebutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_waterbutton = gtk_toggle_button_new_with_label ("Water"); + gtk_signal_connect (GTK_OBJECT (content_waterbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_waterbutton_toggled), + NULL); + gtk_widget_show (content_waterbutton); + gtk_table_attach (GTK_TABLE (table3), content_waterbutton, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_waterbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_mistbutton = gtk_toggle_button_new_with_label ("Mist"); + gtk_signal_connect (GTK_OBJECT (content_mistbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_mistbutton_toggled), + NULL); + gtk_widget_show (content_mistbutton); + gtk_table_attach (GTK_TABLE (table3), content_mistbutton, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_mistbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_areaportalbutton = gtk_toggle_button_new_with_label ("AreaPortal"); + gtk_signal_connect (GTK_OBJECT (content_areaportalbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_areaportalbutton_toggled), + NULL); + gtk_widget_show (content_areaportalbutton); + gtk_table_attach (GTK_TABLE (table3), content_areaportalbutton, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_areaportalbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_playerclipbutton = gtk_toggle_button_new_with_label ("PlayerClip"); + gtk_signal_connect (GTK_OBJECT (content_playerclipbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_playerclipbutton_toggled), + NULL); + gtk_widget_show (content_playerclipbutton); + gtk_table_attach (GTK_TABLE (table3), content_playerclipbutton, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_playerclipbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_monsterclipbutton = gtk_toggle_button_new_with_label ("MonsterClip"); + gtk_signal_connect (GTK_OBJECT (content_monsterclipbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_monsterclipbutton_toggled), + NULL); + gtk_widget_show (content_monsterclipbutton); + gtk_table_attach (GTK_TABLE (table3), content_monsterclipbutton, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_monsterclipbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_current0button = gtk_toggle_button_new_with_label ("Current 0"); + gtk_signal_connect (GTK_OBJECT (content_current0button), "toggled", + GTK_SIGNAL_FUNC (on_content_current0button_toggled), + NULL); + gtk_widget_show (content_current0button); + gtk_table_attach (GTK_TABLE (table3), content_current0button, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_current0button), QUAKE2_FLAG_BUTTON_BORDER); + + content_current90button = gtk_toggle_button_new_with_label ("Current 90"); + gtk_signal_connect (GTK_OBJECT (content_current90button), "toggled", + GTK_SIGNAL_FUNC (on_content_current90button_toggled), + NULL); + gtk_widget_show (content_current90button); + gtk_table_attach (GTK_TABLE (table3), content_current90button, 3, 4, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_current90button), QUAKE2_FLAG_BUTTON_BORDER); + + content_current180button = gtk_toggle_button_new_with_label ("Current 180"); + gtk_signal_connect (GTK_OBJECT (content_current180button), "toggled", + GTK_SIGNAL_FUNC (on_content_current180button_toggled), + NULL); + gtk_widget_show (content_current180button); + gtk_table_attach (GTK_TABLE (table3), content_current180button, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_current180button), QUAKE2_FLAG_BUTTON_BORDER); + + content_current270button = gtk_toggle_button_new_with_label ("Current 270"); + gtk_signal_connect (GTK_OBJECT (content_current270button), "toggled", + GTK_SIGNAL_FUNC (on_content_current270button_toggled), + NULL); + gtk_widget_show (content_current270button); + gtk_table_attach (GTK_TABLE (table3), content_current270button, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_current270button), QUAKE2_FLAG_BUTTON_BORDER); + + content_currentUPbutton = gtk_toggle_button_new_with_label ("Current UP"); + gtk_signal_connect (GTK_OBJECT (content_currentUPbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_currentUPbutton_toggled), + NULL); + gtk_widget_show (content_currentUPbutton); + gtk_table_attach (GTK_TABLE (table3), content_currentUPbutton, 2, 3, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_currentUPbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_currentDOWNbutton = gtk_toggle_button_new_with_label ("Current DOWN"); + gtk_signal_connect (GTK_OBJECT (content_currentDOWNbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_currentDOWNbutton_toggled), + NULL); + gtk_widget_show (content_currentDOWNbutton); + gtk_table_attach (GTK_TABLE (table3), content_currentDOWNbutton, 3, 4, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_currentDOWNbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_originbutton = gtk_toggle_button_new_with_label ("Origin"); + gtk_signal_connect (GTK_OBJECT (content_originbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_originbutton_toggled), + NULL); + gtk_widget_show (content_originbutton); + gtk_table_attach (GTK_TABLE (table3), content_originbutton, 0, 1, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_originbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_detailbutton = gtk_toggle_button_new_with_label ("Detail"); + gtk_signal_connect (GTK_OBJECT (content_detailbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_detailbutton_toggled), + NULL); + gtk_widget_show (content_detailbutton); + gtk_table_attach (GTK_TABLE (table3), content_detailbutton, 1, 2, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_detailbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_translucentbutton = gtk_toggle_button_new_with_label ("Translucent"); + gtk_signal_connect (GTK_OBJECT (content_translucentbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_translucentbutton_toggled), + NULL); + gtk_widget_show (content_translucentbutton); + gtk_table_attach (GTK_TABLE (table3), content_translucentbutton, 2, 3, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_translucentbutton), QUAKE2_FLAG_BUTTON_BORDER); + + content_ladderbutton = gtk_toggle_button_new_with_label ("Ladder"); + gtk_signal_connect (GTK_OBJECT (content_ladderbutton), "toggled", + GTK_SIGNAL_FUNC (on_content_ladderbutton_toggled), + NULL); + gtk_widget_show (content_ladderbutton); + gtk_table_attach (GTK_TABLE (table3), content_ladderbutton, 3, 4, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + gtk_container_set_border_width (GTK_CONTAINER (content_ladderbutton), QUAKE2_FLAG_BUTTON_BORDER); + + label6 = gtk_label_new ("Content Flags"); + gtk_widget_show (label6); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 1), label6); + + return frame1; +} + diff --git a/plugins/surface_quake2/surfdlg_plugin.cpp b/plugins/surface_quake2/surfdlg_plugin.cpp index b10eddab..58c95f16 100644 --- a/plugins/surface_quake2/surfdlg_plugin.cpp +++ b/plugins/surface_quake2/surfdlg_plugin.cpp @@ -1,127 +1,127 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include -#include "surfdlg_plugin.h" -#include "surfacedialog.h" - -#include "synapse.h" - -class CSynapseClient_SurfDLG : public CSynapseClient -{ -public: - // CSynapseClient API - bool RequestAPI(APIDescriptor_t *pAPI); - const char* GetInfo(); - const char* GetName(); - bool OnActivate(); - - CSynapseClient_SurfDLG() { } - virtual ~CSynapseClient_SurfDLG() { } -}; - -// ============================================================================= -// SYNAPSE - -_QERFuncTable_1 g_FuncTable; -_QERUndoTable g_UndoTable; -_QERAppSurfaceTable g_AppSurfaceTable; -_QERSelectedFaceTable g_SelectedFaceTable; -_QERShadersTable g_ShadersTable; -_QERAppShadersTable g_AppShadersTable; -_QERAppDataTable g_AppDataTable; - -CSynapseServer* g_pSynapseServer = NULL; -CSynapseClient_SurfDLG 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(SURFACEDIALOG_MAJOR, "quake2", sizeof(_QERPlugSurfaceTable)); - g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); - g_SynapseClient.AddAPI(UNDO_MAJOR, NULL, sizeof(_QERUndoTable), SYN_REQUIRE, &g_UndoTable); - g_SynapseClient.AddAPI(APPSURFACEDIALOG_MAJOR, NULL, sizeof(_QERAppSurfaceTable), SYN_REQUIRE, &g_AppSurfaceTable); - g_SynapseClient.AddAPI(SELECTEDFACE_MAJOR, NULL, sizeof(_QERSelectedFaceTable), SYN_REQUIRE, &g_SelectedFaceTable); - g_SynapseClient.AddAPI(SHADERS_MAJOR, "quake2", sizeof(_QERShadersTable), SYN_REQUIRE, &g_ShadersTable); - g_SynapseClient.AddAPI(APPSHADERS_MAJOR, NULL, sizeof(_QERAppShadersTable), SYN_REQUIRE, &g_AppShadersTable); - g_SynapseClient.AddAPI(DATA_MAJOR, NULL, sizeof(_QERAppDataTable), SYN_REQUIRE, &g_AppDataTable); - - return &g_SynapseClient; -} - -bool CSynapseClient_SurfDLG::RequestAPI(APIDescriptor_t *pAPI) -{ - if (!strcmp(pAPI->major_name, SURFACEDIALOG_MAJOR)) - { - _QERPlugSurfaceTable* pSurfDialogTable= static_cast<_QERPlugSurfaceTable*>(pAPI->mpTable); - if (!strcmp(pAPI->minor_name, "quake2")) - { - pSurfDialogTable->m_pfnToggleSurface = &ToggleSurface; - pSurfDialogTable->m_pfnDoSurface = &DoSurface; - pSurfDialogTable->m_pfnUpdateSurfaceDialog = &UpdateSurfaceDialog; - pSurfDialogTable->m_pfnSurfaceDlgFitAll = &SurfaceDlgFitAll; - pSurfDialogTable->m_pfnGet_SI_Module_Widget = &Get_SI_Module_Widget; - return true; - } - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -#include "version.h" - -const char* CSynapseClient_SurfDLG::GetInfo() -{ - return "Surface Dialog (Quake 2) module built " __DATE__ " " RADIANT_VERSION; -} - -const char* CSynapseClient_SurfDLG::GetName() -{ - return "surface"; -} - -bool CSynapseClient_SurfDLG::OnActivate() -{ - return true; -} +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include "surfdlg_plugin.h" +#include "surfacedialog.h" + +#include "synapse.h" + +class CSynapseClient_SurfDLG : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + const char* GetName(); + bool OnActivate(); + + CSynapseClient_SurfDLG() { } + virtual ~CSynapseClient_SurfDLG() { } +}; + +// ============================================================================= +// SYNAPSE + +_QERFuncTable_1 g_FuncTable; +_QERUndoTable g_UndoTable; +_QERAppSurfaceTable g_AppSurfaceTable; +_QERSelectedFaceTable g_SelectedFaceTable; +_QERShadersTable g_ShadersTable; +_QERAppShadersTable g_AppShadersTable; +_QERAppDataTable g_AppDataTable; + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClient_SurfDLG 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(SURFACEDIALOG_MAJOR, "quake2", sizeof(_QERPlugSurfaceTable)); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(UNDO_MAJOR, NULL, sizeof(_QERUndoTable), SYN_REQUIRE, &g_UndoTable); + g_SynapseClient.AddAPI(APPSURFACEDIALOG_MAJOR, NULL, sizeof(_QERAppSurfaceTable), SYN_REQUIRE, &g_AppSurfaceTable); + g_SynapseClient.AddAPI(SELECTEDFACE_MAJOR, NULL, sizeof(_QERSelectedFaceTable), SYN_REQUIRE, &g_SelectedFaceTable); + g_SynapseClient.AddAPI(SHADERS_MAJOR, "quake2", sizeof(_QERShadersTable), SYN_REQUIRE, &g_ShadersTable); + g_SynapseClient.AddAPI(APPSHADERS_MAJOR, NULL, sizeof(_QERAppShadersTable), SYN_REQUIRE, &g_AppShadersTable); + g_SynapseClient.AddAPI(DATA_MAJOR, NULL, sizeof(_QERAppDataTable), SYN_REQUIRE, &g_AppDataTable); + + return &g_SynapseClient; +} + +bool CSynapseClient_SurfDLG::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, SURFACEDIALOG_MAJOR)) + { + _QERPlugSurfaceTable* pSurfDialogTable= static_cast<_QERPlugSurfaceTable*>(pAPI->mpTable); + if (!strcmp(pAPI->minor_name, "quake2")) + { + pSurfDialogTable->m_pfnToggleSurface = &ToggleSurface; + pSurfDialogTable->m_pfnDoSurface = &DoSurface; + pSurfDialogTable->m_pfnUpdateSurfaceDialog = &UpdateSurfaceDialog; + pSurfDialogTable->m_pfnSurfaceDlgFitAll = &SurfaceDlgFitAll; + pSurfDialogTable->m_pfnGet_SI_Module_Widget = &Get_SI_Module_Widget; + return true; + } + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClient_SurfDLG::GetInfo() +{ + return "Surface Dialog (Quake 2) module built " __DATE__ " " RADIANT_VERSION; +} + +const char* CSynapseClient_SurfDLG::GetName() +{ + return "surface"; +} + +bool CSynapseClient_SurfDLG::OnActivate() +{ + return true; +} diff --git a/plugins/textool/2DView.cpp b/plugins/textool/2DView.cpp index aab484e1..3bad3fbb 100644 --- a/plugins/textool/2DView.cpp +++ b/plugins/textool/2DView.cpp @@ -1,202 +1,202 @@ -/* -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 -*/ - -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// a class to provide basic services for 2D view of a world -// window <-> local 2D space transforms -// snap to grid -// TODO: this one can be placed under an interface, and provided to the editor as a service - -#include "StdAfx.h" - -static void view_ZoomIn (GtkWidget* widget, gpointer data) -{ - ((C2DView*)data)->ZoomIn (); -} - -static void view_ZoomOut (GtkWidget* widget, gpointer data) -{ - ((C2DView*)data)->ZoomOut (); -} - -void C2DView::PreparePaint() -{ - g_QglTable.m_pfn_qglClearColor( 0, 0, 0, 0 ); - g_QglTable.m_pfn_qglViewport( 0, 0, m_rect.right, m_rect.bottom ); - g_QglTable.m_pfn_qglMatrixMode( GL_PROJECTION ); - g_QglTable.m_pfn_qglLoadIdentity(); - g_QglTable.m_pfn_qglOrtho( m_Mins[0], m_Maxs[0], m_Maxs[1], m_Mins[1], -1, 1 ); -} - -void C2DView::SpaceForWindow( float c[2], int x, int y) -{ - c[0] = ((float)(x))/((float)(m_rect.right-m_rect.left))*(m_Maxs[0]-m_Mins[0])+m_Mins[0]; - c[1] = ((float)(y))/((float)(m_rect.bottom-m_rect.top))*(m_Maxs[1]-m_Mins[1])+m_Mins[1]; -} - -void C2DView::GridForWindow( float c[2], int x, int y) -{ - SpaceForWindow( c, x, y ); - if ( !m_bDoGrid ) - return; - c[0] /= m_GridStep[0]; - c[1] /= m_GridStep[1]; - c[0] = (float)floor( c[0] + 0.5f ); - c[1] = (float)floor( c[1] + 0.5f ); - c[0] *= m_GridStep[0]; - c[1] *= m_GridStep[1]; -} - -void C2DView::WindowForSpace( int &x, int &y, const float c[2] ) -{ - x = m_rect.left + (int)( ((float)(m_rect.right-m_rect.left))*(c[0]-m_Mins[0])/(m_Maxs[0]-m_Mins[0]) ); - y = m_rect.top + (int)( ((float)(m_rect.bottom-m_rect.top))*(c[1]-m_Mins[1])/(m_Maxs[1]-m_Mins[1]) ); -} - -qboolean C2DView::DoesSelect( int x, int y, float c[2] ) -{ - int xc,yc; - WindowForSpace( xc, yc, c ); - if ( abs(xc-x)<=3 && abs(yc-y)<=3 ) - return true; - return false; -} - -void C2DView::ZoomIn() -{ - m_Mins[0] = 0.5f * ( m_Mins[0] - m_Center[0] ) + m_Center[0]; - m_Mins[1] = 0.5f * ( m_Mins[1] - m_Center[1] ) + m_Center[1]; - m_Maxs[0] = 0.5f * ( m_Maxs[0] - m_Center[0] ) + m_Center[0]; - m_Maxs[1] = 0.5f * ( m_Maxs[1] - m_Center[1] ) + m_Center[1]; - g_pToolWnd->Redraw (); -} - -void C2DView::ZoomOut() -{ - m_Mins[0] = 2.0f * ( m_Mins[0] - m_Center[0] ) + m_Center[0]; - m_Mins[1] = 2.0f * ( m_Mins[1] - m_Center[1] ) + m_Center[1]; - m_Maxs[0] = 2.0f * ( m_Maxs[0] - m_Center[0] ) + m_Center[0]; - m_Maxs[1] = 2.0f * ( m_Maxs[1] - m_Center[1] ) + m_Center[1]; - g_pToolWnd->Redraw (); -} - -bool C2DView::OnRButtonDown (int x, int y) -{ - if (ViewState == View_Idle) - { - m_xPosMove = x; // horizontal position of cursor - m_yPosMove = y; // vertical position of cursor - // store - m_MinsMove[0] = m_Mins[0]; m_MinsMove[1] = m_Mins[1]; - m_MaxsMove[0] = m_Maxs[0]; m_MaxsMove[1] = m_Maxs[1]; - ViewState = View_Move; - // set popup to true - m_bPopup = true; - return true; - } - return false; -} - -bool C2DView::OnRButtonUp (int x, int y) -{ - if (ViewState == View_Move) - { - // maybe it's time for popup menu - if (m_bPopup) - { - GtkWidget *menu, *item; - - menu = gtk_menu_new (); - - item = gtk_menu_item_new_with_label ("Validate (RETURN)"); - gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (Textool_Validate), NULL); - gtk_widget_show (item); - gtk_menu_append (GTK_MENU (menu), item); - - item = gtk_menu_item_new_with_label ("Zoom in (INSERT)"); - gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (view_ZoomIn), this); - gtk_widget_show (item); - gtk_menu_append (GTK_MENU (menu), item); - - item = gtk_menu_item_new_with_label ("Zoom out (DELETE)"); - gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (view_ZoomOut), this); - gtk_widget_show (item); - gtk_menu_append (GTK_MENU (menu), item); - - item = gtk_menu_item_new_with_label ("Cancel (ESC)"); - gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (Textool_Cancel), NULL); - gtk_widget_show (item); - gtk_menu_append (GTK_MENU (menu), item); - - gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME); - } - - // back to Idle mode - ViewState = View_Idle; - return true; - } - return false; -} - -bool C2DView::OnMouseMove (int xPos, int yPos) -{ - if (ViewState == View_Move) - { - float V[2]; - // V is the offset - V[0] = ((float)( xPos - m_xPosMove )) * ( m_MaxsMove[0] - m_MinsMove[0] ) / ((float)( m_rect.left - m_rect.right )); - V[1] = ((float)( yPos - m_yPosMove )) * ( m_MaxsMove[1] - m_MinsMove[1] ) / ((float)( m_rect.top - m_rect.bottom )); - // update m_Mins m_Maxs and m_Center - m_Mins[0] = m_MinsMove[0] + V[0]; - m_Mins[1] = m_MinsMove[1] + V[1]; - m_Maxs[0] = m_MaxsMove[0] + V[0]; - m_Maxs[1] = m_MaxsMove[1] + V[1]; - m_Center[0] = 0.5f * ( m_Mins[0] + m_Maxs[0] ); - m_Center[1] = 0.5f * ( m_Mins[1] + m_Maxs[1] ); - // no popup menu if we moved - m_bPopup = false; - // send a repaint message - g_pToolWnd->Redraw (); - return true; - } - return false; -} - -bool C2DView::OnKeyDown (char *s) -{ - if (ViewState == View_Idle) - { - if (!strcmp(s,"Insert")) - { - ZoomOut(); - return true; - } - if (!strcmp(s,"Delete")) - { - ZoomIn(); - return true; - } - } - return false; -} - +/* +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 +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// a class to provide basic services for 2D view of a world +// window <-> local 2D space transforms +// snap to grid +// TODO: this one can be placed under an interface, and provided to the editor as a service + +#include "StdAfx.h" + +static void view_ZoomIn (GtkWidget* widget, gpointer data) +{ + ((C2DView*)data)->ZoomIn (); +} + +static void view_ZoomOut (GtkWidget* widget, gpointer data) +{ + ((C2DView*)data)->ZoomOut (); +} + +void C2DView::PreparePaint() +{ + g_QglTable.m_pfn_qglClearColor( 0, 0, 0, 0 ); + g_QglTable.m_pfn_qglViewport( 0, 0, m_rect.right, m_rect.bottom ); + g_QglTable.m_pfn_qglMatrixMode( GL_PROJECTION ); + g_QglTable.m_pfn_qglLoadIdentity(); + g_QglTable.m_pfn_qglOrtho( m_Mins[0], m_Maxs[0], m_Maxs[1], m_Mins[1], -1, 1 ); +} + +void C2DView::SpaceForWindow( float c[2], int x, int y) +{ + c[0] = ((float)(x))/((float)(m_rect.right-m_rect.left))*(m_Maxs[0]-m_Mins[0])+m_Mins[0]; + c[1] = ((float)(y))/((float)(m_rect.bottom-m_rect.top))*(m_Maxs[1]-m_Mins[1])+m_Mins[1]; +} + +void C2DView::GridForWindow( float c[2], int x, int y) +{ + SpaceForWindow( c, x, y ); + if ( !m_bDoGrid ) + return; + c[0] /= m_GridStep[0]; + c[1] /= m_GridStep[1]; + c[0] = (float)floor( c[0] + 0.5f ); + c[1] = (float)floor( c[1] + 0.5f ); + c[0] *= m_GridStep[0]; + c[1] *= m_GridStep[1]; +} + +void C2DView::WindowForSpace( int &x, int &y, const float c[2] ) +{ + x = m_rect.left + (int)( ((float)(m_rect.right-m_rect.left))*(c[0]-m_Mins[0])/(m_Maxs[0]-m_Mins[0]) ); + y = m_rect.top + (int)( ((float)(m_rect.bottom-m_rect.top))*(c[1]-m_Mins[1])/(m_Maxs[1]-m_Mins[1]) ); +} + +qboolean C2DView::DoesSelect( int x, int y, float c[2] ) +{ + int xc,yc; + WindowForSpace( xc, yc, c ); + if ( abs(xc-x)<=3 && abs(yc-y)<=3 ) + return true; + return false; +} + +void C2DView::ZoomIn() +{ + m_Mins[0] = 0.5f * ( m_Mins[0] - m_Center[0] ) + m_Center[0]; + m_Mins[1] = 0.5f * ( m_Mins[1] - m_Center[1] ) + m_Center[1]; + m_Maxs[0] = 0.5f * ( m_Maxs[0] - m_Center[0] ) + m_Center[0]; + m_Maxs[1] = 0.5f * ( m_Maxs[1] - m_Center[1] ) + m_Center[1]; + g_pToolWnd->Redraw (); +} + +void C2DView::ZoomOut() +{ + m_Mins[0] = 2.0f * ( m_Mins[0] - m_Center[0] ) + m_Center[0]; + m_Mins[1] = 2.0f * ( m_Mins[1] - m_Center[1] ) + m_Center[1]; + m_Maxs[0] = 2.0f * ( m_Maxs[0] - m_Center[0] ) + m_Center[0]; + m_Maxs[1] = 2.0f * ( m_Maxs[1] - m_Center[1] ) + m_Center[1]; + g_pToolWnd->Redraw (); +} + +bool C2DView::OnRButtonDown (int x, int y) +{ + if (ViewState == View_Idle) + { + m_xPosMove = x; // horizontal position of cursor + m_yPosMove = y; // vertical position of cursor + // store + m_MinsMove[0] = m_Mins[0]; m_MinsMove[1] = m_Mins[1]; + m_MaxsMove[0] = m_Maxs[0]; m_MaxsMove[1] = m_Maxs[1]; + ViewState = View_Move; + // set popup to true + m_bPopup = true; + return true; + } + return false; +} + +bool C2DView::OnRButtonUp (int x, int y) +{ + if (ViewState == View_Move) + { + // maybe it's time for popup menu + if (m_bPopup) + { + GtkWidget *menu, *item; + + menu = gtk_menu_new (); + + item = gtk_menu_item_new_with_label ("Validate (RETURN)"); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (Textool_Validate), NULL); + gtk_widget_show (item); + gtk_menu_append (GTK_MENU (menu), item); + + item = gtk_menu_item_new_with_label ("Zoom in (INSERT)"); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (view_ZoomIn), this); + gtk_widget_show (item); + gtk_menu_append (GTK_MENU (menu), item); + + item = gtk_menu_item_new_with_label ("Zoom out (DELETE)"); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (view_ZoomOut), this); + gtk_widget_show (item); + gtk_menu_append (GTK_MENU (menu), item); + + item = gtk_menu_item_new_with_label ("Cancel (ESC)"); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (Textool_Cancel), NULL); + gtk_widget_show (item); + gtk_menu_append (GTK_MENU (menu), item); + + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME); + } + + // back to Idle mode + ViewState = View_Idle; + return true; + } + return false; +} + +bool C2DView::OnMouseMove (int xPos, int yPos) +{ + if (ViewState == View_Move) + { + float V[2]; + // V is the offset + V[0] = ((float)( xPos - m_xPosMove )) * ( m_MaxsMove[0] - m_MinsMove[0] ) / ((float)( m_rect.left - m_rect.right )); + V[1] = ((float)( yPos - m_yPosMove )) * ( m_MaxsMove[1] - m_MinsMove[1] ) / ((float)( m_rect.top - m_rect.bottom )); + // update m_Mins m_Maxs and m_Center + m_Mins[0] = m_MinsMove[0] + V[0]; + m_Mins[1] = m_MinsMove[1] + V[1]; + m_Maxs[0] = m_MaxsMove[0] + V[0]; + m_Maxs[1] = m_MaxsMove[1] + V[1]; + m_Center[0] = 0.5f * ( m_Mins[0] + m_Maxs[0] ); + m_Center[1] = 0.5f * ( m_Mins[1] + m_Maxs[1] ); + // no popup menu if we moved + m_bPopup = false; + // send a repaint message + g_pToolWnd->Redraw (); + return true; + } + return false; +} + +bool C2DView::OnKeyDown (char *s) +{ + if (ViewState == View_Idle) + { + if (!strcmp(s,"Insert")) + { + ZoomOut(); + return true; + } + if (!strcmp(s,"Delete")) + { + ZoomIn(); + return true; + } + } + return false; +} + diff --git a/plugins/textool/ControlPointsManager.cpp b/plugins/textool/ControlPointsManager.cpp index e91a6940..814ddf9d 100644 --- a/plugins/textool/ControlPointsManager.cpp +++ b/plugins/textool/ControlPointsManager.cpp @@ -1,332 +1,332 @@ -/* -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 -*/ - -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// a class to handle control points in a 2D view -// TODO: this one can be placed under an interface, and provided to the editor as service -// - -#include "StdAfx.h" - -void CControlPointsManagerBFace::Init (int iPts, CtrlPts_t *Pts, C2DView *p2DView, int TexSize[2], - _QERFaceData* pFaceData, _QERQglTable *pQglTable) -{ - ManagerState = Idle; - m_NumPoints = iPts; - m_pPts = Pts; - // store the initial config - memcpy( &m_RefPts, Pts, sizeof( CtrlPts_t ) ); - // init TM - memset( m_TM, 0, sizeof( float[2][3] ) ); - m_TM[0][0] = 1.0f; m_TM[1][1] = 1.0f; - m_bGotAnchor = false; - m_TransOffset[0] = 0.0f; m_TransOffset[1] = 0.0f; - m_TexSize[0] = TexSize[0]; - m_TexSize[1] = TexSize[1]; - m_pFaceData = pFaceData; - - CControlPointsManager::Init( p2DView, pQglTable ); -} - -bool CControlPointsManagerBFace::OnLButtonDown (int xPos, int yPos) -{ - if (ManagerState == Idle) - { - int i; - - // scan the point list to see if we selected something - for ( i=0; iDoesSelect( xPos, yPos, m_pPts->data[i] ) ) - { - m_iDragPoint = i; - ManagerState = Drag; - if (m_bGotAnchor && i == m_iAnchorPoint) - { - // this means we selected the Anchor, so we'll translate - m_bGotAnchor = false; - } - // perhaps we won't use translation, but we can compute it anyway - ComputeTransOffset(i); - if (m_bGotAnchor) - { - // we have an Anchor and selected another point - m_Anchor[0] = m_pPts->data[m_iAnchorPoint][0]; - m_Anchor[1] = m_pPts->data[m_iAnchorPoint][1]; - } - } - // send a repaint message - g_pToolWnd->Redraw (); - return true; - } - return false; -} - -bool CControlPointsManagerBFace::OnMouseMove (int xPos, int yPos) -{ - if (ManagerState == Drag) - { - if (m_bGotAnchor) - { - // there's an anchor, we are rotating the shape - // we need to work in XY space for orthonormality - float Pt[2]; - vec3_t V1,V2; - vec3_t cross; - float c,s; - // used in XY space - float XYTM[2][3]; - float XYRefAnchor[2]; - float XYAnchor[2]; - m_p2DView->GridForWindow( Pt, xPos, yPos ); - V2[0] = Pt[0] - m_Anchor[0]; - V2[1] = Pt[1] - m_Anchor[1]; - V2[2] = 0.0f; - V1[0] = m_RefPts.data[m_iDragPoint][0] - m_RefPts.data[m_iAnchorPoint][0]; - V1[1] = m_RefPts.data[m_iDragPoint][1] - m_RefPts.data[m_iAnchorPoint][1]; - V1[2] = 0.0f; - // compute transformation from V1 to V2 - // we need to work in XY orthonormal space - XYSpaceForSTSpace( V1, V1 ); - XYSpaceForSTSpace( V2, V2 ); - VectorNormalize( V2, V2 ); - VectorNormalize( V1, V1 ); - c = DotProduct( V1, V2 ); - CrossProduct( V1, V2, cross ); - s = VectorLength( cross ); - // we compute the transformation matrix in XY space - // reference position of the Anchor in XY space - XYSpaceForSTSpace( XYRefAnchor, m_RefPts.data[m_iAnchorPoint] ); - // current position of the Anchor in XY space - XYSpaceForSTSpace( XYAnchor, m_Anchor ); - // compute transformation matrix - XYTM[0][0] = c; XYTM[1][1] = c; - if (cross[2]>0) - s *= -1.0f; - XYTM[0][1] = s; XYTM[1][0] = -s; - XYTM[0][2] = -c*XYRefAnchor[0] - s*XYRefAnchor[1] + XYAnchor[0]; - XYTM[1][2] = s*XYRefAnchor[0] - c*XYRefAnchor[1] + XYAnchor[1]; - // express this transformation matrix in ST space - m_TM[0][0] = XYTM[0][0]; - m_TM[1][0] = XYTM[1][0] * (float)m_TexSize[0] / (float)m_TexSize[1]; - m_TM[0][1] = XYTM[0][1] * (float)m_TexSize[1] / (float)m_TexSize[0]; - m_TM[1][1] = XYTM[1][1]; - m_TM[0][2] = XYTM[0][2] / (float)m_TexSize[0]; - m_TM[1][2] = XYTM[1][2] / (float)m_TexSize[1]; - // update all points - UpdateCtrlPts(); - } - else - { - // no Anchor point is defined, we translate all points - m_p2DView->GridForWindow( m_pPts->data[m_iDragPoint], xPos, yPos ); - m_TM[0][2] = m_pPts->data[m_iDragPoint][0] + m_TransOffset[0]; - m_TM[1][2] = m_pPts->data[m_iDragPoint][1] + m_TransOffset[1]; - // update all points - UpdateCtrlPts(); - } - // send a repaint message - g_pToolWnd->Redraw (); - return true; - } - - return false; -} - -bool CControlPointsManagerBFace::OnLButtonUp (int x, int y) -{ - if (ManagerState == Drag) - { - // this button is gonna become our Anchor - m_bGotAnchor = true; - m_iAnchorPoint = m_iDragPoint; - // let's get out of Drag mode - ManagerState = Idle; - // send a repaint message - g_pToolWnd->Redraw (); - return true; - } - return false; -} - -void CControlPointsManagerBFace::Render() -{ - int i; - - m_pQglTable->m_pfn_qglColor3f(0, 1, 0); - m_pQglTable->m_pfn_qglPointSize(6); - m_pQglTable->m_pfn_qglBegin( GL_POINTS ); - for ( i=0; im_pfn_qglColor3f(1, 0, 0); - else if ( m_bGotAnchor && i == m_iAnchorPoint ) - m_pQglTable->m_pfn_qglColor3f(0, 0, 1); - m_pQglTable->m_pfn_qglVertex2f( m_pPts->data[i][0], m_pPts->data[i][1] ); - m_pQglTable->m_pfn_qglColor3f(0, 1, 0); - } - m_pQglTable->m_pfn_qglEnd(); -} - -void CControlPointsManagerBFace::UpdateCtrlPts() -{ - int i; - - // update all points - for ( i=0; idata[i][0] = m_RefPts.data[i][0]*m_TM[0][0]+m_RefPts.data[i][1]*m_TM[0][1]+m_TM[0][2]; - m_pPts->data[i][1] = m_RefPts.data[i][0]*m_TM[1][0]+m_RefPts.data[i][1]*m_TM[1][1]+m_TM[1][2]; - } - - if (g_bPrefsUpdateCameraView) - { - Commit(); - // tell Radiant to update - // NOTE: little speed optimisation, disable window updates, and only update camera view - g_FuncTable.m_pfnSetScreenUpdate( false ); - g_SelectedFaceTable.m_pfnSetFaceInfo( 0, m_pFaceData ); - g_FuncTable.m_pfnSetScreenUpdate( true ); - g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA ); - } -} - -//++timo FIXME: we are using a global for the reference data, use a m_pCancelFaceData instead -void CControlPointsManagerBFace::Commit( ) -{ - brushprimit_texdef_t aux; - aux.coords[0][0] = m_TM[0][0]*g_CancelFaceData.brushprimit_texdef.coords[0][0] + m_TM[0][1]*g_CancelFaceData.brushprimit_texdef.coords[1][0]; - aux.coords[0][1] = m_TM[0][0]*g_CancelFaceData.brushprimit_texdef.coords[0][1] + m_TM[0][1]*g_CancelFaceData.brushprimit_texdef.coords[1][1]; - aux.coords[0][2] = m_TM[0][0]*g_CancelFaceData.brushprimit_texdef.coords[0][2] + m_TM[0][1]*g_CancelFaceData.brushprimit_texdef.coords[1][2] + m_TM[0][2]; - aux.coords[1][0] = m_TM[1][0]*g_CancelFaceData.brushprimit_texdef.coords[0][0] + m_TM[1][1]*g_CancelFaceData.brushprimit_texdef.coords[1][0]; - aux.coords[1][1] = m_TM[1][0]*g_CancelFaceData.brushprimit_texdef.coords[0][1] + m_TM[1][1]*g_CancelFaceData.brushprimit_texdef.coords[1][1]; - aux.coords[1][2] = m_TM[1][0]*g_CancelFaceData.brushprimit_texdef.coords[0][2] + m_TM[1][1]*g_CancelFaceData.brushprimit_texdef.coords[1][2] + m_TM[1][2]; - memcpy( &m_pFaceData->brushprimit_texdef, &aux, sizeof(brushprimit_texdef_t) ); -} - -void CControlPointsManagerBFace::ComputeTransOffset(int i) -{ - // compute the translation offset used to counteract rotation - m_TransOffset[0] = -m_TM[0][0]*m_RefPts.data[i][0] - m_TM[0][1]*m_RefPts.data[i][1]; - m_TransOffset[1] = -m_TM[1][0]*m_RefPts.data[i][0] - m_TM[1][1]*m_RefPts.data[i][1]; -} - -void CControlPointsManagerBFace::XYSpaceForSTSpace( float xy[2], const float st[2] ) -{ - xy[0] = st[0] * (float)m_TexSize[0]; - xy[1] = st[1] * (float)m_TexSize[1]; -} - -/* -====================================================================== -patch manager -====================================================================== -*/ - -void CControlPointsManagerPatch::Init( patchMesh_t* pWorkPatch, C2DView *p2DView, _QERQglTable *pQglTable, patchMesh_t* pPatch ) -{ - CControlPointsManager::Init( p2DView, pQglTable ); - m_pPatch = pPatch; - m_pWorkPatch = pWorkPatch; -} - -bool CControlPointsManagerPatch::OnLButtonDown (int xPos, int yPos) -{ - if (ManagerState == Idle) - { - int i,j; - - // scan the point list to see if we selected something - for ( i=0; iwidth; i++ ) - for ( j=0; jheight; j++ ) - if ( m_p2DView->DoesSelect( xPos, yPos, m_pWorkPatch->ctrl[i][j].st ) ) - { - m_iDragPoint[0] = i; - m_iDragPoint[1] = j; - ManagerState = Drag; - } - // send a repaint message - g_pToolWnd->Redraw (); - return true; - } - return false; -} - -bool CControlPointsManagerPatch::OnMouseMove (int xPos, int yPos) -{ - if (ManagerState == Drag) - { - m_p2DView->GridForWindow( m_pWorkPatch->ctrl[ m_iDragPoint[0] ][ m_iDragPoint[1] ].st, xPos, yPos ); - if (g_bPrefsUpdateCameraView) - { - Commit(); - // ask to rebuild the patch display data - m_pPatch->bDirty = true; - // send a repaint to the camera window as well - g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA ); - } - // send a repaint message - g_pToolWnd->Redraw (); - return true; - } - return false; -} - -bool CControlPointsManagerPatch::OnLButtonUp (int x, int y) -{ - if (ManagerState == Drag) - { - ManagerState = Idle; - // send a repaint message - g_pToolWnd->Redraw (); - } - return false; -} - -void CControlPointsManagerPatch::Render() -{ - int i,j; - - m_pQglTable->m_pfn_qglColor3f(0, 1, 0); - m_pQglTable->m_pfn_qglPointSize(6); - m_pQglTable->m_pfn_qglBegin( GL_POINTS ); - for ( i=0; iwidth; i++ ) - for ( j=0; jheight; j++ ) - { - if ( ManagerState == Drag && i == m_iDragPoint[0] && j == m_iDragPoint[1] ) - m_pQglTable->m_pfn_qglColor3f(1, 0, 0); - m_pQglTable->m_pfn_qglVertex2f( m_pWorkPatch->ctrl[i][j].st[0], m_pWorkPatch->ctrl[i][j].st[1] ); - m_pQglTable->m_pfn_qglColor3f(0, 1, 0); - } - m_pQglTable->m_pfn_qglEnd(); -} - -void CControlPointsManagerPatch::Commit() -{ - int i,j; - for ( i=0; iwidth; i++ ) - for ( j=0; jheight; j++ ) - { - m_pPatch->ctrl[i][j].st[0] = m_pWorkPatch->ctrl[i][j].st[0]; - m_pPatch->ctrl[i][j].st[1] = m_pWorkPatch->ctrl[i][j].st[1]; - } -} +/* +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 +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// a class to handle control points in a 2D view +// TODO: this one can be placed under an interface, and provided to the editor as service +// + +#include "StdAfx.h" + +void CControlPointsManagerBFace::Init (int iPts, CtrlPts_t *Pts, C2DView *p2DView, int TexSize[2], + _QERFaceData* pFaceData, _QERQglTable *pQglTable) +{ + ManagerState = Idle; + m_NumPoints = iPts; + m_pPts = Pts; + // store the initial config + memcpy( &m_RefPts, Pts, sizeof( CtrlPts_t ) ); + // init TM + memset( m_TM, 0, sizeof( float[2][3] ) ); + m_TM[0][0] = 1.0f; m_TM[1][1] = 1.0f; + m_bGotAnchor = false; + m_TransOffset[0] = 0.0f; m_TransOffset[1] = 0.0f; + m_TexSize[0] = TexSize[0]; + m_TexSize[1] = TexSize[1]; + m_pFaceData = pFaceData; + + CControlPointsManager::Init( p2DView, pQglTable ); +} + +bool CControlPointsManagerBFace::OnLButtonDown (int xPos, int yPos) +{ + if (ManagerState == Idle) + { + int i; + + // scan the point list to see if we selected something + for ( i=0; iDoesSelect( xPos, yPos, m_pPts->data[i] ) ) + { + m_iDragPoint = i; + ManagerState = Drag; + if (m_bGotAnchor && i == m_iAnchorPoint) + { + // this means we selected the Anchor, so we'll translate + m_bGotAnchor = false; + } + // perhaps we won't use translation, but we can compute it anyway + ComputeTransOffset(i); + if (m_bGotAnchor) + { + // we have an Anchor and selected another point + m_Anchor[0] = m_pPts->data[m_iAnchorPoint][0]; + m_Anchor[1] = m_pPts->data[m_iAnchorPoint][1]; + } + } + // send a repaint message + g_pToolWnd->Redraw (); + return true; + } + return false; +} + +bool CControlPointsManagerBFace::OnMouseMove (int xPos, int yPos) +{ + if (ManagerState == Drag) + { + if (m_bGotAnchor) + { + // there's an anchor, we are rotating the shape + // we need to work in XY space for orthonormality + float Pt[2]; + vec3_t V1,V2; + vec3_t cross; + float c,s; + // used in XY space + float XYTM[2][3]; + float XYRefAnchor[2]; + float XYAnchor[2]; + m_p2DView->GridForWindow( Pt, xPos, yPos ); + V2[0] = Pt[0] - m_Anchor[0]; + V2[1] = Pt[1] - m_Anchor[1]; + V2[2] = 0.0f; + V1[0] = m_RefPts.data[m_iDragPoint][0] - m_RefPts.data[m_iAnchorPoint][0]; + V1[1] = m_RefPts.data[m_iDragPoint][1] - m_RefPts.data[m_iAnchorPoint][1]; + V1[2] = 0.0f; + // compute transformation from V1 to V2 + // we need to work in XY orthonormal space + XYSpaceForSTSpace( V1, V1 ); + XYSpaceForSTSpace( V2, V2 ); + VectorNormalize( V2, V2 ); + VectorNormalize( V1, V1 ); + c = DotProduct( V1, V2 ); + CrossProduct( V1, V2, cross ); + s = VectorLength( cross ); + // we compute the transformation matrix in XY space + // reference position of the Anchor in XY space + XYSpaceForSTSpace( XYRefAnchor, m_RefPts.data[m_iAnchorPoint] ); + // current position of the Anchor in XY space + XYSpaceForSTSpace( XYAnchor, m_Anchor ); + // compute transformation matrix + XYTM[0][0] = c; XYTM[1][1] = c; + if (cross[2]>0) + s *= -1.0f; + XYTM[0][1] = s; XYTM[1][0] = -s; + XYTM[0][2] = -c*XYRefAnchor[0] - s*XYRefAnchor[1] + XYAnchor[0]; + XYTM[1][2] = s*XYRefAnchor[0] - c*XYRefAnchor[1] + XYAnchor[1]; + // express this transformation matrix in ST space + m_TM[0][0] = XYTM[0][0]; + m_TM[1][0] = XYTM[1][0] * (float)m_TexSize[0] / (float)m_TexSize[1]; + m_TM[0][1] = XYTM[0][1] * (float)m_TexSize[1] / (float)m_TexSize[0]; + m_TM[1][1] = XYTM[1][1]; + m_TM[0][2] = XYTM[0][2] / (float)m_TexSize[0]; + m_TM[1][2] = XYTM[1][2] / (float)m_TexSize[1]; + // update all points + UpdateCtrlPts(); + } + else + { + // no Anchor point is defined, we translate all points + m_p2DView->GridForWindow( m_pPts->data[m_iDragPoint], xPos, yPos ); + m_TM[0][2] = m_pPts->data[m_iDragPoint][0] + m_TransOffset[0]; + m_TM[1][2] = m_pPts->data[m_iDragPoint][1] + m_TransOffset[1]; + // update all points + UpdateCtrlPts(); + } + // send a repaint message + g_pToolWnd->Redraw (); + return true; + } + + return false; +} + +bool CControlPointsManagerBFace::OnLButtonUp (int x, int y) +{ + if (ManagerState == Drag) + { + // this button is gonna become our Anchor + m_bGotAnchor = true; + m_iAnchorPoint = m_iDragPoint; + // let's get out of Drag mode + ManagerState = Idle; + // send a repaint message + g_pToolWnd->Redraw (); + return true; + } + return false; +} + +void CControlPointsManagerBFace::Render() +{ + int i; + + m_pQglTable->m_pfn_qglColor3f(0, 1, 0); + m_pQglTable->m_pfn_qglPointSize(6); + m_pQglTable->m_pfn_qglBegin( GL_POINTS ); + for ( i=0; im_pfn_qglColor3f(1, 0, 0); + else if ( m_bGotAnchor && i == m_iAnchorPoint ) + m_pQglTable->m_pfn_qglColor3f(0, 0, 1); + m_pQglTable->m_pfn_qglVertex2f( m_pPts->data[i][0], m_pPts->data[i][1] ); + m_pQglTable->m_pfn_qglColor3f(0, 1, 0); + } + m_pQglTable->m_pfn_qglEnd(); +} + +void CControlPointsManagerBFace::UpdateCtrlPts() +{ + int i; + + // update all points + for ( i=0; idata[i][0] = m_RefPts.data[i][0]*m_TM[0][0]+m_RefPts.data[i][1]*m_TM[0][1]+m_TM[0][2]; + m_pPts->data[i][1] = m_RefPts.data[i][0]*m_TM[1][0]+m_RefPts.data[i][1]*m_TM[1][1]+m_TM[1][2]; + } + + if (g_bPrefsUpdateCameraView) + { + Commit(); + // tell Radiant to update + // NOTE: little speed optimisation, disable window updates, and only update camera view + g_FuncTable.m_pfnSetScreenUpdate( false ); + g_SelectedFaceTable.m_pfnSetFaceInfo( 0, m_pFaceData ); + g_FuncTable.m_pfnSetScreenUpdate( true ); + g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA ); + } +} + +//++timo FIXME: we are using a global for the reference data, use a m_pCancelFaceData instead +void CControlPointsManagerBFace::Commit( ) +{ + brushprimit_texdef_t aux; + aux.coords[0][0] = m_TM[0][0]*g_CancelFaceData.brushprimit_texdef.coords[0][0] + m_TM[0][1]*g_CancelFaceData.brushprimit_texdef.coords[1][0]; + aux.coords[0][1] = m_TM[0][0]*g_CancelFaceData.brushprimit_texdef.coords[0][1] + m_TM[0][1]*g_CancelFaceData.brushprimit_texdef.coords[1][1]; + aux.coords[0][2] = m_TM[0][0]*g_CancelFaceData.brushprimit_texdef.coords[0][2] + m_TM[0][1]*g_CancelFaceData.brushprimit_texdef.coords[1][2] + m_TM[0][2]; + aux.coords[1][0] = m_TM[1][0]*g_CancelFaceData.brushprimit_texdef.coords[0][0] + m_TM[1][1]*g_CancelFaceData.brushprimit_texdef.coords[1][0]; + aux.coords[1][1] = m_TM[1][0]*g_CancelFaceData.brushprimit_texdef.coords[0][1] + m_TM[1][1]*g_CancelFaceData.brushprimit_texdef.coords[1][1]; + aux.coords[1][2] = m_TM[1][0]*g_CancelFaceData.brushprimit_texdef.coords[0][2] + m_TM[1][1]*g_CancelFaceData.brushprimit_texdef.coords[1][2] + m_TM[1][2]; + memcpy( &m_pFaceData->brushprimit_texdef, &aux, sizeof(brushprimit_texdef_t) ); +} + +void CControlPointsManagerBFace::ComputeTransOffset(int i) +{ + // compute the translation offset used to counteract rotation + m_TransOffset[0] = -m_TM[0][0]*m_RefPts.data[i][0] - m_TM[0][1]*m_RefPts.data[i][1]; + m_TransOffset[1] = -m_TM[1][0]*m_RefPts.data[i][0] - m_TM[1][1]*m_RefPts.data[i][1]; +} + +void CControlPointsManagerBFace::XYSpaceForSTSpace( float xy[2], const float st[2] ) +{ + xy[0] = st[0] * (float)m_TexSize[0]; + xy[1] = st[1] * (float)m_TexSize[1]; +} + +/* +====================================================================== +patch manager +====================================================================== +*/ + +void CControlPointsManagerPatch::Init( patchMesh_t* pWorkPatch, C2DView *p2DView, _QERQglTable *pQglTable, patchMesh_t* pPatch ) +{ + CControlPointsManager::Init( p2DView, pQglTable ); + m_pPatch = pPatch; + m_pWorkPatch = pWorkPatch; +} + +bool CControlPointsManagerPatch::OnLButtonDown (int xPos, int yPos) +{ + if (ManagerState == Idle) + { + int i,j; + + // scan the point list to see if we selected something + for ( i=0; iwidth; i++ ) + for ( j=0; jheight; j++ ) + if ( m_p2DView->DoesSelect( xPos, yPos, m_pWorkPatch->ctrl[i][j].st ) ) + { + m_iDragPoint[0] = i; + m_iDragPoint[1] = j; + ManagerState = Drag; + } + // send a repaint message + g_pToolWnd->Redraw (); + return true; + } + return false; +} + +bool CControlPointsManagerPatch::OnMouseMove (int xPos, int yPos) +{ + if (ManagerState == Drag) + { + m_p2DView->GridForWindow( m_pWorkPatch->ctrl[ m_iDragPoint[0] ][ m_iDragPoint[1] ].st, xPos, yPos ); + if (g_bPrefsUpdateCameraView) + { + Commit(); + // ask to rebuild the patch display data + m_pPatch->bDirty = true; + // send a repaint to the camera window as well + g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA ); + } + // send a repaint message + g_pToolWnd->Redraw (); + return true; + } + return false; +} + +bool CControlPointsManagerPatch::OnLButtonUp (int x, int y) +{ + if (ManagerState == Drag) + { + ManagerState = Idle; + // send a repaint message + g_pToolWnd->Redraw (); + } + return false; +} + +void CControlPointsManagerPatch::Render() +{ + int i,j; + + m_pQglTable->m_pfn_qglColor3f(0, 1, 0); + m_pQglTable->m_pfn_qglPointSize(6); + m_pQglTable->m_pfn_qglBegin( GL_POINTS ); + for ( i=0; iwidth; i++ ) + for ( j=0; jheight; j++ ) + { + if ( ManagerState == Drag && i == m_iDragPoint[0] && j == m_iDragPoint[1] ) + m_pQglTable->m_pfn_qglColor3f(1, 0, 0); + m_pQglTable->m_pfn_qglVertex2f( m_pWorkPatch->ctrl[i][j].st[0], m_pWorkPatch->ctrl[i][j].st[1] ); + m_pQglTable->m_pfn_qglColor3f(0, 1, 0); + } + m_pQglTable->m_pfn_qglEnd(); +} + +void CControlPointsManagerPatch::Commit() +{ + int i,j; + for ( i=0; iwidth; i++ ) + for ( j=0; jheight; j++ ) + { + m_pPatch->ctrl[i][j].st[0] = m_pWorkPatch->ctrl[i][j].st[0]; + m_pPatch->ctrl[i][j].st[1] = m_pWorkPatch->ctrl[i][j].st[1]; + } +} diff --git a/plugins/textool/StdAfx.cpp b/plugins/textool/StdAfx.cpp index c6ef9354..ad9e9673 100644 --- a/plugins/textool/StdAfx.cpp +++ b/plugins/textool/StdAfx.cpp @@ -1,28 +1,28 @@ -/* -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 -*/ - -// stdafx.cpp : source file that includes just the standard includes -// stdafx.obj will contain the pre-compiled type information - -#include "stdafx.h" - -// TODO: reference any additional headers you need in STDAFX.H -// and not in this file +/* +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 +*/ + +// stdafx.cpp : source file that includes just the standard includes +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/plugins/textool/TexTool.cpp b/plugins/textool/TexTool.cpp index ee4a7ea3..eb519033 100644 --- a/plugins/textool/TexTool.cpp +++ b/plugins/textool/TexTool.cpp @@ -1,967 +1,967 @@ -/* -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 -*/ - -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// main plugin implementation -// texturing tools for Radiant -// - -#include "StdAfx.h" - -static void dialog_button_callback (GtkWidget *widget, gpointer data) -{ - GtkWidget *parent; - int *loop, *ret; - - parent = gtk_widget_get_toplevel (widget); - loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); - ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); - - *loop = 0; - *ret = (int)data; -} - -static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) -{ - int *loop; - - gtk_widget_hide (widget); - loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); - *loop = 0; - - return TRUE; -} - -int DoMessageBox (const char* lpText, const char* lpCaption, guint32 uType) -{ - GtkWidget *window, *w, *vbox, *hbox; - int mode = (uType & MB_TYPEMASK), ret, loop = 1; - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_signal_connect (GTK_OBJECT (window), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (window), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - gtk_window_set_title (GTK_WINDOW (window), lpCaption); - gtk_container_border_width (GTK_CONTAINER (window), 10); - g_object_set_data (G_OBJECT (window), "loop", &loop); - g_object_set_data (G_OBJECT (window), "ret", &ret); - gtk_widget_realize (window); - - vbox = gtk_vbox_new (FALSE, 10); - gtk_container_add (GTK_CONTAINER (window), vbox); - gtk_widget_show (vbox); - - w = gtk_label_new (lpText); - gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); - gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); - gtk_widget_show (w); - - w = gtk_hseparator_new (); - gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); - gtk_widget_show (w); - - hbox = gtk_hbox_new (FALSE, 10); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); - gtk_widget_show (hbox); - - if (mode == MB_OK) - { - w = gtk_button_new_with_label ("Ok"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); - gtk_widget_grab_default (w); - gtk_widget_show (w); - ret = IDOK; - } - else if (mode == MB_OKCANCEL) - { - w = gtk_button_new_with_label ("Ok"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); - gtk_widget_grab_default (w); - gtk_widget_show (w); - - w = gtk_button_new_with_label ("Cancel"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_show (w); - ret = IDCANCEL; - } - else if (mode == MB_YESNOCANCEL) - { - w = gtk_button_new_with_label ("Yes"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); - GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); - gtk_widget_grab_default (w); - gtk_widget_show (w); - - w = gtk_button_new_with_label ("No"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO)); - gtk_widget_show (w); - - w = gtk_button_new_with_label ("Cancel"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_show (w); - ret = IDCANCEL; - } - else /* if (mode == MB_YESNO) */ - { - w = gtk_button_new_with_label ("Yes"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); - GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); - gtk_widget_grab_default (w); - gtk_widget_show (w); - - w = gtk_button_new_with_label ("No"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO)); - gtk_widget_show (w); - ret = IDNO; - } - - gtk_widget_show (window); - gtk_grab_add (window); - - while (loop) - gtk_main_iteration (); - - gtk_grab_remove (window); - gtk_widget_destroy (window); - - return ret; -} - -// Radiant function table -_QERFuncTable_1 g_FuncTable; - -// plugin name -const char *PLUGIN_NAME = "Q3 Texture Tools"; - -// commands in the menu -const char *PLUGIN_COMMANDS = "About...;Go..."; - -// cast to GtkWidget* -void *g_pMainWnd; -IWindow *g_pToolWnd = NULL; // handle to the window -CWindowListener g_Listen; - -// plugin interfaces --------------------------- -bool g_bQglInitDone = false; -_QERQglTable g_QglTable; -bool g_bSelectedFaceInitDone = false; -_QERSelectedFaceTable g_SelectedFaceTable; -bool g_bUITable = false; -_QERUITable g_UITable; - -// selected face ------------------------------- -// we use this one to commit / read with Radiant -_QERFaceData g_SelectedFaceData; -// g_pSelectedFaceWindings gets allocated with MAX_POINTS_ON_WINDING at plugin startup ( QERPlug_Init ) -winding_t *g_pSelectedFaceWinding = NULL; -const float g_ViewportRatio = 1.2f; -// usefull class to manage the 2D view -C2DView g_2DView; -// control points to move the polygon -CControlPointsManagerBFace g_ControlPointsBFace; -// tells if a face is selected and we have something to render in the TexWindow -bool g_bTexViewReady = false; -// data for texture work -int g_NumPoints; -CtrlPts_t g_WorkWinding; -// reference _QERFaceData we use on Cancel, and for Commit -_QERFaceData g_CancelFaceData; - -// patches ------------------------------------- -bool g_bPatch = false; -//++timo we use this one to grab selected patchMesh_t -// FIXME: update when there's a real interface to read/write patches -bool g_bSurfaceTableInitDone = false; -_QERAppSurfaceTable g_SurfaceTable; -CControlPointsManagerPatch g_ControlPointsPatch; -// data for texture work -patchMesh_t* g_pPatch; -// we only use ctrl[][].st in this one -patchMesh_t g_WorkPatch; -// copy of initial g_pPatch for Cancel situation -patchMesh_t g_CancelPatch; - -// --------------------------------------------- -// holds the manager we are currently using -CControlPointsManager *g_pManager = NULL; - -// --------------------------------------------- -// globals flags for user preferences -//++timo TODO: this should be retrieved from the Editor's .INI prefs in a dedicated interface -// update camera view during manipulation ? -bool g_bPrefsUpdateCameraView = true; - -// misc ---------------------------------------- -bool g_bHelp = false; -//++timo FIXME: used to close the plugin window if InitTexView fails -// it's dirty, only use is to prevent infinite loop in DialogProc -bool g_bClosing = false; - -const char *PLUGIN_ABOUT = "Texture Tools for Radiant\n\n" - "Gtk port by Leonardo Zide (leo@lokigames.com)\n" - "Original version by Timothee \"TTimo\" Besset (timo@qeradiant.com)"; - -extern "C" void* WINAPI QERPlug_GetFuncTable () -{ - return &g_FuncTable; -} - -const char* QERPlug_Init (void* hApp, void *pWidget) -{ - int size; - GtkWidget* pMainWidget = static_cast(pWidget); - - g_pMainWnd = pMainWidget; - memset(&g_FuncTable, 0, sizeof(_QERFuncTable_1)); - g_FuncTable.m_nSize = sizeof(_QERFuncTable_1); - size = (int)((winding_t *)0)->points[MAX_POINTS_ON_WINDING]; - g_pSelectedFaceWinding = (winding_t *)malloc( size ); - memset( g_pSelectedFaceWinding, 0, size ); - return "Texture tools for Radiant"; -} - -const char* QERPlug_GetName() -{ - return (char*)PLUGIN_NAME; -} - -const char* QERPlug_GetCommandList() -{ - return PLUGIN_COMMANDS; -} - -char *TranslateString (char *buf) -{ - static char buf2[32768]; - int i, l; - char *out; - - l = strlen(buf); - out = buf2; - for (i=0 ; igetHeight(); - g_2DView.m_rect.right = hwndDlg->getWidth(); - - // we need to draw this area, now compute a bigger area so the texture scale is the same along X and Y - // compute box shape in XY space, let's say X <-> S we'll get a ratio for Y: - if (!g_bPatch) - { - g_SelectedFaceTable.m_pfnGetTextureSize( 0, TexSize ); - } - else - { - TexSize[0] = g_pPatch->d_texture->width; - TexSize[1] = g_pPatch->d_texture->height; - } - // we want a texture with the same X / Y ratio - // compute XY space / window size ratio - float SSize = (float)fabs( g_2DView.m_Maxs[0] - g_2DView.m_Mins[0] ); - float TSize = (float)fabs( g_2DView.m_Maxs[1] - g_2DView.m_Mins[1] ); - float XSize = TexSize[0] * SSize; - float YSize = TexSize[1] * TSize; - float RatioX = XSize / (float)abs( g_2DView.m_rect.left - g_2DView.m_rect.right ); - float RatioY = YSize / (float)abs( g_2DView.m_rect.top - g_2DView.m_rect.bottom ); - if ( RatioX > RatioY ) - { - YSize = (float)abs( g_2DView.m_rect.top - g_2DView.m_rect.bottom ) * RatioX; - TSize = YSize / (float)TexSize[1]; - } - else - { - XSize = (float)abs( g_2DView.m_rect.left - g_2DView.m_rect.right ) * RatioY; - SSize = XSize / (float)TexSize[0]; - } - g_2DView.m_Mins[0] = g_2DView.m_Center[0] - 0.5f * SSize; - g_2DView.m_Maxs[0] = g_2DView.m_Center[0] + 0.5f * SSize; - g_2DView.m_Mins[1] = g_2DView.m_Center[1] - 0.5f * TSize; - g_2DView.m_Maxs[1] = g_2DView.m_Center[1] + 0.5f * TSize; -} - -// call this one each time we need to re-init -//++timo TODO: re-init objects state, g_2DView and g_ControlPointsManager -void InitTexView( IWindow* hwndDlg ) -{ - // size of the texture we are working on - int TexSize[2]; - g_bTexViewReady = false; - if (g_SelectedFaceTable.m_pfnGetSelectedFaceCount() != 0) - { - g_SelectedFaceTable.m_pfnGetFaceInfo( 0, &g_SelectedFaceData, g_pSelectedFaceWinding ); - g_bPatch = false; - int i; - // we have something selected - // setup: compute BBox for the winding ( in ST space ) - //++timo FIXME: move this in a C2DView member ? used as well for patches - g_2DView.m_Mins[0] = +9999.0f; g_2DView.m_Mins[1] = +9999.0f; - g_2DView.m_Maxs[0] = -9999.0f; g_2DView.m_Maxs[1] = -9999.0f; - for ( i=0; inumpoints; i++ ) - { - if ( g_pSelectedFaceWinding->points[i][3] < g_2DView.m_Mins[0] ) - g_2DView.m_Mins[0] = g_pSelectedFaceWinding->points[i][3]; - if ( g_pSelectedFaceWinding->points[i][3] > g_2DView.m_Maxs[0] ) - g_2DView.m_Maxs[0] = g_pSelectedFaceWinding->points[i][3]; - if ( g_pSelectedFaceWinding->points[i][4] < g_2DView.m_Mins[1] ) - g_2DView.m_Mins[1] = g_pSelectedFaceWinding->points[i][4]; - if ( g_pSelectedFaceWinding->points[i][4] > g_2DView.m_Maxs[1] ) - g_2DView.m_Maxs[1] = g_pSelectedFaceWinding->points[i][4]; - } - // NOTE: FitView will read and init TexSize - FitView( hwndDlg, TexSize ); - // now init the work tables - g_NumPoints = g_pSelectedFaceWinding->numpoints; - for ( i=0; ipoints[i][3]; - g_WorkWinding.data[i][1] = g_pSelectedFaceWinding->points[i][4]; - } - g_ControlPointsBFace.Init( g_NumPoints, &g_WorkWinding, &g_2DView, TexSize, &g_SelectedFaceData, &g_QglTable ); - // init snap-to-grid - float fTexStep[2]; - fTexStep[0] = 1.0f / float(TexSize[0]); - fTexStep[1] = 1.0f / float(TexSize[1]); - g_2DView.SetGrid( fTexStep[0], fTexStep[1] ); - g_pManager = &g_ControlPointsBFace; - // prepare the "Cancel" data - memcpy( &g_CancelFaceData, &g_SelectedFaceData, sizeof(_QERFaceData) ); - // we are done - g_bTexViewReady = true; - } - else if ( g_SurfaceTable.m_pfnAnyPatchesSelected()) - { - g_pPatch = g_SurfaceTable.m_pfnGetSelectedPatch(); - g_bPatch = true; - int i,j; - // compute BBox for all patch points - g_2DView.m_Mins[0] = +9999.0f; g_2DView.m_Mins[1] = +9999.0f; - g_2DView.m_Maxs[0] = -9999.0f; g_2DView.m_Maxs[1] = -9999.0f; - for ( i=0; iwidth; i++ ) - { - for ( j=0; jheight; j++ ) - { - if ( g_pPatch->ctrl[i][j].st[0] < g_2DView.m_Mins[0] ) - g_2DView.m_Mins[0] = g_pPatch->ctrl[i][j].st[0]; - if ( g_pPatch->ctrl[i][j].st[0] > g_2DView.m_Maxs[0] ) - g_2DView.m_Maxs[0] = g_pPatch->ctrl[i][j].st[0]; - if ( g_pPatch->ctrl[i][j].st[1] < g_2DView.m_Mins[1] ) - g_2DView.m_Mins[1] = g_pPatch->ctrl[i][j].st[1]; - if ( g_pPatch->ctrl[i][j].st[1] > g_2DView.m_Maxs[1] ) - g_2DView.m_Maxs[1] = g_pPatch->ctrl[i][j].st[1]; - } - } - FitView( hwndDlg, TexSize); - // init the work tables - g_WorkPatch = *g_pPatch; - g_ControlPointsPatch.Init( &g_WorkPatch, &g_2DView, &g_QglTable, g_pPatch ); - // init snap-to-grid - float fTexStep[2]; - fTexStep[0] = 1.0f / float(TexSize[0]); - fTexStep[1] = 1.0f / float(TexSize[1]); - g_2DView.SetGrid( fTexStep[0], fTexStep[1] ); - g_pManager = &g_ControlPointsPatch; - // prepare the "cancel" data - g_CancelPatch = *g_pPatch; - // we are done - g_bTexViewReady = true; - } -} - -void Textool_Validate() -{ - // validate current situation into the main view - g_pManager->Commit( ); - // for a brush face we have an aditionnal step - if (!g_bPatch) - { - // tell Radiant to update (will also send update windows messages ) - g_SelectedFaceTable.m_pfnSetFaceInfo( 0, &g_SelectedFaceData ); - } - else - { - // ask to rebuild the patch display data - g_pPatch->bDirty = true; - // send a repaint to the camera window as well - g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA ); - } - // we'll need to update after that as well: - g_bTexViewReady = false; - // send a repaint message - g_pToolWnd->Redraw (); -} - -void Textool_Cancel() -{ - if (!g_bPatch) - { - // tell Radiant to update (will also send update windows messages ) - g_SelectedFaceTable.m_pfnSetFaceInfo( 0, &g_CancelFaceData ); - } - else - { - *g_pPatch = g_CancelPatch; - g_pPatch->bDirty = true; - g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA ); - } - // do not call destroy, decref it - g_pToolWnd->DecRef(); - g_pToolWnd = NULL; -} - -static void DoExpose () -{ - int i,j; - - g_2DView.PreparePaint(); - g_QglTable.m_pfn_qglColor3f(1, 1, 1); - // draw the texture background - g_QglTable.m_pfn_qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); - if (!g_bPatch) - { - g_QglTable.m_pfn_qglBindTexture( GL_TEXTURE_2D, g_SelectedFaceTable.m_pfnGetTextureNumber(0) ); - } - else - { - g_QglTable.m_pfn_qglBindTexture( GL_TEXTURE_2D, g_pPatch->d_texture->texture_number ); - } - - g_QglTable.m_pfn_qglEnable( GL_TEXTURE_2D ); - g_QglTable.m_pfn_qglBegin( GL_QUADS ); - g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Mins[0], g_2DView.m_Mins[1] ); - g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Mins[0], g_2DView.m_Mins[1] ); - g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Maxs[0], g_2DView.m_Mins[1] ); - g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Maxs[0], g_2DView.m_Mins[1] ); - g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Maxs[0], g_2DView.m_Maxs[1] ); - g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Maxs[0], g_2DView.m_Maxs[1] ); - g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Mins[0], g_2DView.m_Maxs[1] ); - g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Mins[0], g_2DView.m_Maxs[1] ); - g_QglTable.m_pfn_qglEnd(); - g_QglTable.m_pfn_qglDisable( GL_TEXTURE_2D ); - - if (!g_bPatch) - { - g_QglTable.m_pfn_qglBegin( GL_LINE_LOOP ); - for ( i=0; iwidth; i++ ) - for ( j=0; jheight; j++ ) - { - if ( i < g_pPatch->width-1 ) - { - g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i][j].st[0], g_WorkPatch.ctrl[i][j].st[1] ); - g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i+1][j].st[0], g_WorkPatch.ctrl[i+1][j].st[1] ); - } - - if ( j < g_pPatch->height-1 ) - { - g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i][j].st[0], g_WorkPatch.ctrl[i][j].st[1] ); - g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i][j+1].st[0], g_WorkPatch.ctrl[i][j+1].st[1] ); - } - } - g_QglTable.m_pfn_qglEnd(); - } - - // let the control points manager render - g_pManager->Render( ); -} - -static bool CanProcess () -{ - if (!g_bTexViewReady && !g_bClosing) - { - InitTexView (g_pToolWnd); - - if (!g_bTexViewReady) - { - g_bClosing = true; - DoMessageBox ("You must have brush primitives activated in your project settings and\n" - "have a patch or a single face selected to use the TexTool plugin.\n" - "See plugins/TexToolHelp for documentation.", "TexTool plugin", MB_ICONERROR | MB_OK); - // decref, this will destroy - g_pToolWnd->DecRef(); - g_pToolWnd = NULL; - return 0; - } - else - g_bClosing = false; - } - else if (!g_bTexViewReady && g_bClosing) - { - return 0; - } - - return 1; -} - -#if 0 -static void button_press (GtkWidget *widget, GdkEventButton *event, gpointer data) -{ - if (CanProcess ()) - { - switch (event->button) - { - case 1: - g_pManager->OnLButtonDown (event->x, event->y); break; - case 3: - g_2DView.OnRButtonDown (event->x, event->y); break; - } - } -} - -static void button_release (GtkWidget *widget, GdkEventButton *event, gpointer data) -{ - if (CanProcess ()) - { - switch (event->button) - { - case 1: - g_pManager->OnLButtonUp (event->x, event->y); break; - case 3: - g_2DView.OnRButtonUp (event->x, event->y); break; - } - } -} - -static void motion (GtkWidget *widget, GdkEventMotion *event, gpointer data) -{ - if (CanProcess ()) - { - if (g_2DView.OnMouseMove (event->x, event->y)) - return; - - if (g_pManager->OnMouseMove (event->x, event->y)) - return; - } -} - -static gint expose (GtkWidget *widget, GdkEventExpose *event, gpointer data) -{ - if (event->count > 0) - return TRUE; - - if (!CanProcess ()) - return TRUE; - - if (g_bTexViewReady) - { - g_2DView.m_rect.bottom = widget->allocation.height; - g_2DView.m_rect.right = widget->allocation.width; - - if (!g_QglTable.m_pfn_glwidget_make_current (g_pToolWidget)) - { - Sys_Printf("TexTool: glMakeCurrent failed\n"); - return TRUE; - } - - DoExpose (); - - g_QglTable.m_pfn_glwidget_swap_buffers (g_pToolWidget); - } - - return TRUE; -} - -static gint keypress (GtkWidget* widget, GdkEventKey* event, gpointer data) -{ - unsigned int code = gdk_keyval_to_upper(event->keyval); - - if (code == GDK_Escape) - { - gtk_widget_destroy (g_pToolWnd); - g_pToolWnd = NULL; - return TRUE; - } - - if (CanProcess ()) - { - if (g_2DView.OnKeyDown (code)) - return FALSE; - - if (code == GDK_Return) - { - Textool_Validate(); - return FALSE; - } - } - - return TRUE; -} - -static gint close (GtkWidget *widget, GdkEvent* event, gpointer data) -{ - gtk_widget_destroy (widget); - g_pToolWnd = NULL; - - return TRUE; -} - -static GtkWidget* CreateOpenGLWidget () -{ - g_pToolWidget = g_QglTable.m_pfn_glwidget_new (FALSE, g_QglTable.m_pfn_GetQeglobalsGLWidget ()); - - gtk_widget_set_events (g_pToolWidget, GDK_DESTROY | GDK_EXPOSURE_MASK | GDK_KEY_PRESS_MASK | - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK); - - // Connect signal handlers - gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "expose_event", GTK_SIGNAL_FUNC (expose), NULL); - gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "motion_notify_event", - GTK_SIGNAL_FUNC (motion), NULL); - gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "button_press_event", - GTK_SIGNAL_FUNC (button_press), NULL); - gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "button_release_event", - GTK_SIGNAL_FUNC (button_release), NULL); - - gtk_signal_connect (GTK_OBJECT (g_pToolWnd), "delete_event", GTK_SIGNAL_FUNC (close), NULL); - gtk_signal_connect (GTK_OBJECT (g_pToolWnd), "key_press_event", - GTK_SIGNAL_FUNC (keypress), NULL); - - return g_pToolWidget; -} -#endif - -#if 0 -static void DoPaint () -{ - if (!CanProcess ()) - return; - - if (g_bTexViewReady) - { - g_2DView.m_rect.bottom = g_pToolWnd->getHeight(); - g_2DView.m_rect.right = g_pToolWnd->getWidth(); - - // set GL_PROJECTION - g_2DView.PreparePaint(); - // render the objects - // the master is not rendered the same way, draw over a unified texture background - g_2DView.TextureBackground(g_DrawObjects[0].pObject->getTextureNumber()); - if (g_nDrawObjects >= 1) - { - int i; - for (i=1;iPrepareModelView(g_DrawObjects[i].pTopo); - g_DrawObjects[i].pObject->RenderAuxiliary(); - } - } - // draw the polygon outline and control points - g_DrawObjects[0].pObject->PrepareModelView(NULL); - g_DrawObjects[0].pObject->RenderUI(); - } -} -#endif - -bool CWindowListener::OnLButtonDown(guint32 nFlags, double x, double y) -{ - if (CanProcess()) - { - g_pManager->OnLButtonDown((int)x, (int)y); - return true; - } - return false; -} - -bool CWindowListener::OnRButtonDown(guint32 nFlags, double x, double y) -{ - if (CanProcess()) - { - g_2DView.OnRButtonDown ((int)x, (int)y); - return true; - } - return false; -} - -bool CWindowListener::OnLButtonUp(guint32 nFlags, double x, double y) -{ - if (CanProcess()) - { - g_pManager->OnLButtonUp((int)x, (int)y); - return true; - } - return false; -} - -bool CWindowListener::OnRButtonUp(guint32 nFlags, double x, double y) -{ - if (CanProcess()) - { - g_2DView.OnRButtonUp ((int)x, (int)y); - return true; - } - return false; -} - -bool CWindowListener::OnMouseMove(guint32 nFlags, double x, double y) -{ - if (CanProcess ()) - { - if (g_2DView.OnMouseMove ((int)x, (int)y)) - return true; - - g_pManager->OnMouseMove((int)x, (int)y); - return true; - } - return false; -} - -// the widget is closing -void CWindowListener::Close() -{ - g_pToolWnd = NULL; -} - -bool CWindowListener::Paint() -{ - if (!CanProcess ()) - return false; - - if (g_bTexViewReady) - DoExpose(); - - return true; -} - -bool CWindowListener::OnKeyPressed(char *s) -{ - if (!strcmp(s,"Escape")) - { - Textool_Cancel(); - return TRUE; - } - if (CanProcess ()) - { - if (g_2DView.OnKeyDown (s)) - return TRUE; - - if (!strcmp(s,"Return")) - { - Textool_Validate(); - return TRUE; - } - } - return FALSE; -} - -extern "C" void QERPlug_Dispatch(const char* p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) -{ - #if 0 - // if it's the first call, perhaps we need some additional init steps - if (!g_bQglInitDone) - { - g_QglTable.m_nSize = sizeof(_QERQglTable); - if ( g_FuncTable.m_pfnRequestInterface( QERQglTable_GUID, static_cast(&g_QglTable) ) ) - { - g_bQglInitDone = true; - } - else - { - Sys_Printf("TexTool plugin: _QERQglTable interface request failed\n"); - return; - } - } - - if (!g_bSelectedFaceInitDone) - { - g_SelectedFaceTable.m_nSize = sizeof(_QERSelectedFaceTable); - if (g_FuncTable.m_pfnRequestInterface (QERSelectedFaceTable_GUID, - static_cast(&g_SelectedFaceTable))) - { - g_bSelectedFaceInitDone = true; - } - else - { - Sys_Printf("TexTool plugin: _QERSelectedFaceTable interface request failed\n"); - return; - } - } - - if (!g_bSurfaceTableInitDone) - { - g_SurfaceTable.m_nSize = sizeof(_QERAppSurfaceTable); - if ( g_FuncTable.m_pfnRequestInterface( QERAppSurfaceTable_GUID, static_cast(&g_SurfaceTable) ) ) - { - g_bSurfaceTableInitDone = true; - } - else - { - Sys_Printf("TexTool plugin: _QERAppSurfaceTable interface request failed\n"); - return; - } - } - - if (!g_bUITable) - { - g_UITable.m_nSize = sizeof(_QERUITable); - if ( g_FuncTable.m_pfnRequestInterface( QERUI_GUID, static_cast(&g_UITable) ) ) - { - g_bUITable = true; - } - else - { - Sys_Printf("TexTool plugin: _QERUITable interface request failed\n"); - return; - } - } - #endif - - if (!strcmp(p, "About...")) - { - DoMessageBox (PLUGIN_ABOUT, "About ...", MB_OK ); - } - else if (!strcmp(p, "Go...")) - { - if (!g_pToolWnd) - { - g_pToolWnd = g_UITable.m_pfnCreateGLWindow(); - g_pToolWnd->setSizeParm(300,300); - g_pToolWnd->setName("TexTool"); - // g_Listener is a static class, we need to bump the refCount to avoid premature release problems - g_Listen.IncRef(); - // setListener will incRef on the listener too - g_pToolWnd->setListener(&g_Listen); - if (!g_pToolWnd->Show()) - { - DoMessageBox ("Error creating texture tools window!", "TexTool plugin", MB_ICONERROR | MB_OK); - return; - } - } - - g_bTexViewReady = false; - g_bClosing = false; - } - else if (!strcmp(p, "Help...")) - { - if (!g_bHelp) - DoMessageBox ("Select a brush face (ctrl+shift+left mouse) or a patch, and hit Go...\n" - "See tutorials for more", "TexTool plugin", MB_OK ); - else - DoMessageBox ("Are you kidding me ?", "TexTool plugin", MB_OK ); - g_bHelp = true; - } -} - -// ============================================================================= -// SYNAPSE - -CSynapseServer* g_pSynapseServer = NULL; -CSynapseClientTexTool 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(PLUGIN_MAJOR, "textool", 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); - g_SynapseClient.AddAPI(SELECTEDFACE_MAJOR, NULL, sizeof(g_SelectedFaceTable), SYN_REQUIRE, &g_SelectedFaceTable); - - return &g_SynapseClient; -} - -bool CSynapseClientTexTool::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; - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -#include "version.h" - -const char* CSynapseClientTexTool::GetInfo() -{ - return "Texture Tools plugin built " __DATE__ " " RADIANT_VERSION; -} +/* +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 +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// main plugin implementation +// texturing tools for Radiant +// + +#include "StdAfx.h" + +static void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} + +int DoMessageBox (const char* lpText, const char* lpCaption, guint32 uType) +{ + GtkWidget *window, *w, *vbox, *hbox; + int mode = (uType & MB_TYPEMASK), ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_window_set_title (GTK_WINDOW (window), lpCaption); + gtk_container_border_width (GTK_CONTAINER (window), 10); + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + gtk_widget_realize (window); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + w = gtk_label_new (lpText); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + if (mode == MB_OK) + { + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + ret = IDOK; + } + else if (mode == MB_OKCANCEL) + { + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + } + else if (mode == MB_YESNOCANCEL) + { + w = gtk_button_new_with_label ("Yes"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("No"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO)); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + } + else /* if (mode == MB_YESNO) */ + { + w = gtk_button_new_with_label ("Yes"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("No"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO)); + gtk_widget_show (w); + ret = IDNO; + } + + gtk_widget_show (window); + gtk_grab_add (window); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} + +// Radiant function table +_QERFuncTable_1 g_FuncTable; + +// plugin name +const char *PLUGIN_NAME = "Q3 Texture Tools"; + +// commands in the menu +const char *PLUGIN_COMMANDS = "About...;Go..."; + +// cast to GtkWidget* +void *g_pMainWnd; +IWindow *g_pToolWnd = NULL; // handle to the window +CWindowListener g_Listen; + +// plugin interfaces --------------------------- +bool g_bQglInitDone = false; +_QERQglTable g_QglTable; +bool g_bSelectedFaceInitDone = false; +_QERSelectedFaceTable g_SelectedFaceTable; +bool g_bUITable = false; +_QERUITable g_UITable; + +// selected face ------------------------------- +// we use this one to commit / read with Radiant +_QERFaceData g_SelectedFaceData; +// g_pSelectedFaceWindings gets allocated with MAX_POINTS_ON_WINDING at plugin startup ( QERPlug_Init ) +winding_t *g_pSelectedFaceWinding = NULL; +const float g_ViewportRatio = 1.2f; +// usefull class to manage the 2D view +C2DView g_2DView; +// control points to move the polygon +CControlPointsManagerBFace g_ControlPointsBFace; +// tells if a face is selected and we have something to render in the TexWindow +bool g_bTexViewReady = false; +// data for texture work +int g_NumPoints; +CtrlPts_t g_WorkWinding; +// reference _QERFaceData we use on Cancel, and for Commit +_QERFaceData g_CancelFaceData; + +// patches ------------------------------------- +bool g_bPatch = false; +//++timo we use this one to grab selected patchMesh_t +// FIXME: update when there's a real interface to read/write patches +bool g_bSurfaceTableInitDone = false; +_QERAppSurfaceTable g_SurfaceTable; +CControlPointsManagerPatch g_ControlPointsPatch; +// data for texture work +patchMesh_t* g_pPatch; +// we only use ctrl[][].st in this one +patchMesh_t g_WorkPatch; +// copy of initial g_pPatch for Cancel situation +patchMesh_t g_CancelPatch; + +// --------------------------------------------- +// holds the manager we are currently using +CControlPointsManager *g_pManager = NULL; + +// --------------------------------------------- +// globals flags for user preferences +//++timo TODO: this should be retrieved from the Editor's .INI prefs in a dedicated interface +// update camera view during manipulation ? +bool g_bPrefsUpdateCameraView = true; + +// misc ---------------------------------------- +bool g_bHelp = false; +//++timo FIXME: used to close the plugin window if InitTexView fails +// it's dirty, only use is to prevent infinite loop in DialogProc +bool g_bClosing = false; + +const char *PLUGIN_ABOUT = "Texture Tools for Radiant\n\n" + "Gtk port by Leonardo Zide (leo@lokigames.com)\n" + "Original version by Timothee \"TTimo\" Besset (timo@qeradiant.com)"; + +extern "C" void* WINAPI QERPlug_GetFuncTable () +{ + return &g_FuncTable; +} + +const char* QERPlug_Init (void* hApp, void *pWidget) +{ + int size; + GtkWidget* pMainWidget = static_cast(pWidget); + + g_pMainWnd = pMainWidget; + memset(&g_FuncTable, 0, sizeof(_QERFuncTable_1)); + g_FuncTable.m_nSize = sizeof(_QERFuncTable_1); + size = (int)((winding_t *)0)->points[MAX_POINTS_ON_WINDING]; + g_pSelectedFaceWinding = (winding_t *)malloc( size ); + memset( g_pSelectedFaceWinding, 0, size ); + return "Texture tools for Radiant"; +} + +const char* QERPlug_GetName() +{ + return (char*)PLUGIN_NAME; +} + +const char* QERPlug_GetCommandList() +{ + return PLUGIN_COMMANDS; +} + +char *TranslateString (char *buf) +{ + static char buf2[32768]; + int i, l; + char *out; + + l = strlen(buf); + out = buf2; + for (i=0 ; igetHeight(); + g_2DView.m_rect.right = hwndDlg->getWidth(); + + // we need to draw this area, now compute a bigger area so the texture scale is the same along X and Y + // compute box shape in XY space, let's say X <-> S we'll get a ratio for Y: + if (!g_bPatch) + { + g_SelectedFaceTable.m_pfnGetTextureSize( 0, TexSize ); + } + else + { + TexSize[0] = g_pPatch->d_texture->width; + TexSize[1] = g_pPatch->d_texture->height; + } + // we want a texture with the same X / Y ratio + // compute XY space / window size ratio + float SSize = (float)fabs( g_2DView.m_Maxs[0] - g_2DView.m_Mins[0] ); + float TSize = (float)fabs( g_2DView.m_Maxs[1] - g_2DView.m_Mins[1] ); + float XSize = TexSize[0] * SSize; + float YSize = TexSize[1] * TSize; + float RatioX = XSize / (float)abs( g_2DView.m_rect.left - g_2DView.m_rect.right ); + float RatioY = YSize / (float)abs( g_2DView.m_rect.top - g_2DView.m_rect.bottom ); + if ( RatioX > RatioY ) + { + YSize = (float)abs( g_2DView.m_rect.top - g_2DView.m_rect.bottom ) * RatioX; + TSize = YSize / (float)TexSize[1]; + } + else + { + XSize = (float)abs( g_2DView.m_rect.left - g_2DView.m_rect.right ) * RatioY; + SSize = XSize / (float)TexSize[0]; + } + g_2DView.m_Mins[0] = g_2DView.m_Center[0] - 0.5f * SSize; + g_2DView.m_Maxs[0] = g_2DView.m_Center[0] + 0.5f * SSize; + g_2DView.m_Mins[1] = g_2DView.m_Center[1] - 0.5f * TSize; + g_2DView.m_Maxs[1] = g_2DView.m_Center[1] + 0.5f * TSize; +} + +// call this one each time we need to re-init +//++timo TODO: re-init objects state, g_2DView and g_ControlPointsManager +void InitTexView( IWindow* hwndDlg ) +{ + // size of the texture we are working on + int TexSize[2]; + g_bTexViewReady = false; + if (g_SelectedFaceTable.m_pfnGetSelectedFaceCount() != 0) + { + g_SelectedFaceTable.m_pfnGetFaceInfo( 0, &g_SelectedFaceData, g_pSelectedFaceWinding ); + g_bPatch = false; + int i; + // we have something selected + // setup: compute BBox for the winding ( in ST space ) + //++timo FIXME: move this in a C2DView member ? used as well for patches + g_2DView.m_Mins[0] = +9999.0f; g_2DView.m_Mins[1] = +9999.0f; + g_2DView.m_Maxs[0] = -9999.0f; g_2DView.m_Maxs[1] = -9999.0f; + for ( i=0; inumpoints; i++ ) + { + if ( g_pSelectedFaceWinding->points[i][3] < g_2DView.m_Mins[0] ) + g_2DView.m_Mins[0] = g_pSelectedFaceWinding->points[i][3]; + if ( g_pSelectedFaceWinding->points[i][3] > g_2DView.m_Maxs[0] ) + g_2DView.m_Maxs[0] = g_pSelectedFaceWinding->points[i][3]; + if ( g_pSelectedFaceWinding->points[i][4] < g_2DView.m_Mins[1] ) + g_2DView.m_Mins[1] = g_pSelectedFaceWinding->points[i][4]; + if ( g_pSelectedFaceWinding->points[i][4] > g_2DView.m_Maxs[1] ) + g_2DView.m_Maxs[1] = g_pSelectedFaceWinding->points[i][4]; + } + // NOTE: FitView will read and init TexSize + FitView( hwndDlg, TexSize ); + // now init the work tables + g_NumPoints = g_pSelectedFaceWinding->numpoints; + for ( i=0; ipoints[i][3]; + g_WorkWinding.data[i][1] = g_pSelectedFaceWinding->points[i][4]; + } + g_ControlPointsBFace.Init( g_NumPoints, &g_WorkWinding, &g_2DView, TexSize, &g_SelectedFaceData, &g_QglTable ); + // init snap-to-grid + float fTexStep[2]; + fTexStep[0] = 1.0f / float(TexSize[0]); + fTexStep[1] = 1.0f / float(TexSize[1]); + g_2DView.SetGrid( fTexStep[0], fTexStep[1] ); + g_pManager = &g_ControlPointsBFace; + // prepare the "Cancel" data + memcpy( &g_CancelFaceData, &g_SelectedFaceData, sizeof(_QERFaceData) ); + // we are done + g_bTexViewReady = true; + } + else if ( g_SurfaceTable.m_pfnAnyPatchesSelected()) + { + g_pPatch = g_SurfaceTable.m_pfnGetSelectedPatch(); + g_bPatch = true; + int i,j; + // compute BBox for all patch points + g_2DView.m_Mins[0] = +9999.0f; g_2DView.m_Mins[1] = +9999.0f; + g_2DView.m_Maxs[0] = -9999.0f; g_2DView.m_Maxs[1] = -9999.0f; + for ( i=0; iwidth; i++ ) + { + for ( j=0; jheight; j++ ) + { + if ( g_pPatch->ctrl[i][j].st[0] < g_2DView.m_Mins[0] ) + g_2DView.m_Mins[0] = g_pPatch->ctrl[i][j].st[0]; + if ( g_pPatch->ctrl[i][j].st[0] > g_2DView.m_Maxs[0] ) + g_2DView.m_Maxs[0] = g_pPatch->ctrl[i][j].st[0]; + if ( g_pPatch->ctrl[i][j].st[1] < g_2DView.m_Mins[1] ) + g_2DView.m_Mins[1] = g_pPatch->ctrl[i][j].st[1]; + if ( g_pPatch->ctrl[i][j].st[1] > g_2DView.m_Maxs[1] ) + g_2DView.m_Maxs[1] = g_pPatch->ctrl[i][j].st[1]; + } + } + FitView( hwndDlg, TexSize); + // init the work tables + g_WorkPatch = *g_pPatch; + g_ControlPointsPatch.Init( &g_WorkPatch, &g_2DView, &g_QglTable, g_pPatch ); + // init snap-to-grid + float fTexStep[2]; + fTexStep[0] = 1.0f / float(TexSize[0]); + fTexStep[1] = 1.0f / float(TexSize[1]); + g_2DView.SetGrid( fTexStep[0], fTexStep[1] ); + g_pManager = &g_ControlPointsPatch; + // prepare the "cancel" data + g_CancelPatch = *g_pPatch; + // we are done + g_bTexViewReady = true; + } +} + +void Textool_Validate() +{ + // validate current situation into the main view + g_pManager->Commit( ); + // for a brush face we have an aditionnal step + if (!g_bPatch) + { + // tell Radiant to update (will also send update windows messages ) + g_SelectedFaceTable.m_pfnSetFaceInfo( 0, &g_SelectedFaceData ); + } + else + { + // ask to rebuild the patch display data + g_pPatch->bDirty = true; + // send a repaint to the camera window as well + g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA ); + } + // we'll need to update after that as well: + g_bTexViewReady = false; + // send a repaint message + g_pToolWnd->Redraw (); +} + +void Textool_Cancel() +{ + if (!g_bPatch) + { + // tell Radiant to update (will also send update windows messages ) + g_SelectedFaceTable.m_pfnSetFaceInfo( 0, &g_CancelFaceData ); + } + else + { + *g_pPatch = g_CancelPatch; + g_pPatch->bDirty = true; + g_FuncTable.m_pfnSysUpdateWindows( W_CAMERA ); + } + // do not call destroy, decref it + g_pToolWnd->DecRef(); + g_pToolWnd = NULL; +} + +static void DoExpose () +{ + int i,j; + + g_2DView.PreparePaint(); + g_QglTable.m_pfn_qglColor3f(1, 1, 1); + // draw the texture background + g_QglTable.m_pfn_qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + if (!g_bPatch) + { + g_QglTable.m_pfn_qglBindTexture( GL_TEXTURE_2D, g_SelectedFaceTable.m_pfnGetTextureNumber(0) ); + } + else + { + g_QglTable.m_pfn_qglBindTexture( GL_TEXTURE_2D, g_pPatch->d_texture->texture_number ); + } + + g_QglTable.m_pfn_qglEnable( GL_TEXTURE_2D ); + g_QglTable.m_pfn_qglBegin( GL_QUADS ); + g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Mins[0], g_2DView.m_Mins[1] ); + g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Mins[0], g_2DView.m_Mins[1] ); + g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Maxs[0], g_2DView.m_Mins[1] ); + g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Maxs[0], g_2DView.m_Mins[1] ); + g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Maxs[0], g_2DView.m_Maxs[1] ); + g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Maxs[0], g_2DView.m_Maxs[1] ); + g_QglTable.m_pfn_qglTexCoord2f( g_2DView.m_Mins[0], g_2DView.m_Maxs[1] ); + g_QglTable.m_pfn_qglVertex2f( g_2DView.m_Mins[0], g_2DView.m_Maxs[1] ); + g_QglTable.m_pfn_qglEnd(); + g_QglTable.m_pfn_qglDisable( GL_TEXTURE_2D ); + + if (!g_bPatch) + { + g_QglTable.m_pfn_qglBegin( GL_LINE_LOOP ); + for ( i=0; iwidth; i++ ) + for ( j=0; jheight; j++ ) + { + if ( i < g_pPatch->width-1 ) + { + g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i][j].st[0], g_WorkPatch.ctrl[i][j].st[1] ); + g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i+1][j].st[0], g_WorkPatch.ctrl[i+1][j].st[1] ); + } + + if ( j < g_pPatch->height-1 ) + { + g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i][j].st[0], g_WorkPatch.ctrl[i][j].st[1] ); + g_QglTable.m_pfn_qglVertex2f( g_WorkPatch.ctrl[i][j+1].st[0], g_WorkPatch.ctrl[i][j+1].st[1] ); + } + } + g_QglTable.m_pfn_qglEnd(); + } + + // let the control points manager render + g_pManager->Render( ); +} + +static bool CanProcess () +{ + if (!g_bTexViewReady && !g_bClosing) + { + InitTexView (g_pToolWnd); + + if (!g_bTexViewReady) + { + g_bClosing = true; + DoMessageBox ("You must have brush primitives activated in your project settings and\n" + "have a patch or a single face selected to use the TexTool plugin.\n" + "See plugins/TexToolHelp for documentation.", "TexTool plugin", MB_ICONERROR | MB_OK); + // decref, this will destroy + g_pToolWnd->DecRef(); + g_pToolWnd = NULL; + return 0; + } + else + g_bClosing = false; + } + else if (!g_bTexViewReady && g_bClosing) + { + return 0; + } + + return 1; +} + +#if 0 +static void button_press (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + if (CanProcess ()) + { + switch (event->button) + { + case 1: + g_pManager->OnLButtonDown (event->x, event->y); break; + case 3: + g_2DView.OnRButtonDown (event->x, event->y); break; + } + } +} + +static void button_release (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + if (CanProcess ()) + { + switch (event->button) + { + case 1: + g_pManager->OnLButtonUp (event->x, event->y); break; + case 3: + g_2DView.OnRButtonUp (event->x, event->y); break; + } + } +} + +static void motion (GtkWidget *widget, GdkEventMotion *event, gpointer data) +{ + if (CanProcess ()) + { + if (g_2DView.OnMouseMove (event->x, event->y)) + return; + + if (g_pManager->OnMouseMove (event->x, event->y)) + return; + } +} + +static gint expose (GtkWidget *widget, GdkEventExpose *event, gpointer data) +{ + if (event->count > 0) + return TRUE; + + if (!CanProcess ()) + return TRUE; + + if (g_bTexViewReady) + { + g_2DView.m_rect.bottom = widget->allocation.height; + g_2DView.m_rect.right = widget->allocation.width; + + if (!g_QglTable.m_pfn_glwidget_make_current (g_pToolWidget)) + { + Sys_Printf("TexTool: glMakeCurrent failed\n"); + return TRUE; + } + + DoExpose (); + + g_QglTable.m_pfn_glwidget_swap_buffers (g_pToolWidget); + } + + return TRUE; +} + +static gint keypress (GtkWidget* widget, GdkEventKey* event, gpointer data) +{ + unsigned int code = gdk_keyval_to_upper(event->keyval); + + if (code == GDK_Escape) + { + gtk_widget_destroy (g_pToolWnd); + g_pToolWnd = NULL; + return TRUE; + } + + if (CanProcess ()) + { + if (g_2DView.OnKeyDown (code)) + return FALSE; + + if (code == GDK_Return) + { + Textool_Validate(); + return FALSE; + } + } + + return TRUE; +} + +static gint close (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + gtk_widget_destroy (widget); + g_pToolWnd = NULL; + + return TRUE; +} + +static GtkWidget* CreateOpenGLWidget () +{ + g_pToolWidget = g_QglTable.m_pfn_glwidget_new (FALSE, g_QglTable.m_pfn_GetQeglobalsGLWidget ()); + + gtk_widget_set_events (g_pToolWidget, GDK_DESTROY | GDK_EXPOSURE_MASK | GDK_KEY_PRESS_MASK | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK); + + // Connect signal handlers + gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "expose_event", GTK_SIGNAL_FUNC (expose), NULL); + gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "motion_notify_event", + GTK_SIGNAL_FUNC (motion), NULL); + gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "button_press_event", + GTK_SIGNAL_FUNC (button_press), NULL); + gtk_signal_connect (GTK_OBJECT (g_pToolWidget), "button_release_event", + GTK_SIGNAL_FUNC (button_release), NULL); + + gtk_signal_connect (GTK_OBJECT (g_pToolWnd), "delete_event", GTK_SIGNAL_FUNC (close), NULL); + gtk_signal_connect (GTK_OBJECT (g_pToolWnd), "key_press_event", + GTK_SIGNAL_FUNC (keypress), NULL); + + return g_pToolWidget; +} +#endif + +#if 0 +static void DoPaint () +{ + if (!CanProcess ()) + return; + + if (g_bTexViewReady) + { + g_2DView.m_rect.bottom = g_pToolWnd->getHeight(); + g_2DView.m_rect.right = g_pToolWnd->getWidth(); + + // set GL_PROJECTION + g_2DView.PreparePaint(); + // render the objects + // the master is not rendered the same way, draw over a unified texture background + g_2DView.TextureBackground(g_DrawObjects[0].pObject->getTextureNumber()); + if (g_nDrawObjects >= 1) + { + int i; + for (i=1;iPrepareModelView(g_DrawObjects[i].pTopo); + g_DrawObjects[i].pObject->RenderAuxiliary(); + } + } + // draw the polygon outline and control points + g_DrawObjects[0].pObject->PrepareModelView(NULL); + g_DrawObjects[0].pObject->RenderUI(); + } +} +#endif + +bool CWindowListener::OnLButtonDown(guint32 nFlags, double x, double y) +{ + if (CanProcess()) + { + g_pManager->OnLButtonDown((int)x, (int)y); + return true; + } + return false; +} + +bool CWindowListener::OnRButtonDown(guint32 nFlags, double x, double y) +{ + if (CanProcess()) + { + g_2DView.OnRButtonDown ((int)x, (int)y); + return true; + } + return false; +} + +bool CWindowListener::OnLButtonUp(guint32 nFlags, double x, double y) +{ + if (CanProcess()) + { + g_pManager->OnLButtonUp((int)x, (int)y); + return true; + } + return false; +} + +bool CWindowListener::OnRButtonUp(guint32 nFlags, double x, double y) +{ + if (CanProcess()) + { + g_2DView.OnRButtonUp ((int)x, (int)y); + return true; + } + return false; +} + +bool CWindowListener::OnMouseMove(guint32 nFlags, double x, double y) +{ + if (CanProcess ()) + { + if (g_2DView.OnMouseMove ((int)x, (int)y)) + return true; + + g_pManager->OnMouseMove((int)x, (int)y); + return true; + } + return false; +} + +// the widget is closing +void CWindowListener::Close() +{ + g_pToolWnd = NULL; +} + +bool CWindowListener::Paint() +{ + if (!CanProcess ()) + return false; + + if (g_bTexViewReady) + DoExpose(); + + return true; +} + +bool CWindowListener::OnKeyPressed(char *s) +{ + if (!strcmp(s,"Escape")) + { + Textool_Cancel(); + return TRUE; + } + if (CanProcess ()) + { + if (g_2DView.OnKeyDown (s)) + return TRUE; + + if (!strcmp(s,"Return")) + { + Textool_Validate(); + return TRUE; + } + } + return FALSE; +} + +extern "C" void QERPlug_Dispatch(const char* p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) +{ + #if 0 + // if it's the first call, perhaps we need some additional init steps + if (!g_bQglInitDone) + { + g_QglTable.m_nSize = sizeof(_QERQglTable); + if ( g_FuncTable.m_pfnRequestInterface( QERQglTable_GUID, static_cast(&g_QglTable) ) ) + { + g_bQglInitDone = true; + } + else + { + Sys_Printf("TexTool plugin: _QERQglTable interface request failed\n"); + return; + } + } + + if (!g_bSelectedFaceInitDone) + { + g_SelectedFaceTable.m_nSize = sizeof(_QERSelectedFaceTable); + if (g_FuncTable.m_pfnRequestInterface (QERSelectedFaceTable_GUID, + static_cast(&g_SelectedFaceTable))) + { + g_bSelectedFaceInitDone = true; + } + else + { + Sys_Printf("TexTool plugin: _QERSelectedFaceTable interface request failed\n"); + return; + } + } + + if (!g_bSurfaceTableInitDone) + { + g_SurfaceTable.m_nSize = sizeof(_QERAppSurfaceTable); + if ( g_FuncTable.m_pfnRequestInterface( QERAppSurfaceTable_GUID, static_cast(&g_SurfaceTable) ) ) + { + g_bSurfaceTableInitDone = true; + } + else + { + Sys_Printf("TexTool plugin: _QERAppSurfaceTable interface request failed\n"); + return; + } + } + + if (!g_bUITable) + { + g_UITable.m_nSize = sizeof(_QERUITable); + if ( g_FuncTable.m_pfnRequestInterface( QERUI_GUID, static_cast(&g_UITable) ) ) + { + g_bUITable = true; + } + else + { + Sys_Printf("TexTool plugin: _QERUITable interface request failed\n"); + return; + } + } + #endif + + if (!strcmp(p, "About...")) + { + DoMessageBox (PLUGIN_ABOUT, "About ...", MB_OK ); + } + else if (!strcmp(p, "Go...")) + { + if (!g_pToolWnd) + { + g_pToolWnd = g_UITable.m_pfnCreateGLWindow(); + g_pToolWnd->setSizeParm(300,300); + g_pToolWnd->setName("TexTool"); + // g_Listener is a static class, we need to bump the refCount to avoid premature release problems + g_Listen.IncRef(); + // setListener will incRef on the listener too + g_pToolWnd->setListener(&g_Listen); + if (!g_pToolWnd->Show()) + { + DoMessageBox ("Error creating texture tools window!", "TexTool plugin", MB_ICONERROR | MB_OK); + return; + } + } + + g_bTexViewReady = false; + g_bClosing = false; + } + else if (!strcmp(p, "Help...")) + { + if (!g_bHelp) + DoMessageBox ("Select a brush face (ctrl+shift+left mouse) or a patch, and hit Go...\n" + "See tutorials for more", "TexTool plugin", MB_OK ); + else + DoMessageBox ("Are you kidding me ?", "TexTool plugin", MB_OK ); + g_bHelp = true; + } +} + +// ============================================================================= +// SYNAPSE + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientTexTool 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(PLUGIN_MAJOR, "textool", 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); + g_SynapseClient.AddAPI(SELECTEDFACE_MAJOR, NULL, sizeof(g_SelectedFaceTable), SYN_REQUIRE, &g_SelectedFaceTable); + + return &g_SynapseClient; +} + +bool CSynapseClientTexTool::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; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientTexTool::GetInfo() +{ + return "Texture Tools plugin built " __DATE__ " " RADIANT_VERSION; +} diff --git a/plugins/vfspak/vfs.cpp b/plugins/vfspak/vfs.cpp index 09484c50..5b5a0299 100644 --- a/plugins/vfspak/vfs.cpp +++ b/plugins/vfspak/vfs.cpp @@ -1,803 +1,803 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -// -// Rules: -// -// - Directories should be searched in the following order: ~/.q3a/baseq3, -// install dir (/usr/local/games/quake3/baseq3) and cd_path (/mnt/cdrom/baseq3). -// -// - Pak files are searched first inside the directories. -// - Case insensitive. -// - Unix-style slashes (/) -// -// Leonardo Zide (leo@lokigames.com) -// - -#include -#include -#if defined __linux__ || defined (__APPLE__) - #include - #include - #define WINAPI -#else - #include - #include - #define R_OK 04 - #define S_ISDIR(mode) (mode & _S_IFDIR) -#endif - -#include "str.h" -#include -#include -#include "vfs.h" -#include "vfspak.h" - -typedef struct -{ - char magic[4]; // Name of the new WAD format ("PACK") - gint32 diroffset; // Position of WAD directory from start of file - gint32 dirsize; // Number of entries * 0x40 (64 char) -} pakheader_t; - -typedef struct -{ - char filename[0x38]; // Name of the file, Unix style, with extension, 50 chars, padded with '\0'. - gint32 offset; // Position of the entry in PACK file - gint32 size; // Size of the entry in PACK file -} pakentry_t; - -typedef struct -{ - char* name; - pakentry_t entry; - FILE *pak; -} VFS_PAKFILE; - -// ============================================================================= -// Global variables - -static GSList* g_unzFiles; -static GSList* g_pakFiles; -static char g_strDirs[VFS_MAXDIRS][PATH_MAX]; -static int g_numDirs; -static bool g_bUsePak = true; - -// ============================================================================= -// Static functions - -static void vfsAddSlash (char *str) -{ - int n = strlen (str); - if (n > 0) - { - if (str[n-1] != '\\' && str[n-1] != '/') - strcat (str, "/"); - } -} - -static void vfsFixDOSName (char *src) -{ - if (src == NULL) - return; - - while (*src) - { - if (*src == '\\') - *src = '/'; - src++; - } -} - -static void vfsInitPakFile (const char *filename) -{ - pakheader_t header; - FILE *f; - long i; - - f = fopen (filename, "rb"); - if (f == NULL) - return; - - // read header - fread (header.magic, 1, 4, f); - fread (&header.diroffset, 1, 4, f); - fread (&header.dirsize, 1, 4, f); - - // fix endianess - header.diroffset = GINT32_FROM_LE (header.diroffset); - header.dirsize = GINT32_FROM_LE (header.dirsize); - - // check that the magic header - if (strncmp (header.magic, "PACK", 4)) - { - fclose (f); - return; - } - - g_FuncTable.m_pfnSysPrintf(" pak file: %s\n", filename); - - g_unzFiles = g_slist_append (g_unzFiles, f); - fseek (f, header.diroffset, SEEK_SET); - - for (i = 0; i < (long)(header.dirsize/sizeof (pakentry_t)); i++) - { - VFS_PAKFILE* file; - - file = (VFS_PAKFILE*)g_malloc (sizeof (VFS_PAKFILE)); - g_pakFiles = g_slist_append (g_pakFiles, file); - - fread (file->entry.filename, 1, sizeof (file->entry.filename), f); - fread (&file->entry.offset, 1, sizeof (file->entry.offset), f); - fread (&file->entry.size, 1, sizeof (file->entry.size), f); - file->pak = f; - - // fix endianess - file->entry.offset = GINT32_FROM_LE (file->entry.offset); - file->entry.size = GINT32_FROM_LE (file->entry.size); - - // fix filename - vfsFixDOSName (file->entry.filename); - g_strdown (file->entry.filename); - //g_FuncTable.m_pfnSysPrintf("vfs file from pak: %s\n", file->entry.filename); - } -} - -static GSList* vfsGetListInternal (const char *dir, const char *ext, bool directories) -{ - GSList *lst, *lst_aux, *files = NULL; - char dirname[NAME_MAX], extension[NAME_MAX], filename[NAME_MAX]; - int dirlen; - char *ptr; - //struct dirent *dirlist; - char *dirlist; - struct stat st; - GDir *diskdir; - int i; - - dirname[0] = '\0'; - if (dir != NULL) - { - strcat (dirname, dir); - g_strdown (dirname); - vfsFixDOSName (dirname); - vfsAddSlash (dirname); - Sys_Printf("vfs dirname_1: %s\n", dirname); - } - //else - // dirname[0] = '\0'; - dirlen = strlen (dirname); - - if (ext != NULL) - strcpy (extension, ext); - else - extension[0] = '\0'; - g_strdown (extension); - - for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) - { - VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; - gboolean found = FALSE; - ptr = file->entry.filename; - - // check that the file name begins with dirname - for (i = 0; (*ptr && i < dirlen); i++, ptr++) - if (*ptr != dirname[i]) - break; - - if (i != dirlen) - continue; - - if (directories) - { - char *sep = strchr (ptr, '/'); - if (sep == NULL) - continue; - - i = sep-ptr; - - // check for duplicates - for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) - if (strncmp ((char*)lst_aux->data, ptr, i) == 0) - { - found = TRUE; - break; - } - - if (!found) - { - char *name = g_strndup (ptr, i+1); - name[i] = '\0'; - files = g_slist_append (files, name); - } - } - else - { - // check extension - if ((ext != NULL) && (strstr (ptr, extension) == NULL)) - continue; - - // check for duplicates - for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) - if (strcmp ((char*)lst_aux->data, ptr) == 0) - { - found = TRUE; - break; - } - - if (!found) - files = g_slist_append (files, g_strdup (ptr)); - } - } - - for (i = 0; i < g_numDirs; i++) - { - strcpy (dirname, g_strDirs[i]); - strcat (dirname, dir); - g_strdown (dirname); - vfsFixDOSName (dirname); - vfsAddSlash (dirname); - - diskdir = g_dir_open (dirname, 0, NULL); - - if (diskdir != NULL) - { - while (1) - { - const char* name = g_dir_read_name(diskdir); - if(name == NULL) - break; - - if (directories && (name[0] == '.')) - continue; - - sprintf (filename, "%s%s", dirname, name); - stat (filename, &st); - Sys_Printf("vfs FileName: %s\n", filename); - - if ((S_ISDIR (st.st_mode) != 0) != directories) - continue; - - gboolean found = FALSE; - - dirlist = g_strdup(name); - - g_strdown (dirlist); - - char *ptr_ext = strrchr (dirlist, '.'); - if(ext == NULL - || (ext != NULL && ptr_ext != NULL && ptr_ext[0] != '\0' && strcmp (ptr_ext+1, extension) == 0)) - { - - // check for duplicates - for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) - if (strcmp ((char*)lst_aux->data, dirlist) == 0) - { - found = TRUE; - break; - } - - if (!found) - files = g_slist_append (files, g_strdup (dirlist)); - } - - g_free(dirlist); - } - g_dir_close (diskdir); - } - } - - return files; -} - -/*! -This behaves identically to -stricmp(a,b), except that ASCII chars -[\]^`_ come AFTER alphabet chars instead of before. This is because -it effectively converts all alphabet chars to uppercase before comparison, -while stricmp converts them to lowercase. -*/ -//!\todo Analyse the code in rtcw/q3 to see how it behaves. -static int vfsPakSort (const void *a, const void *b) -{ - char *s1, *s2; - int c1, c2; - - s1 = (char*)a; - s2 = (char*)b; - - do { - c1 = *s1++; - c2 = *s2++; - - if (c1 >= 'a' && c1 <= 'z') - { - c1 -= ('a' - 'A'); - } - if (c2 >= 'a' && c2 <= 'z') - { - c2 -= ('a' - 'A'); - } - - if ( c1 == '\\' || c1 == ':' ) - { - c1 = '/'; - } - if ( c2 == '\\' || c2 == ':' ) - { - c2 = '/'; - } - - // Arnout: note - sort pakfiles in reverse order. This ensures that - // later pakfiles override earlier ones. This because the vfs module - // returns a filehandle to the first file it can find (while it should - // return the filehandle to the file in the most overriding pakfile, the - // last one in the list that is). - if (c1 < c2) - { - //return -1; // strings not equal - return 1; // strings not equal - } - if (c1 > c2) - { - //return 1; - return -1; - } - } while (c1); - - return 0; // strings are equal -} - -// ============================================================================= -// Global functions - -void vfsInitDirectory (const char *path) -{ - char filename[PATH_MAX]; - //struct dirent *direntry; - GDir *dir; - //GSList *dirlistptr; - GSList *dirlist = NULL; - - if (g_numDirs == (VFS_MAXDIRS-1)) - return; - - strcpy (g_strDirs[g_numDirs], path); - vfsFixDOSName (g_strDirs[g_numDirs]); - vfsAddSlash (g_strDirs[g_numDirs]); - g_numDirs++; - - if (g_bUsePak) - { - dir = g_dir_open (path, 0, NULL); - if (dir != NULL) - { - g_FuncTable.m_pfnSysPrintf("vfs directory: %s\n", path); - - for(;;) - { - const char* name = g_dir_read_name(dir); - if(name == NULL) - break; - - char *ext = strrchr (name, '.'); - if ((ext == NULL) || (strcasecmp (ext, ".pak") != 0)) - continue; - - char* direntry = g_strdup(name); - dirlist = g_slist_append (dirlist, direntry); - } - - g_dir_close (dir); - - - // sort them - dirlist = g_slist_sort (dirlist, vfsPakSort); - - // add the entries to the vfs and free the list - while (dirlist) - { - GSList *cur = dirlist; - char* name = (char*)cur->data; - - sprintf (filename, "%s/%s", path, name); - vfsInitPakFile (filename); - - g_free (name); - dirlist = g_slist_remove (cur, name); - } - } else - g_FuncTable.m_pfnSysFPrintf(SYS_WRN, "vfs directory not found: %s\n", path); - - } -} - - -// frees all memory that we allocated -void vfsShutdown () -{ - while (g_unzFiles) - { - fclose ((FILE*)g_unzFiles->data); - g_unzFiles = g_slist_remove (g_unzFiles, g_unzFiles->data); - } - - while (g_pakFiles) - { - g_free (g_pakFiles->data); - g_pakFiles = g_slist_remove (g_pakFiles, g_pakFiles->data); - } -} - -GSList* vfsGetFileList (const char *dir, const char *ext) -{ - return vfsGetListInternal (dir, ext, false); -} - -GSList* vfsGetDirList (const char *dir) -{ - return vfsGetListInternal (dir, NULL, true); -} - -void vfsClearFileDirList (GSList **lst) -{ - while (*lst) - { - g_free ((*lst)->data); - *lst = g_slist_remove (*lst, (*lst)->data); - } -} - -// return the number of files that match -int vfsGetFileCount (const char *filename, int flag) -{ - int i, count = 0; - char fixed[NAME_MAX], tmp[NAME_MAX]; - GSList *lst; - - strcpy (fixed, filename); - vfsFixDOSName (fixed); - g_strdown (fixed); - - for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) - { - VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; - - if (strcmp (file->entry.filename, fixed) == 0) - count++; - } - - for (i = 0; i < g_numDirs; i++) - { - strcpy (tmp, g_strDirs[i]); - strcat (tmp, fixed); - if (access (tmp, R_OK) == 0) - count++; - } - - return count; -} - -// NOTE: when loading a file, you have to allocate one extra byte and set it to \0 -int vfsLoadFile (const char *filename, void **bufferptr, int index) -{ - int i, count = 0; - char tmp[NAME_MAX], fixed[NAME_MAX]; - GSList *lst; - - *bufferptr = NULL; - strcpy (fixed, filename); - vfsFixDOSName (fixed); - g_strdown (fixed); - - for (i = 0; i < g_numDirs; i++) - { - strcpy (tmp, g_strDirs[i]); - strcat (tmp, filename); - if (access (tmp, R_OK) == 0) - { - if (count == index) - { - long len; - FILE *f; - - f = fopen (tmp, "rb"); - if (f == NULL) - return -1; - - fseek (f, 0, SEEK_END); - len = ftell (f); - rewind (f); - - *bufferptr = malloc (len+1); - if (*bufferptr == NULL) - return -1; - - fread (*bufferptr, 1, len, f); - fclose (f); - - // we need to end the buffer with a 0 - ((char*) (*bufferptr))[len] = 0; - - return len; - } - - count++; - } - } - - for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) - { - VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; - - if (strcmp (file->entry.filename, fixed) != 0) - continue; - - if (count == index) - { - fseek (file->pak, file->entry.offset, SEEK_SET); - - *bufferptr = malloc (file->entry.size+1); - // we need to end the buffer with a 0 - ((char*) (*bufferptr))[file->entry.size] = 0; - - return fread (*bufferptr, 1, file->entry.size, file->pak); - } - - count++; - } - - return -1; -} - -void vfsFreeFile (void *p) -{ - g_free(p); -} - -// open a full path file -int vfsLoadFullPathFile (const char *filename, void **bufferptr) -{ - FILE *f; - long len; - - f = fopen (filename, "rb"); - if (f == NULL) - return -1; - - fseek (f, 0, SEEK_END); - len = ftell (f); - rewind (f); - - *bufferptr = g_malloc (len+1); - if (*bufferptr == NULL) - return -1; - - fread (*bufferptr, 1, len, f); - fclose (f); - - // we need to end the buffer with a 0 - ((char*) (*bufferptr))[len] = 0; - - return len; -} - -void vfsCleanFileName(char *in) -{ - strlwr(in); - vfsFixDOSName(in); - int n = strlen(in); - if (in[n-1] == '/') - in[n-1] = '\0'; -} - -const char* vfsBasePromptPath() -{ -#ifdef _WIN32 - static char* path = "C:"; -#else - static char* path = "/"; -#endif - return path; -} - -/*! -\param shorten will try to match against the short version -http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=144 -recent switch back to short path names in project settings has broken some stuff -with shorten == true, we will convert in to short version before looking for root -FIXME WAAA .. the stuff below is much more simple on linux .. add appropriate #ifdef -*/ -char* vfsExtractRelativePath_short(const char *in, bool shorten) -{ - int i; - char l_in[PATH_MAX]; - char check[PATH_MAX]; - static char out[PATH_MAX]; - out[0] = 0; - -#ifdef DBG_RLTPATH - Sys_Printf("vfsExtractRelativePath: %s\n", in); -#endif - -#ifdef _WIN32 - if (shorten) - { - // make it short - if (GetShortPathName(in, l_in, PATH_MAX) == 0) - { -#ifdef DBG_RLTPATH - Sys_Printf("GetShortPathName failed\n"); -#endif - return NULL; - } - } - else - { - strcpy(l_in,in); - } - vfsCleanFileName(l_in); -#else - strcpy(l_in, in); - vfsCleanFileName(l_in); -#endif // ifdef WIN32 - - -#ifdef DBG_RLTPATH - Sys_Printf("cleaned path: %s\n", l_in); -#endif - - for (i = 0; i < g_numDirs; i++) - { - strcpy(check,g_strDirs[i]); - vfsCleanFileName(check); -#ifdef DBG_RLTPATH - Sys_Printf("Matching against %s\n", check); -#endif - - // try to find a match - if (strstr(l_in, check)) - { - strcpy(out,l_in+strlen(check)+1); - break; - } - - } - if (out[0]!=0) - { -#ifdef DBG_RLTPATH - Sys_Printf("vfsExtractRelativePath: success\n"); -#endif - return out; - } -#ifdef DBG_RLTPATH - Sys_Printf("vfsExtractRelativePath: failed\n"); -#endif - return NULL; -} - -// HYDRA: this now searches VFS/PAK files in addition to the filesystem -// if FLAG is unspecified then ONLY dirs are searched. -// PAK's are searched before DIRs to mimic engine behaviour -// index is ignored when searching PAK files. -// see ifilesystem.h -char* vfsGetFullPath(const char *in, int index, int flag) -{ - int count = 0; - static char out[PATH_MAX]; - char tmp[NAME_MAX]; - int i; - - if (flag & VFS_SEARCH_PAK) - { - char fixed[NAME_MAX]; - GSList *lst; - - strcpy (fixed, in); - vfsFixDOSName (fixed); - g_strdown (fixed); - - for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) - { - VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; - - char *ptr,*lastptr; - lastptr = file->name; - - while (ptr = strchr(lastptr,'/')) - lastptr = ptr+1; - - if (strcmp (lastptr, fixed) == 0) - { - strncpy(out,file->name,PATH_MAX); - return out; - } - } - - } - - if (!flag || (flag & VFS_SEARCH_DIR)) - { - for (i = 0; i < g_numDirs; i++) - { - strcpy (tmp, g_strDirs[i]); - strcat (tmp, in); - if (access (tmp, R_OK) == 0) - { - if (count == index) - { - strcpy (out, tmp); - return out; - } - count++; - } - } - } - return NULL; -} - -// FIXME TTimo: this and the above should be merged at some point -char* vfsExtractRelativePath(const char *in) -{ - static char out[PATH_MAX]; - unsigned int i, count; - char *chunk, *backup = NULL; // those point to out stuff - char *ret = vfsExtractRelativePath_short(in, false); - if (!ret) - { -#ifdef DBG_RLTPATH - Sys_Printf("trying with a short version\n"); -#endif - ret = vfsExtractRelativePath_short(in, true); - if (ret) - { - // ok, but we have a relative short version now - // hack the long relative version out of here - count = 0; - for(i=0;i +#include +#if defined __linux__ || defined (__APPLE__) + #include + #include + #define WINAPI +#else + #include + #include + #define R_OK 04 + #define S_ISDIR(mode) (mode & _S_IFDIR) +#endif + +#include "str.h" +#include +#include +#include "vfs.h" +#include "vfspak.h" + +typedef struct +{ + char magic[4]; // Name of the new WAD format ("PACK") + gint32 diroffset; // Position of WAD directory from start of file + gint32 dirsize; // Number of entries * 0x40 (64 char) +} pakheader_t; + +typedef struct +{ + char filename[0x38]; // Name of the file, Unix style, with extension, 50 chars, padded with '\0'. + gint32 offset; // Position of the entry in PACK file + gint32 size; // Size of the entry in PACK file +} pakentry_t; + +typedef struct +{ + char* name; + pakentry_t entry; + FILE *pak; +} VFS_PAKFILE; + +// ============================================================================= +// Global variables + +static GSList* g_unzFiles; +static GSList* g_pakFiles; +static char g_strDirs[VFS_MAXDIRS][PATH_MAX]; +static int g_numDirs; +static bool g_bUsePak = true; + +// ============================================================================= +// Static functions + +static void vfsAddSlash (char *str) +{ + int n = strlen (str); + if (n > 0) + { + if (str[n-1] != '\\' && str[n-1] != '/') + strcat (str, "/"); + } +} + +static void vfsFixDOSName (char *src) +{ + if (src == NULL) + return; + + while (*src) + { + if (*src == '\\') + *src = '/'; + src++; + } +} + +static void vfsInitPakFile (const char *filename) +{ + pakheader_t header; + FILE *f; + long i; + + f = fopen (filename, "rb"); + if (f == NULL) + return; + + // read header + fread (header.magic, 1, 4, f); + fread (&header.diroffset, 1, 4, f); + fread (&header.dirsize, 1, 4, f); + + // fix endianess + header.diroffset = GINT32_FROM_LE (header.diroffset); + header.dirsize = GINT32_FROM_LE (header.dirsize); + + // check that the magic header + if (strncmp (header.magic, "PACK", 4)) + { + fclose (f); + return; + } + + g_FuncTable.m_pfnSysPrintf(" pak file: %s\n", filename); + + g_unzFiles = g_slist_append (g_unzFiles, f); + fseek (f, header.diroffset, SEEK_SET); + + for (i = 0; i < (long)(header.dirsize/sizeof (pakentry_t)); i++) + { + VFS_PAKFILE* file; + + file = (VFS_PAKFILE*)g_malloc (sizeof (VFS_PAKFILE)); + g_pakFiles = g_slist_append (g_pakFiles, file); + + fread (file->entry.filename, 1, sizeof (file->entry.filename), f); + fread (&file->entry.offset, 1, sizeof (file->entry.offset), f); + fread (&file->entry.size, 1, sizeof (file->entry.size), f); + file->pak = f; + + // fix endianess + file->entry.offset = GINT32_FROM_LE (file->entry.offset); + file->entry.size = GINT32_FROM_LE (file->entry.size); + + // fix filename + vfsFixDOSName (file->entry.filename); + g_strdown (file->entry.filename); + //g_FuncTable.m_pfnSysPrintf("vfs file from pak: %s\n", file->entry.filename); + } +} + +static GSList* vfsGetListInternal (const char *dir, const char *ext, bool directories) +{ + GSList *lst, *lst_aux, *files = NULL; + char dirname[NAME_MAX], extension[NAME_MAX], filename[NAME_MAX]; + int dirlen; + char *ptr; + //struct dirent *dirlist; + char *dirlist; + struct stat st; + GDir *diskdir; + int i; + + dirname[0] = '\0'; + if (dir != NULL) + { + strcat (dirname, dir); + g_strdown (dirname); + vfsFixDOSName (dirname); + vfsAddSlash (dirname); + Sys_Printf("vfs dirname_1: %s\n", dirname); + } + //else + // dirname[0] = '\0'; + dirlen = strlen (dirname); + + if (ext != NULL) + strcpy (extension, ext); + else + extension[0] = '\0'; + g_strdown (extension); + + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + gboolean found = FALSE; + ptr = file->entry.filename; + + // check that the file name begins with dirname + for (i = 0; (*ptr && i < dirlen); i++, ptr++) + if (*ptr != dirname[i]) + break; + + if (i != dirlen) + continue; + + if (directories) + { + char *sep = strchr (ptr, '/'); + if (sep == NULL) + continue; + + i = sep-ptr; + + // check for duplicates + for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) + if (strncmp ((char*)lst_aux->data, ptr, i) == 0) + { + found = TRUE; + break; + } + + if (!found) + { + char *name = g_strndup (ptr, i+1); + name[i] = '\0'; + files = g_slist_append (files, name); + } + } + else + { + // check extension + if ((ext != NULL) && (strstr (ptr, extension) == NULL)) + continue; + + // check for duplicates + for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) + if (strcmp ((char*)lst_aux->data, ptr) == 0) + { + found = TRUE; + break; + } + + if (!found) + files = g_slist_append (files, g_strdup (ptr)); + } + } + + for (i = 0; i < g_numDirs; i++) + { + strcpy (dirname, g_strDirs[i]); + strcat (dirname, dir); + g_strdown (dirname); + vfsFixDOSName (dirname); + vfsAddSlash (dirname); + + diskdir = g_dir_open (dirname, 0, NULL); + + if (diskdir != NULL) + { + while (1) + { + const char* name = g_dir_read_name(diskdir); + if(name == NULL) + break; + + if (directories && (name[0] == '.')) + continue; + + sprintf (filename, "%s%s", dirname, name); + stat (filename, &st); + Sys_Printf("vfs FileName: %s\n", filename); + + if ((S_ISDIR (st.st_mode) != 0) != directories) + continue; + + gboolean found = FALSE; + + dirlist = g_strdup(name); + + g_strdown (dirlist); + + char *ptr_ext = strrchr (dirlist, '.'); + if(ext == NULL + || (ext != NULL && ptr_ext != NULL && ptr_ext[0] != '\0' && strcmp (ptr_ext+1, extension) == 0)) + { + + // check for duplicates + for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) + if (strcmp ((char*)lst_aux->data, dirlist) == 0) + { + found = TRUE; + break; + } + + if (!found) + files = g_slist_append (files, g_strdup (dirlist)); + } + + g_free(dirlist); + } + g_dir_close (diskdir); + } + } + + return files; +} + +/*! +This behaves identically to -stricmp(a,b), except that ASCII chars +[\]^`_ come AFTER alphabet chars instead of before. This is because +it effectively converts all alphabet chars to uppercase before comparison, +while stricmp converts them to lowercase. +*/ +//!\todo Analyse the code in rtcw/q3 to see how it behaves. +static int vfsPakSort (const void *a, const void *b) +{ + char *s1, *s2; + int c1, c2; + + s1 = (char*)a; + s2 = (char*)b; + + do { + c1 = *s1++; + c2 = *s2++; + + if (c1 >= 'a' && c1 <= 'z') + { + c1 -= ('a' - 'A'); + } + if (c2 >= 'a' && c2 <= 'z') + { + c2 -= ('a' - 'A'); + } + + if ( c1 == '\\' || c1 == ':' ) + { + c1 = '/'; + } + if ( c2 == '\\' || c2 == ':' ) + { + c2 = '/'; + } + + // Arnout: note - sort pakfiles in reverse order. This ensures that + // later pakfiles override earlier ones. This because the vfs module + // returns a filehandle to the first file it can find (while it should + // return the filehandle to the file in the most overriding pakfile, the + // last one in the list that is). + if (c1 < c2) + { + //return -1; // strings not equal + return 1; // strings not equal + } + if (c1 > c2) + { + //return 1; + return -1; + } + } while (c1); + + return 0; // strings are equal +} + +// ============================================================================= +// Global functions + +void vfsInitDirectory (const char *path) +{ + char filename[PATH_MAX]; + //struct dirent *direntry; + GDir *dir; + //GSList *dirlistptr; + GSList *dirlist = NULL; + + if (g_numDirs == (VFS_MAXDIRS-1)) + return; + + strcpy (g_strDirs[g_numDirs], path); + vfsFixDOSName (g_strDirs[g_numDirs]); + vfsAddSlash (g_strDirs[g_numDirs]); + g_numDirs++; + + if (g_bUsePak) + { + dir = g_dir_open (path, 0, NULL); + if (dir != NULL) + { + g_FuncTable.m_pfnSysPrintf("vfs directory: %s\n", path); + + for(;;) + { + const char* name = g_dir_read_name(dir); + if(name == NULL) + break; + + char *ext = strrchr (name, '.'); + if ((ext == NULL) || (strcasecmp (ext, ".pak") != 0)) + continue; + + char* direntry = g_strdup(name); + dirlist = g_slist_append (dirlist, direntry); + } + + g_dir_close (dir); + + + // sort them + dirlist = g_slist_sort (dirlist, vfsPakSort); + + // add the entries to the vfs and free the list + while (dirlist) + { + GSList *cur = dirlist; + char* name = (char*)cur->data; + + sprintf (filename, "%s/%s", path, name); + vfsInitPakFile (filename); + + g_free (name); + dirlist = g_slist_remove (cur, name); + } + } else + g_FuncTable.m_pfnSysFPrintf(SYS_WRN, "vfs directory not found: %s\n", path); + + } +} + + +// frees all memory that we allocated +void vfsShutdown () +{ + while (g_unzFiles) + { + fclose ((FILE*)g_unzFiles->data); + g_unzFiles = g_slist_remove (g_unzFiles, g_unzFiles->data); + } + + while (g_pakFiles) + { + g_free (g_pakFiles->data); + g_pakFiles = g_slist_remove (g_pakFiles, g_pakFiles->data); + } +} + +GSList* vfsGetFileList (const char *dir, const char *ext) +{ + return vfsGetListInternal (dir, ext, false); +} + +GSList* vfsGetDirList (const char *dir) +{ + return vfsGetListInternal (dir, NULL, true); +} + +void vfsClearFileDirList (GSList **lst) +{ + while (*lst) + { + g_free ((*lst)->data); + *lst = g_slist_remove (*lst, (*lst)->data); + } +} + +// return the number of files that match +int vfsGetFileCount (const char *filename, int flag) +{ + int i, count = 0; + char fixed[NAME_MAX], tmp[NAME_MAX]; + GSList *lst; + + strcpy (fixed, filename); + vfsFixDOSName (fixed); + g_strdown (fixed); + + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + + if (strcmp (file->entry.filename, fixed) == 0) + count++; + } + + for (i = 0; i < g_numDirs; i++) + { + strcpy (tmp, g_strDirs[i]); + strcat (tmp, fixed); + if (access (tmp, R_OK) == 0) + count++; + } + + return count; +} + +// NOTE: when loading a file, you have to allocate one extra byte and set it to \0 +int vfsLoadFile (const char *filename, void **bufferptr, int index) +{ + int i, count = 0; + char tmp[NAME_MAX], fixed[NAME_MAX]; + GSList *lst; + + *bufferptr = NULL; + strcpy (fixed, filename); + vfsFixDOSName (fixed); + g_strdown (fixed); + + for (i = 0; i < g_numDirs; i++) + { + strcpy (tmp, g_strDirs[i]); + strcat (tmp, filename); + if (access (tmp, R_OK) == 0) + { + if (count == index) + { + long len; + FILE *f; + + f = fopen (tmp, "rb"); + if (f == NULL) + return -1; + + fseek (f, 0, SEEK_END); + len = ftell (f); + rewind (f); + + *bufferptr = malloc (len+1); + if (*bufferptr == NULL) + return -1; + + fread (*bufferptr, 1, len, f); + fclose (f); + + // we need to end the buffer with a 0 + ((char*) (*bufferptr))[len] = 0; + + return len; + } + + count++; + } + } + + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + + if (strcmp (file->entry.filename, fixed) != 0) + continue; + + if (count == index) + { + fseek (file->pak, file->entry.offset, SEEK_SET); + + *bufferptr = malloc (file->entry.size+1); + // we need to end the buffer with a 0 + ((char*) (*bufferptr))[file->entry.size] = 0; + + return fread (*bufferptr, 1, file->entry.size, file->pak); + } + + count++; + } + + return -1; +} + +void vfsFreeFile (void *p) +{ + g_free(p); +} + +// open a full path file +int vfsLoadFullPathFile (const char *filename, void **bufferptr) +{ + FILE *f; + long len; + + f = fopen (filename, "rb"); + if (f == NULL) + return -1; + + fseek (f, 0, SEEK_END); + len = ftell (f); + rewind (f); + + *bufferptr = g_malloc (len+1); + if (*bufferptr == NULL) + return -1; + + fread (*bufferptr, 1, len, f); + fclose (f); + + // we need to end the buffer with a 0 + ((char*) (*bufferptr))[len] = 0; + + return len; +} + +void vfsCleanFileName(char *in) +{ + strlwr(in); + vfsFixDOSName(in); + int n = strlen(in); + if (in[n-1] == '/') + in[n-1] = '\0'; +} + +const char* vfsBasePromptPath() +{ +#ifdef _WIN32 + static char* path = "C:"; +#else + static char* path = "/"; +#endif + return path; +} + +/*! +\param shorten will try to match against the short version +http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=144 +recent switch back to short path names in project settings has broken some stuff +with shorten == true, we will convert in to short version before looking for root +FIXME WAAA .. the stuff below is much more simple on linux .. add appropriate #ifdef +*/ +char* vfsExtractRelativePath_short(const char *in, bool shorten) +{ + int i; + char l_in[PATH_MAX]; + char check[PATH_MAX]; + static char out[PATH_MAX]; + out[0] = 0; + +#ifdef DBG_RLTPATH + Sys_Printf("vfsExtractRelativePath: %s\n", in); +#endif + +#ifdef _WIN32 + if (shorten) + { + // make it short + if (GetShortPathName(in, l_in, PATH_MAX) == 0) + { +#ifdef DBG_RLTPATH + Sys_Printf("GetShortPathName failed\n"); +#endif + return NULL; + } + } + else + { + strcpy(l_in,in); + } + vfsCleanFileName(l_in); +#else + strcpy(l_in, in); + vfsCleanFileName(l_in); +#endif // ifdef WIN32 + + +#ifdef DBG_RLTPATH + Sys_Printf("cleaned path: %s\n", l_in); +#endif + + for (i = 0; i < g_numDirs; i++) + { + strcpy(check,g_strDirs[i]); + vfsCleanFileName(check); +#ifdef DBG_RLTPATH + Sys_Printf("Matching against %s\n", check); +#endif + + // try to find a match + if (strstr(l_in, check)) + { + strcpy(out,l_in+strlen(check)+1); + break; + } + + } + if (out[0]!=0) + { +#ifdef DBG_RLTPATH + Sys_Printf("vfsExtractRelativePath: success\n"); +#endif + return out; + } +#ifdef DBG_RLTPATH + Sys_Printf("vfsExtractRelativePath: failed\n"); +#endif + return NULL; +} + +// HYDRA: this now searches VFS/PAK files in addition to the filesystem +// if FLAG is unspecified then ONLY dirs are searched. +// PAK's are searched before DIRs to mimic engine behaviour +// index is ignored when searching PAK files. +// see ifilesystem.h +char* vfsGetFullPath(const char *in, int index, int flag) +{ + int count = 0; + static char out[PATH_MAX]; + char tmp[NAME_MAX]; + int i; + + if (flag & VFS_SEARCH_PAK) + { + char fixed[NAME_MAX]; + GSList *lst; + + strcpy (fixed, in); + vfsFixDOSName (fixed); + g_strdown (fixed); + + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + + char *ptr,*lastptr; + lastptr = file->name; + + while (ptr = strchr(lastptr,'/')) + lastptr = ptr+1; + + if (strcmp (lastptr, fixed) == 0) + { + strncpy(out,file->name,PATH_MAX); + return out; + } + } + + } + + if (!flag || (flag & VFS_SEARCH_DIR)) + { + for (i = 0; i < g_numDirs; i++) + { + strcpy (tmp, g_strDirs[i]); + strcat (tmp, in); + if (access (tmp, R_OK) == 0) + { + if (count == index) + { + strcpy (out, tmp); + return out; + } + count++; + } + } + } + return NULL; +} + +// FIXME TTimo: this and the above should be merged at some point +char* vfsExtractRelativePath(const char *in) +{ + static char out[PATH_MAX]; + unsigned int i, count; + char *chunk, *backup = NULL; // those point to out stuff + char *ret = vfsExtractRelativePath_short(in, false); + if (!ret) + { +#ifdef DBG_RLTPATH + Sys_Printf("trying with a short version\n"); +#endif + ret = vfsExtractRelativePath_short(in, true); + if (ret) + { + // ok, but we have a relative short version now + // hack the long relative version out of here + count = 0; + for(i=0;i -#include "vfspak.h" -#include "vfs.h" - -// ============================================================================= -// SYNAPSE - -_QERFuncTable_1 g_FuncTable; - -CSynapseServer* g_pSynapseServer = NULL; -CSynapseClientVFS 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(VFS_MAJOR, "pak", sizeof(_QERFileSystemTable)); - g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); - - return &g_SynapseClient; -} - -bool CSynapseClientVFS::RequestAPI(APIDescriptor_t *pAPI) -{ - if (!strcmp(pAPI->major_name, VFS_MAJOR)) - { - _QERFileSystemTable* pTable= static_cast<_QERFileSystemTable*>(pAPI->mpTable); - pTable->m_pfnInitDirectory = &vfsInitDirectory; - pTable->m_pfnShutdown = &vfsShutdown; - pTable->m_pfnFreeFile = &vfsFreeFile; - pTable->m_pfnGetDirList = &vfsGetDirList; - pTable->m_pfnGetFileList = &vfsGetFileList; - pTable->m_pfnClearFileDirList = &vfsClearFileDirList; - pTable->m_pfnGetFileCount = &vfsGetFileCount; - pTable->m_pfnLoadFile = &vfsLoadFile; - pTable->m_pfnLoadFullPathFile = &vfsLoadFullPathFile; - pTable->m_pfnExtractRelativePath = &vfsExtractRelativePath; - pTable->m_pfnGetFullPath = &vfsGetFullPath; - pTable->m_pfnBasePromptPath = &vfsBasePromptPath; - return true; - } - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -#include "version.h" - -const char* CSynapseClientVFS::GetInfo() -{ - return "PAK VFS module built " __DATE__ " " RADIANT_VERSION; -} - -const char* CSynapseClientVFS::GetName() -{ - return "VFS"; -} - - +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// +// Quake 1 Virtual FileSystem - reads files from different dirs and inside pak files +// +// Leonardo Zide (leo@lokigames.com) +// + +#include +#include "vfspak.h" +#include "vfs.h" + +// ============================================================================= +// SYNAPSE + +_QERFuncTable_1 g_FuncTable; + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientVFS 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(VFS_MAJOR, "pak", sizeof(_QERFileSystemTable)); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + + return &g_SynapseClient; +} + +bool CSynapseClientVFS::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, VFS_MAJOR)) + { + _QERFileSystemTable* pTable= static_cast<_QERFileSystemTable*>(pAPI->mpTable); + pTable->m_pfnInitDirectory = &vfsInitDirectory; + pTable->m_pfnShutdown = &vfsShutdown; + pTable->m_pfnFreeFile = &vfsFreeFile; + pTable->m_pfnGetDirList = &vfsGetDirList; + pTable->m_pfnGetFileList = &vfsGetFileList; + pTable->m_pfnClearFileDirList = &vfsClearFileDirList; + pTable->m_pfnGetFileCount = &vfsGetFileCount; + pTable->m_pfnLoadFile = &vfsLoadFile; + pTable->m_pfnLoadFullPathFile = &vfsLoadFullPathFile; + pTable->m_pfnExtractRelativePath = &vfsExtractRelativePath; + pTable->m_pfnGetFullPath = &vfsGetFullPath; + pTable->m_pfnBasePromptPath = &vfsBasePromptPath; + return true; + } + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientVFS::GetInfo() +{ + return "PAK VFS module built " __DATE__ " " RADIANT_VERSION; +} + +const char* CSynapseClientVFS::GetName() +{ + return "VFS"; +} + + diff --git a/plugins/vfspk3/unzip.cpp b/plugins/vfspk3/unzip.cpp index 42f0ccac..f7b7db1f 100644 --- a/plugins/vfspk3/unzip.cpp +++ b/plugins/vfspk3/unzip.cpp @@ -1,4537 +1,4537 @@ -/***************************************************************************** - * name: unzip.c - * - * desc: IO on .zip files using portions of zlib - * - * - *****************************************************************************/ - -#include -#include -#include -#include "unzip-vfspk3.h" - -typedef unsigned char byte; - -/* unzip.h -- IO for uncompress .zip files using zlib - Version 0.15 beta, Mar 19th, 1998, - - Copyright (C) 1998 Gilles Vollant - - This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g - WinZip, InfoZip tools and compatible. - Encryption and multi volume ZipFile (span) are not supported. - Old compressions used by old PKZip 1.x are not supported - - THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE - CAN CHANGE IN FUTURE VERSION !! - I WAIT FEEDBACK at mail info@winimage.com - Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution - - Condition of use and distribution are the same than zlib : - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - -*/ -/* for more info about .ZIP format, see - ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip - PkWare has also a specification at : - ftp://ftp.pkware.com/probdesc.zip */ - -/* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.1.3, July 9th, 1998 - - Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - - - The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt - (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). -*/ - -/* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-1998 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - - -#ifndef _ZCONF_H -#define _ZCONF_H - -/* Maximum value for memLevel in deflateInit2 */ -#ifndef MAX_MEM_LEVEL -# ifdef MAXSEG_64K -# define MAX_MEM_LEVEL 8 -# else -# define MAX_MEM_LEVEL 9 -# endif -#endif - -/* Maximum value for windowBits in deflateInit2 and inflateInit2. - * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files - * created by gzip. (Files created by minigzip can still be extracted by - * gzip.) - */ -#ifndef MAX_WBITS -# define MAX_WBITS 15 /* 32K LZ77 window */ -#endif - -/* The memory requirements for deflate are (in bytes): - (1 << (windowBits+2)) + (1 << (memLevel+9)) - that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) - plus a few kilobytes for small objects. For example, if you want to reduce - the default memory requirements from 256K to 128K, compile with - make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" - Of course this will generally degrade compression (there's no free lunch). - - The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes - for small objects. -*/ - - /* Type declarations */ - -#ifndef OF /* function prototypes */ -#define OF(args) args -#endif - -typedef unsigned char Byte; /* 8 bits */ -typedef unsigned int uInt; /* 16 bits or more */ -typedef unsigned long uLong; /* 32 bits or more */ -typedef Byte *voidp; - -#ifndef SEEK_SET -# define SEEK_SET 0 /* Seek from beginning of file. */ -# define SEEK_CUR 1 /* Seek from current position. */ -# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ -#endif - -#endif /* _ZCONF_H */ - -#define ZLIB_VERSION "1.1.3" - -/* - The 'zlib' compression library provides in-memory compression and - decompression functions, including integrity checks of the uncompressed - data. This version of the library supports only one compression method - (deflation) but other algorithms will be added later and will have the same - stream interface. - - Compression can be done in a single step if the buffers are large - enough (for example if an input file is mmap'ed), or can be done by - repeated calls of the compression function. In the latter case, the - application must provide more input and/or consume the output - (providing more output space) before each call. - - The library also supports reading and writing files in gzip (.gz) format - with an interface similar to that of stdio. - - The library does not install any signal handler. The decoder checks - the consistency of the compressed data, so the library should never - crash even in case of corrupted input. -*/ - -/* - The application must update next_in and avail_in when avail_in has - dropped to zero. It must update next_out and avail_out when avail_out - has dropped to zero. The application must initialize zalloc, zfree and - opaque before calling the init function. All other fields are set by the - compression library and must not be updated by the application. - - The opaque value provided by the application will be passed as the first - parameter for calls of zalloc and zfree. This can be useful for custom - memory management. The compression library attaches no meaning to the - opaque value. - - zalloc must return Z_NULL if there is not enough memory for the object. - If zlib is used in a multi-threaded application, zalloc and zfree must be - thread safe. - - On 16-bit systems, the functions zalloc and zfree must be able to allocate - exactly 65536 bytes, but will not be required to allocate more than this - if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, - pointers returned by zalloc for objects of exactly 65536 bytes *must* - have their offset normalized to zero. The default allocation function - provided by this library ensures this (see zutil.c). To reduce memory - requirements and avoid any allocation of 64K objects, at the expense of - compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). - - The fields total_in and total_out can be used for statistics or - progress reports. After compression, total_in holds the total size of - the uncompressed data and may be saved for use in the decompressor - (particularly if the decompressor wants to decompress everything in - a single step). -*/ - - /* constants */ - -#define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ -#define Z_SYNC_FLUSH 2 -#define Z_FULL_FLUSH 3 -#define Z_FINISH 4 -/* Allowed flush values; see deflate() below for details */ - -#define Z_OK 0 -#define Z_STREAM_END 1 -#define Z_NEED_DICT 2 -#define Z_ERRNO (-1) -#define Z_STREAM_ERROR (-2) -#define Z_DATA_ERROR (-3) -#define Z_MEM_ERROR (-4) -#define Z_BUF_ERROR (-5) -#define Z_VERSION_ERROR (-6) -/* Return codes for the compression/decompression functions. Negative - * values are errors, positive values are used for special but normal events. - */ - -#define Z_NO_COMPRESSION 0 -#define Z_BEST_SPEED 1 -#define Z_BEST_COMPRESSION 9 -#define Z_DEFAULT_COMPRESSION (-1) -/* compression levels */ - -#define Z_FILTERED 1 -#define Z_HUFFMAN_ONLY 2 -#define Z_DEFAULT_STRATEGY 0 -/* compression strategy; see deflateInit2() below for details */ - -#define Z_BINARY 0 -#define Z_ASCII 1 -#define Z_UNKNOWN 2 -/* Possible values of the data_type field */ - -#define Z_DEFLATED 8 -/* The deflate compression method (the only one supported in this version) */ - -#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ - -#define zlib_version zlibVersion() -/* for compatibility with versions < 1.0.2 */ - - /* basic functions */ - -const char * zlibVersion OF((void)); -/* The application can compare zlibVersion and ZLIB_VERSION for consistency. - If the first character differs, the library code actually used is - not compatible with the zlib.h header file used by the application. - This check is automatically made by deflateInit and inflateInit. - */ - -/* -int deflateInit OF((z_streamp strm, int level)); - - Initializes the internal stream state for compression. The fields - zalloc, zfree and opaque must be initialized before by the caller. - If zalloc and zfree are set to Z_NULL, deflateInit updates them to - use default allocation functions. - - The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: - 1 gives best speed, 9 gives best compression, 0 gives no compression at - all (the input data is simply copied a block at a time). - Z_DEFAULT_COMPRESSION requests a default compromise between speed and - compression (currently equivalent to level 6). - - deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if level is not a valid compression level, - Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible - with the version assumed by the caller (ZLIB_VERSION). - msg is set to null if there is no error message. deflateInit does not - perform any compression: this will be done by deflate(). -*/ - - -int deflate OF((z_streamp strm, int flush)); -/* - deflate compresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce some - output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. deflate performs one or both of the - following actions: - - - Compress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in and avail_in are updated and - processing will resume at this point for the next call of deflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. This action is forced if the parameter flush is non zero. - Forcing flush frequently degrades the compression ratio, so this parameter - should be set only when necessary (in interactive applications). - Some output may be provided even if flush is not set. - - Before the call of deflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating avail_in or avail_out accordingly; avail_out - should never be zero before the call. The application can consume the - compressed output when it wants, for example when the output buffer is full - (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK - and with zero avail_out, it must be called again after making room in the - output buffer because there might be more output pending. - - If the parameter flush is set to Z_SYNC_FLUSH, all pending output is - flushed to the output buffer and the output is aligned on a byte boundary, so - that the decompressor can get all input data available so far. (In particular - avail_in is zero after the call if enough output space has been provided - before the call.) Flushing may degrade compression for some compression - algorithms and so it should be used only when necessary. - - If flush is set to Z_FULL_FLUSH, all output is flushed as with - Z_SYNC_FLUSH, and the compression state is reset so that decompression can - restart from this point if previous compressed data has been damaged or if - random access is desired. Using Z_FULL_FLUSH too often can seriously degrade - the compression. - - If deflate returns with avail_out == 0, this function must be called again - with the same value of the flush parameter and more output space (updated - avail_out), until the flush is complete (deflate returns with non-zero - avail_out). - - If the parameter flush is set to Z_FINISH, pending input is processed, - pending output is flushed and deflate returns with Z_STREAM_END if there - was enough output space; if deflate returns with Z_OK, this function must be - called again with Z_FINISH and more output space (updated avail_out) but no - more input data, until it returns with Z_STREAM_END or an error. After - deflate has returned Z_STREAM_END, the only possible operations on the - stream are deflateReset or deflateEnd. - - Z_FINISH can be used immediately after deflateInit if all the compression - is to be done in a single step. In this case, avail_out must be at least - 0.1% larger than avail_in plus 12 bytes. If deflate does not return - Z_STREAM_END, then it must be called again as described above. - - deflate() sets strm->adler to the adler32 checksum of all input read - so (that is, total_in bytes). - - deflate() may update data_type if it can make a good guess about - the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered - binary. This field is only for information purposes and does not affect - the compression algorithm in any manner. - - deflate() returns Z_OK if some progress has been made (more input - processed or more output produced), Z_STREAM_END if all input has been - consumed and all output has been produced (only when flush is set to - Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example - if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible - (for example avail_in or avail_out was zero). -*/ - - -int deflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the - stream state was inconsistent, Z_DATA_ERROR if the stream was freed - prematurely (some input or output was discarded). In the error case, - msg may be set but then points to a static string (which must not be - deallocated). -*/ - - -/* -int inflateInit OF((z_streamp strm)); - - Initializes the internal stream state for decompression. The fields - next_in, avail_in, zalloc, zfree and opaque must be initialized before by - the caller. If next_in is not Z_NULL and avail_in is large enough (the exact - value depends on the compression method), inflateInit determines the - compression method from the zlib header and allocates all data structures - accordingly; otherwise the allocation will be deferred to the first call of - inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to - use default allocation functions. - - inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_VERSION_ERROR if the zlib library version is incompatible with the - version assumed by the caller. msg is set to null if there is no error - message. inflateInit does not perform any decompression apart from reading - the zlib header if present: this will be done by inflate(). (So next_in and - avail_in may be modified, but next_out and avail_out are unchanged.) -*/ - - -int inflate OF((z_streamp strm, int flush)); -/* - inflate decompresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may some - introduce some output latency (reading input without producing any output) - except when forced to flush. - - The detailed semantics are as follows. inflate performs one or both of the - following actions: - - - Decompress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in is updated and processing - will resume at this point for the next call of inflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. inflate() provides as much output as possible, until there - is no more input data or no more space in the output buffer (see below - about the flush parameter). - - Before the call of inflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating the next_* and avail_* values accordingly. - The application can consume the uncompressed output when it wants, for - example when the output buffer is full (avail_out == 0), or after each - call of inflate(). If inflate returns Z_OK and with zero avail_out, it - must be called again after making room in the output buffer because there - might be more output pending. - - If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much - output as possible to the output buffer. The flushing behavior of inflate is - not specified for values of the flush parameter other than Z_SYNC_FLUSH - and Z_FINISH, but the current implementation actually flushes as much output - as possible anyway. - - inflate() should normally be called until it returns Z_STREAM_END or an - error. However if all decompression is to be performed in a single step - (a single call of inflate), the parameter flush should be set to - Z_FINISH. In this case all pending input is processed and all pending - output is flushed; avail_out must be large enough to hold all the - uncompressed data. (The size of the uncompressed data may have been saved - by the compressor for this purpose.) The next operation on this stream must - be inflateEnd to deallocate the decompression state. The use of Z_FINISH - is never required, but can be used to inform inflate that a faster routine - may be used for the single inflate() call. - - If a preset dictionary is needed at this point (see inflateSetDictionary - below), inflate sets strm-adler to the adler32 checksum of the - dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise - it sets strm->adler to the adler32 checksum of all output produced - so (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or - an error code as described below. At the end of the stream, inflate() - checks that its computed adler32 checksum is equal to that saved by the - compressor and returns Z_STREAM_END only if the checksum is correct. - - inflate() returns Z_OK if some progress has been made (more input processed - or more output produced), Z_STREAM_END if the end of the compressed data has - been reached and all uncompressed output has been produced, Z_NEED_DICT if a - preset dictionary is needed at this point, Z_DATA_ERROR if the input data was - corrupted (input stream not conforming to the zlib format or incorrect - adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent - (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if no progress is possible or if there was not - enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR - case, the application may then call inflateSync to look for a good - compression block. -*/ - - -int inflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state - was inconsistent. In the error case, msg may be set but then points to a - static string (which must not be deallocated). -*/ - - /* Advanced functions */ - -/* - The following functions are needed only in some special applications. -*/ - -/* -int deflateInit2 OF((z_streamp strm, - int level, - int method, - int windowBits, - int memLevel, - int strategy)); - - This is another version of deflateInit with more compression options. The - fields next_in, zalloc, zfree and opaque must be initialized before by - the caller. - - The method parameter is the compression method. It must be Z_DEFLATED in - this version of the library. - - The windowBits parameter is the base two logarithm of the window size - (the size of the history buffer). It should be in the range 8..15 for this - version of the library. Larger values of this parameter result in better - compression at the expense of memory usage. The default value is 15 if - deflateInit is used instead. - - The memLevel parameter specifies how much memory should be allocated - for the internal compression state. memLevel=1 uses minimum memory but - is slow and reduces compression ratio; memLevel=9 uses maximum memory - for optimal speed. The default value is 8. See zconf.h for total memory - usage as a function of windowBits and memLevel. - - The strategy parameter is used to tune the compression algorithm. Use the - value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a - filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no - string match). Filtered data consists mostly of small values with a - somewhat random distribution. In this case, the compression algorithm is - tuned to compress them better. The effect of Z_FILTERED is to force more - Huffman coding and less string matching; it is somewhat intermediate - between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects - the compression ratio but not the correctness of the compressed output even - if it is not set appropriately. - - deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid - method). msg is set to null if there is no error message. deflateInit2 does - not perform any compression: this will be done by deflate(). -*/ - -int deflateSetDictionary OF((z_streamp strm, - const Byte *dictionary, - uInt dictLength)); -/* - Initializes the compression dictionary from the given byte sequence - without producing any compressed output. This function must be called - immediately after deflateInit, deflateInit2 or deflateReset, before any - call of deflate. The compressor and decompressor must use exactly the same - dictionary (see inflateSetDictionary). - - The dictionary should consist of strings (byte sequences) that are likely - to be encountered later in the data to be compressed, with the most commonly - used strings preferably put towards the end of the dictionary. Using a - dictionary is most useful when the data to be compressed is short and can be - predicted with good accuracy; the data can then be compressed better than - with the default empty dictionary. - - Depending on the size of the compression data structures selected by - deflateInit or deflateInit2, a part of the dictionary may in effect be - discarded, for example if the dictionary is larger than the window size in - deflate or deflate2. Thus the strings most likely to be useful should be - put at the end of the dictionary, not at the front. - - Upon return of this function, strm->adler is set to the Adler32 value - of the dictionary; the decompressor may later use this value to determine - which dictionary has been used by the compressor. (The Adler32 value - applies to the whole dictionary even if only a subset of the dictionary is - actually used by the compressor.) - - deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is - inconsistent (for example if deflate has already been called for this stream - or if the compression method is bsort). deflateSetDictionary does not - perform any compression: this will be done by deflate(). -*/ - -int deflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when several compression strategies will be - tried, for example when there are several ways of pre-processing the input - data with a filter. The streams that will be discarded should then be freed - by calling deflateEnd. Note that deflateCopy duplicates the internal - compression state which can be quite large, so this strategy is slow and - can consume lots of memory. - - deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. -*/ - -int deflateReset OF((z_streamp strm)); -/* - This function is equivalent to deflateEnd followed by deflateInit, - but does not free and reallocate all the internal compression state. - The stream will keep the same compression level and any other attributes - that may have been set by deflateInit2. - - deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -int deflateParams OF((z_streamp strm, - int level, - int strategy)); -/* - Dynamically update the compression level and compression strategy. The - interpretation of level and strategy is as in deflateInit2. This can be - used to switch between compression and straight copy of the input data, or - to switch to a different kind of input data requiring a different - strategy. If the compression level is changed, the input available so far - is compressed with the old level (and may be flushed); the new level will - take effect only at the next call of deflate(). - - Before the call of deflateParams, the stream state must be set as for - a call of deflate(), since the currently available input may have to - be compressed and flushed. In particular, strm->avail_out must be non-zero. - - deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source - stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR - if strm->avail_out was zero. -*/ - -/* -int inflateInit2 OF((z_streamp strm, - int windowBits)); - - This is another version of inflateInit with an extra parameter. The - fields next_in, avail_in, zalloc, zfree and opaque must be initialized - before by the caller. - - The windowBits parameter is the base two logarithm of the maximum window - size (the size of the history buffer). It should be in the range 8..15 for - this version of the library. The default value is 15 if inflateInit is used - instead. If a compressed stream with a larger window size is given as - input, inflate() will return with the error code Z_DATA_ERROR instead of - trying to allocate a larger window. - - inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative - memLevel). msg is set to null if there is no error message. inflateInit2 - does not perform any decompression apart from reading the zlib header if - present: this will be done by inflate(). (So next_in and avail_in may be - modified, but next_out and avail_out are unchanged.) -*/ - -int inflateSetDictionary OF((z_streamp strm, - const Byte *dictionary, - uInt dictLength)); -/* - Initializes the decompression dictionary from the given uncompressed byte - sequence. This function must be called immediately after a call of inflate - if this call returned Z_NEED_DICT. The dictionary chosen by the compressor - can be determined from the Adler32 value returned by this call of - inflate. The compressor and decompressor must use exactly the same - dictionary (see deflateSetDictionary). - - inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is - inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the - expected one (incorrect Adler32 value). inflateSetDictionary does not - perform any decompression: this will be done by subsequent calls of - inflate(). -*/ - -int inflateSync OF((z_streamp strm)); -/* - Skips invalid compressed data until a full flush point (see above the - description of deflate with Z_FULL_FLUSH) can be found, or until all - available input is skipped. No output is provided. - - inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR - if no more input was provided, Z_DATA_ERROR if no flush point has been found, - or Z_STREAM_ERROR if the stream structure was inconsistent. In the success - case, the application may save the current current value of total_in which - indicates where valid compressed data was found. In the error case, the - application may repeatedly call inflateSync, providing more input each time, - until success or end of the input data. -*/ - -int inflateReset OF((z_streamp strm)); -/* - This function is equivalent to inflateEnd followed by inflateInit, - but does not free and reallocate all the internal decompression state. - The stream will keep attributes that may have been set by inflateInit2. - - inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - - - /* utility functions */ - -/* - The following utility functions are implemented on top of the - basic stream-oriented functions. To simplify the interface, some - default options are assumed (compression level and memory usage, - standard memory allocation functions). The source code of these - utility functions can easily be modified if you need special options. -*/ - -int compress OF((Byte *dest, uLong *destLen, - const Byte *source, uLong sourceLen)); -/* - Compresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be at least 0.1% larger than - sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the - compressed buffer. - This function can be used to compress a whole file at once if the - input file is mmap'ed. - compress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer. -*/ - -int compress2 OF((Byte *dest, uLong *destLen, - const Byte *source, uLong sourceLen, - int level)); -/* - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least 0.1% larger than sourceLen plus - 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ - -int uncompress OF((Byte *dest, uLong *destLen, - const Byte *source, uLong sourceLen)); -/* - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be large enough to hold the - entire uncompressed data. (The size of the uncompressed data must have - been saved previously by the compressor and transmitted to the decompressor - by some mechanism outside the scope of this compression library.) - Upon exit, destLen is the actual size of the compressed buffer. - This function can be used to decompress a whole file at once if the - input file is mmap'ed. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted. -*/ - - -typedef voidp gzFile; - -gzFile gzopen OF((const char *path, const char *mode)); -/* - Opens a gzip (.gz) file for reading or writing. The mode parameter - is as in fopen ("rb" or "wb") but can also include a compression level - ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for - Huffman only compression as in "wb1h". (See the description - of deflateInit2 for more information about the strategy parameter.) - - gzopen can be used to read a file which is not in gzip format; in this - case gzread will directly read from the file without decompression. - - gzopen returns NULL if the file could not be opened or if there was - insufficient memory to allocate the (de)compression state; errno - can be checked to distinguish the two cases (if errno is zero, the - zlib error is Z_MEM_ERROR). */ - -gzFile gzdopen OF((int fd, const char *mode)); -/* - gzdopen() associates a gzFile with the file descriptor fd. File - descriptors are obtained from calls like open, dup, creat, pipe or - fileno (in the file has been previously opened with fopen). - The mode parameter is as in gzopen. - The next call of gzclose on the returned gzFile will also close the - file descriptor fd, just like fclose(fdopen(fd), mode) closes the file - descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). - gzdopen returns NULL if there was insufficient memory to allocate - the (de)compression state. -*/ - -int gzsetparams OF((gzFile file, int level, int strategy)); -/* - Dynamically update the compression level or strategy. See the description - of deflateInit2 for the meaning of these parameters. - gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not - opened for writing. -*/ - -int gzread OF((gzFile file, voidp buf, unsigned len)); -/* - Reads the given number of uncompressed bytes from the compressed file. - If the input file was not in gzip format, gzread copies the given number - of bytes into the buffer. - gzread returns the number of uncompressed bytes actually read (0 for - end of file, -1 for error). */ - -int gzwrite OF((gzFile file, - const voidp buf, unsigned len)); -/* - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of uncompressed bytes actually written - (0 in case of error). -*/ - -int gzprintf OF((gzFile file, const char *format, ...)); -/* - Converts, formats, and writes the args to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written (0 in case of error). -*/ - -int gzputs OF((gzFile file, const char *s)); -/* - Writes the given null-terminated string to the compressed file, excluding - the terminating null character. - gzputs returns the number of characters written, or -1 in case of error. -*/ - -char * gzgets OF((gzFile file, char *buf, int len)); -/* - Reads bytes from the compressed file until len-1 characters are read, or - a newline character is read and transferred to buf, or an end-of-file - condition is encountered. The string is then terminated with a null - character. - gzgets returns buf, or Z_NULL in case of error. -*/ - -int gzputc OF((gzFile file, int c)); -/* - Writes c, converted to an unsigned char, into the compressed file. - gzputc returns the value that was written, or -1 in case of error. -*/ - -int gzgetc OF((gzFile file)); -/* - Reads one byte from the compressed file. gzgetc returns this byte - or -1 in case of end of file or error. -*/ - -int gzflush OF((gzFile file, int flush)); -/* - Flushes all pending output into the compressed file. The parameter - flush is as in the deflate() function. The return value is the zlib - error number (see function gzerror below). gzflush returns Z_OK if - the flush parameter is Z_FINISH and all output could be flushed. - gzflush should be called only when strictly necessary because it can - degrade compression. -*/ - -long gzseek OF((gzFile file, - long offset, int whence)); -/* - Sets the starting position for the next gzread or gzwrite on the - given compressed file. The offset represents a number of bytes in the - uncompressed data stream. The whence parameter is defined as in lseek(2); - the value SEEK_END is not supported. - If the file is opened for reading, this function is emulated but can be - extremely slow. If the file is opened for writing, only forward seeks are - supported; gzseek then compresses a sequence of zeroes up to the new - starting position. - - gzseek returns the resulting offset location as measured in bytes from - the beginning of the uncompressed stream, or -1 in case of error, in - particular if the file is opened for writing and the new starting position - would be before the current position. -*/ - -int gzrewind OF((gzFile file)); -/* - Rewinds the given file. This function is supported only for reading. - - gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) -*/ - -long gztell OF((gzFile file)); -/* - Returns the starting position for the next gzread or gzwrite on the - given compressed file. This position represents a number of bytes in the - uncompressed data stream. - - gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) -*/ - -int gzeof OF((gzFile file)); -/* - Returns 1 when EOF has previously been detected reading the given - input stream, otherwise zero. -*/ - -int gzclose OF((gzFile file)); -/* - Flushes all pending output if necessary, closes the compressed file - and deallocates all the (de)compression state. The return value is the zlib - error number (see function gzerror below). -*/ - -const char * gzerror OF((gzFile file, int *errnum)); -/* - Returns the error message for the last error which occurred on the - given compressed file. errnum is set to zlib error number. If an - error occurred in the file system and not in the compression library, - errnum is set to Z_ERRNO and the application may consult errno - to get the exact error code. -*/ - - /* checksum functions */ - -/* - These functions are not related to compression but are exported - anyway because they might be useful in applications using the - compression library. -*/ - -uLong adler32 OF((uLong adler, const Byte *buf, uInt len)); - -/* - Update a running Adler-32 checksum with the bytes buf[0..len-1] and - return the updated checksum. If buf is NULL, this function returns - the required initial value for the checksum. - An Adler-32 checksum is almost as reliable as a CRC32 but can be computed - much faster. Usage example: - - uLong adler = adler32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - adler = adler32(adler, buffer, length); - } - if (adler != original_adler) error(); -*/ - -uLong crc32 OF((uLong crc, const Byte *buf, uInt len)); -/* - Update a running crc with the bytes buf[0..len-1] and return the updated - crc. If buf is NULL, this function returns the required initial value - for the crc. Pre- and post-conditioning (one's complement) is performed - within this function so it shouldn't be done by the application. - Usage example: - - uLong crc = crc32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - crc = crc32(crc, buffer, length); - } - if (crc != original_crc) error(); -*/ - -// private stuff to not include cmdlib.h -/* -============================================================================ - - BYTE ORDER FUNCTIONS - -============================================================================ -*/ - -#ifdef _SGI_SOURCE -#define __BIG_ENDIAN__ -#endif - -#ifdef __BIG_ENDIAN__ - -short __LittleShort (short l) -{ - byte b1,b2; - - b1 = l&255; - b2 = (l>>8)&255; - - return (b1<<8) + b2; -} - -short __BigShort (short l) -{ - return l; -} - - -int __LittleLong (int l) -{ - byte b1,b2,b3,b4; - - b1 = l&255; - b2 = (l>>8)&255; - b3 = (l>>16)&255; - b4 = (l>>24)&255; - - return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; -} - -int __BigLong (int l) -{ - return l; -} - - -float __LittleFloat (float l) -{ - union {byte b[4]; float f;} in, out; - - in.f = l; - out.b[0] = in.b[3]; - out.b[1] = in.b[2]; - out.b[2] = in.b[1]; - out.b[3] = in.b[0]; - - return out.f; -} - -float __BigFloat (float l) -{ - return l; -} - - -#else - - -short __BigShort (short l) -{ - byte b1,b2; - - b1 = l&255; - b2 = (l>>8)&255; - - return (b1<<8) + b2; -} - -short __LittleShort (short l) -{ - return l; -} - - -int __BigLong (int l) -{ - byte b1,b2,b3,b4; - - b1 = l&255; - b2 = (l>>8)&255; - b3 = (l>>16)&255; - b4 = (l>>24)&255; - - return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; -} - -int __LittleLong (int l) -{ - return l; -} - -float __BigFloat (float l) -{ - union {byte b[4]; float f;} in, out; - - in.f = l; - out.b[0] = in.b[3]; - out.b[1] = in.b[2]; - out.b[2] = in.b[1]; - out.b[3] = in.b[0]; - - return out.f; -} - -float __LittleFloat (float l) -{ - return l; -} - - - -#endif - - - - - /* various hacks, don't look :) */ - -/* deflateInit and inflateInit are macros to allow checking the zlib version - * and the compiler's view of z_stream: - */ -int deflateInit_ OF((z_streamp strm, int level, - const char *version, int stream_size)); -int inflateInit_ OF((z_streamp strm, - const char *version, int stream_size)); -int deflateInit2_ OF((z_streamp strm, int level, int method, - int windowBits, int memLevel, - int strategy, const char *version, - int stream_size)); -int inflateInit2_ OF((z_streamp strm, int windowBits, - const char *version, int stream_size)); -#define deflateInit(strm, level) \ - deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit(strm) \ - inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) -#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ - deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ - (strategy), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit2(strm, windowBits) \ - inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) - - -const char * zError OF((int err)); -int inflateSyncPoint OF((z_streamp z)); -const uLong * get_crc_table OF((void)); - -typedef unsigned char uch; -typedef unsigned short ush; -typedef unsigned long ulg; - -extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ -/* (size given to avoid silly warnings with Visual C++) */ - -#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] - -#define ERR_RETURN(strm,err) \ - return (strm->msg = (char*)ERR_MSG(err), (err)) -/* To be used only when the state is known to be valid */ - - /* common constants */ - -#ifndef DEF_WBITS -# define DEF_WBITS MAX_WBITS -#endif -/* default windowBits for decompression. MAX_WBITS is for compression only */ - -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif -/* default memLevel */ - -#define STORED_BLOCK 0 -#define STATIC_TREES 1 -#define DYN_TREES 2 -/* The three kinds of block type */ - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -/* The minimum and maximum match lengths */ - -#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ - - /* target dependencies */ - - /* Common defaults */ - -#ifndef OS_CODE -# define OS_CODE 0x03 /* assume Unix */ -#endif - -#ifndef F_OPEN -# define F_OPEN(name, mode) fopen((name), (mode)) -#endif - - /* functions */ - -#ifdef HAVE_STRERROR - extern char *strerror OF((int)); -# define zstrerror(errnum) strerror(errnum) -#else -# define zstrerror(errnum) "" -#endif - -#define zmemcpy memcpy -#define zmemcmp memcmp -#define zmemzero(dest, len) memset(dest, 0, len) - -/* Diagnostic functions */ -#ifdef _ZIP_DEBUG_ - int z_verbose = 0; -# define Assert(cond,msg) assert(cond); - //{if(!(cond)) Sys_Error(msg);} -# define Trace(x) {if (z_verbose>=0) Sys_Error x ;} -# define Tracev(x) {if (z_verbose>0) Sys_Error x ;} -# define Tracevv(x) {if (z_verbose>1) Sys_Error x ;} -# define Tracec(c,x) {if (z_verbose>0 && (c)) Sys_Error x ;} -# define Tracecv(c,x) {if (z_verbose>1 && (c)) Sys_Error x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif - - -typedef uLong (*check_func) OF((uLong check, const Byte *buf, uInt len)); -voidp zcalloc OF((voidp opaque, unsigned items, unsigned size)); -void zcfree OF((voidp opaque, voidp ptr)); - -#define ZALLOC(strm, items, size) \ - (*((strm)->zalloc))((strm)->opaque, (items), (size)) -#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidp)(addr)) -#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} - - -#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \ - !defined(CASESENSITIVITYDEFAULT_NO) -#define CASESENSITIVITYDEFAULT_NO -#endif - - -#ifndef UNZ_BUFSIZE -#define UNZ_BUFSIZE (65536) -#endif - -#ifndef UNZ_MAXFILENAMEINZIP -#define UNZ_MAXFILENAMEINZIP (256) -#endif - -#ifndef ALLOC -# define ALLOC(size) (malloc(size)) -#endif -#ifndef TRYFREE -# define TRYFREE(p) {if (p) free(p);} -#endif - -#define SIZECENTRALDIRITEM (0x2e) -#define SIZEZIPLOCALHEADER (0x1e) - - - -/* =========================================================================== - Read a byte from a gz_stream; update next_in and avail_in. Return EOF - for end of file. - IN assertion: the stream s has been sucessfully opened for reading. -*/ - -/* -static int unzlocal_getByte(FILE *fin,int *pi) -{ - unsigned char c; - int err = fread(&c, 1, 1, fin); - if (err==1) - { - *pi = (int)c; - return UNZ_OK; - } - else - { - if (ferror(fin)) - return UNZ_ERRNO; - else - return UNZ_EOF; - } -} -*/ - -/* =========================================================================== - Reads a long in LSB order from the given gz_stream. Sets -*/ -static int unzlocal_getShort (FILE* fin, uLong *pX) -{ - short v; - - fread( &v, sizeof(v), 1, fin ); - - *pX = __LittleShort( v); - return UNZ_OK; - -/* - uLong x ; - int i; - int err; - - err = unzlocal_getByte(fin,&i); - x = (uLong)i; - - if (err==UNZ_OK) - err = unzlocal_getByte(fin,&i); - x += ((uLong)i)<<8; - - if (err==UNZ_OK) - *pX = x; - else - *pX = 0; - return err; -*/ -} - -static int unzlocal_getLong (FILE *fin, uLong *pX) -{ - int v; - - fread( &v, sizeof(v), 1, fin ); - - *pX = __LittleLong( v); - return UNZ_OK; - -/* - uLong x ; - int i; - int err; - - err = unzlocal_getByte(fin,&i); - x = (uLong)i; - - if (err==UNZ_OK) - err = unzlocal_getByte(fin,&i); - x += ((uLong)i)<<8; - - if (err==UNZ_OK) - err = unzlocal_getByte(fin,&i); - x += ((uLong)i)<<16; - - if (err==UNZ_OK) - err = unzlocal_getByte(fin,&i); - x += ((uLong)i)<<24; - - if (err==UNZ_OK) - *pX = x; - else - *pX = 0; - return err; -*/ -} - - -/* My own strcmpi / strcasecmp */ -static int strcmpcasenosensitive_internal (const char* fileName1,const char* fileName2) -{ - for (;;) - { - char c1=*(fileName1++); - char c2=*(fileName2++); - if ((c1>='a') && (c1<='z')) - c1 -= 0x20; - if ((c2>='a') && (c2<='z')) - c2 -= 0x20; - if (c1=='\0') - return ((c2=='\0') ? 0 : -1); - if (c2=='\0') - return 1; - if (c1c2) - return 1; - } -} - - -#ifdef CASESENSITIVITYDEFAULT_NO -#define CASESENSITIVITYDEFAULTVALUE 2 -#else -#define CASESENSITIVITYDEFAULTVALUE 1 -#endif - -#ifndef STRCMPCASENOSENTIVEFUNCTION -#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal -#endif - -/* - Compare two filename (fileName1,fileName2). - If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) - If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi - or strcasecmp) - If iCaseSenisivity = 0, case sensitivity is defaut of your operating system - (like 1 on Unix, 2 on Windows) - -*/ -extern int unzStringFileNameCompare (const char* fileName1,const char* fileName2,int iCaseSensitivity) -{ - if (iCaseSensitivity==0) - iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; - - if (iCaseSensitivity==1) - return strcmp(fileName1,fileName2); - - return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); -} - -#define BUFREADCOMMENT (0x400) - -/* - Locate the Central directory of a zipfile (at the end, just before - the global comment) -*/ -static uLong unzlocal_SearchCentralDir(FILE *fin) -{ - unsigned char* buf; - uLong uSizeFile; - uLong uBackRead; - uLong uMaxBack=0xffff; /* maximum size of global comment */ - uLong uPosFound=0; - - if (fseek(fin,0,SEEK_END) != 0) - return 0; - - - uSizeFile = ftell( fin ); - - if (uMaxBack>uSizeFile) - uMaxBack = uSizeFile; - - buf = (unsigned char*)malloc(BUFREADCOMMENT+4); - if (buf==NULL) - return 0; - - uBackRead = 4; - while (uBackReaduMaxBack) - uBackRead = uMaxBack; - else - uBackRead+=BUFREADCOMMENT; - uReadPos = uSizeFile-uBackRead ; - - uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? - (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); - if (fseek(fin,uReadPos,SEEK_SET)!=0) - break; - - if (fread(buf,(uInt)uReadSize,1,fin)!=1) - break; - - for (i=(int)uReadSize-3; (i--)>0;) - if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && - ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) - { - uPosFound = uReadPos+i; - break; - } - - if (uPosFound!=0) - break; - } - free(buf); - return uPosFound; -} - -extern unzFile unzReOpen (const char* path, unzFile file) -{ - unz_s *s; - FILE * fin; - - fin=fopen(path,"rb"); - if (fin==NULL) - return NULL; - - s=(unz_s*)malloc(sizeof(unz_s)); - memcpy(s, (unz_s*)file, sizeof(unz_s)); - - s->file = fin; - return (unzFile)s; -} - -/* - Open a Zip file. path contain the full pathname (by example, - on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer - "zlib/zlib109.zip". - If the zipfile cannot be opened (file don't exist or in not valid), the - return value is NULL. - Else, the return value is a unzFile Handle, usable with other function - of this unzip package. -*/ -extern unzFile unzOpen (const char* path) -{ - unz_s us; - unz_s *s; - uLong central_pos,uL; - FILE * fin ; - - uLong number_disk; /* number of the current dist, used for - spaning ZIP, unsupported, always 0*/ - uLong number_disk_with_CD; /* number the the disk with central dir, used - for spaning ZIP, unsupported, always 0*/ - uLong number_entry_CD; /* total number of entries in - the central dir - (same than number_entry on nospan) */ - - int err=UNZ_OK; - - fin=fopen(path,"rb"); - if (fin==NULL) - return NULL; - - central_pos = unzlocal_SearchCentralDir(fin); - if (central_pos==0) - err=UNZ_ERRNO; - - if (fseek(fin,central_pos,SEEK_SET)!=0) - err=UNZ_ERRNO; - - /* the signature, already checked */ - if (unzlocal_getLong(fin,&uL)!=UNZ_OK) - err=UNZ_ERRNO; - - /* number of this disk */ - if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK) - err=UNZ_ERRNO; - - /* number of the disk with the start of the central directory */ - if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) - err=UNZ_ERRNO; - - /* total number of entries in the central dir on this disk */ - if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) - err=UNZ_ERRNO; - - /* total number of entries in the central dir */ - if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) - err=UNZ_ERRNO; - - if ((number_entry_CD!=us.gi.number_entry) || - (number_disk_with_CD!=0) || - (number_disk!=0)) - err=UNZ_BADZIPFILE; - - /* size of the central directory */ - if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) - err=UNZ_ERRNO; - - /* offset of start of central directory with respect to the - starting disk number */ - if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) - err=UNZ_ERRNO; - - /* zipfile comment length */ - if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) - err=UNZ_ERRNO; - - if ((central_pospfile_in_zip_read!=NULL) - unzCloseCurrentFile(file); - - fclose(s->file); - free(s); - return UNZ_OK; -} - - -/* - Write info about the ZipFile in the *pglobal_info structure. - No preparation of the structure is needed - return UNZ_OK if there is no problem. */ -extern int unzGetGlobalInfo (unzFile file,unz_global_info *pglobal_info) -{ - unz_s* s; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - *pglobal_info=s->gi; - return UNZ_OK; -} - - -/* - Translate date/time from Dos format to tm_unz (readable more easilty) -*/ -static void unzlocal_DosDateToTmuDate (uLong ulDosDate, tm_unz* ptm) -{ - uLong uDate; - uDate = (uLong)(ulDosDate>>16); - ptm->tm_mday = (uInt)(uDate&0x1f) ; - ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; - ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; - - ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); - ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; - ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; -} - -/* - Get Info about the current file in the zipfile, with internal only info -*/ -static int unzlocal_GetCurrentFileInfoInternal (unzFile file, - unz_file_info *pfile_info, - unz_file_info_internal - *pfile_info_internal, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize) -{ - unz_s* s; - unz_file_info file_info; - unz_file_info_internal file_info_internal; - int err=UNZ_OK; - uLong uMagic; - long lSeek=0; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0) - err=UNZ_ERRNO; - - - /* we check the magic */ - if (err==UNZ_OK) - if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) - err=UNZ_ERRNO; - else if (uMagic!=0x02014b50) - err=UNZ_BADZIPFILE; - - if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK) - err=UNZ_ERRNO; - - unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); - - if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) - err=UNZ_ERRNO; - - lSeek+=file_info.size_filename; - if ((err==UNZ_OK) && (szFileName!=NULL)) - { - uLong uSizeRead ; - if (file_info.size_filename0) && (fileNameBufferSize>0)) - if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1) - err=UNZ_ERRNO; - lSeek -= uSizeRead; - } - - - if ((err==UNZ_OK) && (extraField!=NULL)) - { - uLong uSizeRead ; - if (file_info.size_file_extrafile,lSeek,SEEK_CUR)==0) - lSeek=0; - else - err=UNZ_ERRNO; - if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) - if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1) - err=UNZ_ERRNO; - lSeek += file_info.size_file_extra - uSizeRead; - } - else - lSeek+=file_info.size_file_extra; - - - if ((err==UNZ_OK) && (szComment!=NULL)) - { - uLong uSizeRead ; - if (file_info.size_file_commentfile,lSeek,SEEK_CUR)==0) - lSeek=0; - else - err=UNZ_ERRNO; - if ((file_info.size_file_comment>0) && (commentBufferSize>0)) - if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1) - err=UNZ_ERRNO; - lSeek+=file_info.size_file_comment - uSizeRead; - } - else - lSeek+=file_info.size_file_comment; - - if ((err==UNZ_OK) && (pfile_info!=NULL)) - *pfile_info=file_info; - - if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) - *pfile_info_internal=file_info_internal; - - return err; -} - - - -/* - Write info about the ZipFile in the *pglobal_info structure. - No preparation of the structure is needed - return UNZ_OK if there is no problem. -*/ -extern int unzGetCurrentFileInfo ( unzFile file, unz_file_info *pfile_info, - char *szFileName, uLong fileNameBufferSize, - void *extraField, uLong extraFieldBufferSize, - char *szComment, uLong commentBufferSize) -{ - return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, - szFileName,fileNameBufferSize, - extraField,extraFieldBufferSize, - szComment,commentBufferSize); -} - -/* - Set the current file of the zipfile to the first file. - return UNZ_OK if there is no problem -*/ -extern int unzGoToFirstFile (unzFile file) -{ - int err=UNZ_OK; - unz_s* s; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - s->pos_in_central_dir=s->offset_central_dir; - s->num_file=0; - err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, - &s->cur_file_info_internal, - NULL,0,NULL,0,NULL,0); - s->current_file_ok = (err == UNZ_OK); - return err; -} - - -/* - Set the current file of the zipfile to the next file. - return UNZ_OK if there is no problem - return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. -*/ -extern int unzGoToNextFile (unzFile file) -{ - unz_s* s; - int err; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (!s->current_file_ok) - return UNZ_END_OF_LIST_OF_FILE; - if (s->num_file+1==s->gi.number_entry) - return UNZ_END_OF_LIST_OF_FILE; - - s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + - s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; - s->num_file++; - err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, - &s->cur_file_info_internal, - NULL,0,NULL,0,NULL,0); - s->current_file_ok = (err == UNZ_OK); - return err; -} - - -/* - Try locate the file szFileName in the zipfile. - For the iCaseSensitivity signification, see unzipStringFileNameCompare - - return value : - UNZ_OK if the file is found. It becomes the current file. - UNZ_END_OF_LIST_OF_FILE if the file is not found -*/ -extern int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) -{ - unz_s* s; - int err; - - - uLong num_fileSaved; - uLong pos_in_central_dirSaved; - - - if (file==NULL) - return UNZ_PARAMERROR; - - if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) - return UNZ_PARAMERROR; - - s=(unz_s*)file; - if (!s->current_file_ok) - return UNZ_END_OF_LIST_OF_FILE; - - num_fileSaved = s->num_file; - pos_in_central_dirSaved = s->pos_in_central_dir; - - err = unzGoToFirstFile(file); - - while (err == UNZ_OK) - { - char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; - unzGetCurrentFileInfo(file,NULL, - szCurrentFileName,sizeof(szCurrentFileName)-1, - NULL,0,NULL,0); - if (unzStringFileNameCompare(szCurrentFileName, - szFileName,iCaseSensitivity)==0) - return UNZ_OK; - err = unzGoToNextFile(file); - } - - s->num_file = num_fileSaved ; - s->pos_in_central_dir = pos_in_central_dirSaved ; - return err; -} - - -/* - Read the static header of the current zipfile - Check the coherency of the static header and info in the end of central - directory about this file - store in *piSizeVar the size of extra info in static header - (filename and size of extra field data) -*/ -static int unzlocal_CheckCurrentFileCoherencyHeader (unz_s* s, uInt* piSizeVar, - uLong *poffset_local_extrafield, - uInt *psize_local_extrafield) -{ - uLong uMagic,uData,uFlags; - uLong size_filename; - uLong size_extra_field; - int err=UNZ_OK; - - *piSizeVar = 0; - *poffset_local_extrafield = 0; - *psize_local_extrafield = 0; - - if (fseek(s->file,s->cur_file_info_internal.offset_curfile + - s->byte_before_the_zipfile,SEEK_SET)!=0) - return UNZ_ERRNO; - - - if (err==UNZ_OK) - if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) - err=UNZ_ERRNO; - else if (uMagic!=0x04034b50) - err=UNZ_BADZIPFILE; - - if (unzlocal_getShort(s->file,&uData) != UNZ_OK) - err=UNZ_ERRNO; -/* - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) - err=UNZ_BADZIPFILE; -*/ - if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&uData) != UNZ_OK) - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) - err=UNZ_BADZIPFILE; - - if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && - (s->cur_file_info.compression_method!=Z_DEFLATED)) - err=UNZ_BADZIPFILE; - - if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */ - err=UNZ_ERRNO; - - if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */ - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && - ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */ - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && - ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */ - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && - ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - - if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK) - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) - err=UNZ_BADZIPFILE; - - *piSizeVar += (uInt)size_filename; - - if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK) - err=UNZ_ERRNO; - *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + - SIZEZIPLOCALHEADER + size_filename; - *psize_local_extrafield = (uInt)size_extra_field; - - *piSizeVar += (uInt)size_extra_field; - - return err; -} - -/* - Open for reading data the current file in the zipfile. - If there is no error and the file is opened, the return value is UNZ_OK. -*/ -extern int unzOpenCurrentFile (unzFile file) -{ - int err=UNZ_OK; - int Store; - uInt iSizeVar; - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - uLong offset_local_extrafield; /* offset of the static extra field */ - uInt size_local_extrafield; /* size of the static extra field */ - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (!s->current_file_ok) - return UNZ_PARAMERROR; - - if (s->pfile_in_zip_read != NULL) - unzCloseCurrentFile(file); - - if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, - &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) - return UNZ_BADZIPFILE; - - pfile_in_zip_read_info = (file_in_zip_read_info_s*) - malloc(sizeof(file_in_zip_read_info_s)); - if (pfile_in_zip_read_info==NULL) - return UNZ_INTERNALERROR; - - pfile_in_zip_read_info->read_buffer=(char*)malloc(UNZ_BUFSIZE); - pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; - pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; - pfile_in_zip_read_info->pos_local_extrafield=0; - - if (pfile_in_zip_read_info->read_buffer==NULL) - { - free(pfile_in_zip_read_info); - return UNZ_INTERNALERROR; - } - - pfile_in_zip_read_info->stream_initialised=0; - - if ((s->cur_file_info.compression_method!=0) && - (s->cur_file_info.compression_method!=Z_DEFLATED)) - err=UNZ_BADZIPFILE; - Store = s->cur_file_info.compression_method==0; - - pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; - pfile_in_zip_read_info->crc32=0; - pfile_in_zip_read_info->compression_method = - s->cur_file_info.compression_method; - pfile_in_zip_read_info->file=s->file; - pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; - - pfile_in_zip_read_info->stream.total_out = 0; - - if (!Store) - { - pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; - pfile_in_zip_read_info->stream.zfree = (free_func)0; - pfile_in_zip_read_info->stream.opaque = (voidp)0; - - err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); - if (err == Z_OK) - pfile_in_zip_read_info->stream_initialised=1; - /* windowBits is passed < 0 to tell that there is no zlib header. - * Note that in this case inflate *requires* an extra "dummy" byte - * after the compressed stream in order to complete decompression and - * return Z_STREAM_END. - * In unzip, i don't wait absolutely Z_STREAM_END because I known the - * size of both compressed and uncompressed data - */ - } - pfile_in_zip_read_info->rest_read_compressed = - s->cur_file_info.compressed_size ; - pfile_in_zip_read_info->rest_read_uncompressed = - s->cur_file_info.uncompressed_size ; - - - pfile_in_zip_read_info->pos_in_zipfile = - s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + - iSizeVar; - - pfile_in_zip_read_info->stream.avail_in = (uInt)0; - - - s->pfile_in_zip_read = pfile_in_zip_read_info; - return UNZ_OK; -} - - -/* - Read bytes from the current file. - buf contain buffer where data must be copied - len the size of buf. - - return the number of byte copied if somes bytes are copied - return 0 if the end of file was reached - return <0 with error code if there is an error - (UNZ_ERRNO for IO error, or zLib error for uncompress error) -*/ -extern int unzReadCurrentFile (unzFile file, void *buf, unsigned len) -{ - int err=UNZ_OK; - uInt iRead = 0; - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - - if ((pfile_in_zip_read_info->read_buffer == NULL)) - return UNZ_END_OF_LIST_OF_FILE; - if (len==0) - return 0; - - pfile_in_zip_read_info->stream.next_out = (Byte*)buf; - - pfile_in_zip_read_info->stream.avail_out = (uInt)len; - - if (len>pfile_in_zip_read_info->rest_read_uncompressed) - pfile_in_zip_read_info->stream.avail_out = - (uInt)pfile_in_zip_read_info->rest_read_uncompressed; - - while (pfile_in_zip_read_info->stream.avail_out>0) - { - if ((pfile_in_zip_read_info->stream.avail_in==0) && - (pfile_in_zip_read_info->rest_read_compressed>0)) - { - uInt uReadThis = UNZ_BUFSIZE; - if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; - if (uReadThis == 0) - return UNZ_EOF; - if (s->cur_file_info.compressed_size == pfile_in_zip_read_info->rest_read_compressed) - if (fseek(pfile_in_zip_read_info->file, - pfile_in_zip_read_info->pos_in_zipfile + - pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0) - return UNZ_ERRNO; - if (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1, - pfile_in_zip_read_info->file)!=1) - return UNZ_ERRNO; - pfile_in_zip_read_info->pos_in_zipfile += uReadThis; - - pfile_in_zip_read_info->rest_read_compressed-=uReadThis; - - pfile_in_zip_read_info->stream.next_in = - (Byte*)pfile_in_zip_read_info->read_buffer; - pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; - } - - if (pfile_in_zip_read_info->compression_method==0) - { - uInt uDoCopy,i ; - if (pfile_in_zip_read_info->stream.avail_out < - pfile_in_zip_read_info->stream.avail_in) - uDoCopy = pfile_in_zip_read_info->stream.avail_out ; - else - uDoCopy = pfile_in_zip_read_info->stream.avail_in ; - - for (i=0;istream.next_out+i) = - *(pfile_in_zip_read_info->stream.next_in+i); - - pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, - pfile_in_zip_read_info->stream.next_out, - uDoCopy); - pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; - pfile_in_zip_read_info->stream.avail_in -= uDoCopy; - pfile_in_zip_read_info->stream.avail_out -= uDoCopy; - pfile_in_zip_read_info->stream.next_out += uDoCopy; - pfile_in_zip_read_info->stream.next_in += uDoCopy; - pfile_in_zip_read_info->stream.total_out += uDoCopy; - iRead += uDoCopy; - } - else - { - uLong uTotalOutBefore,uTotalOutAfter; - const Byte *bufBefore; - uLong uOutThis; - int flush=Z_SYNC_FLUSH; - - uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; - bufBefore = pfile_in_zip_read_info->stream.next_out; - - /* - if ((pfile_in_zip_read_info->rest_read_uncompressed == - pfile_in_zip_read_info->stream.avail_out) && - (pfile_in_zip_read_info->rest_read_compressed == 0)) - flush = Z_FINISH; - */ - err=inflate(&pfile_in_zip_read_info->stream,flush); - - uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; - uOutThis = uTotalOutAfter-uTotalOutBefore; - - pfile_in_zip_read_info->crc32 = - crc32(pfile_in_zip_read_info->crc32,bufBefore, - (uInt)(uOutThis)); - - pfile_in_zip_read_info->rest_read_uncompressed -= - uOutThis; - - iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); - - if (err==Z_STREAM_END) - return (iRead==0) ? UNZ_EOF : iRead; - if (err!=Z_OK) - break; - } - } - - if (err==Z_OK) - return iRead; - return err; -} - - -/* - Give the current position in uncompressed data -*/ -extern long unztell (unzFile file) -{ - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - return (long)pfile_in_zip_read_info->stream.total_out; -} - - -/* - return 1 if the end of file was reached, 0 elsewhere -*/ -extern int unzeof (unzFile file) -{ - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - if (pfile_in_zip_read_info->rest_read_uncompressed == 0) - return 1; - else - return 0; -} - - - -/* - Read extra field from the current file (opened by unzOpenCurrentFile) - This is the static-header version of the extra field (sometimes, there is - more info in the static-header version than in the central-header) - - if buf==NULL, it return the size of the static extra field that can be read - - if buf!=NULL, len is the size of the buffer, the extra header is copied in - buf. - the return value is the number of bytes copied in buf, or (if <0) - the error code -*/ -extern int unzGetLocalExtrafield (unzFile file,void *buf,unsigned len) -{ - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - uInt read_now; - uLong size_to_read; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - size_to_read = (pfile_in_zip_read_info->size_local_extrafield - - pfile_in_zip_read_info->pos_local_extrafield); - - if (buf==NULL) - return (int)size_to_read; - - if (len>size_to_read) - read_now = (uInt)size_to_read; - else - read_now = (uInt)len ; - - if (read_now==0) - return 0; - - if (fseek(pfile_in_zip_read_info->file, - pfile_in_zip_read_info->offset_local_extrafield + - pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0) - return UNZ_ERRNO; - - if (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1) - return UNZ_ERRNO; - - return (int)read_now; -} - -/* - Close the file in zip opened with unzipOpenCurrentFile - Return UNZ_CRCERROR if all the file was read but the CRC is not good -*/ -extern int unzCloseCurrentFile (unzFile file) -{ - int err=UNZ_OK; - - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - - if (pfile_in_zip_read_info->rest_read_uncompressed == 0) - { - if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) - err=UNZ_CRCERROR; - } - - - free(pfile_in_zip_read_info->read_buffer); - pfile_in_zip_read_info->read_buffer = NULL; - if (pfile_in_zip_read_info->stream_initialised) - inflateEnd(&pfile_in_zip_read_info->stream); - - pfile_in_zip_read_info->stream_initialised = 0; - free(pfile_in_zip_read_info); - - s->pfile_in_zip_read=NULL; - - return err; -} - - -/* - Get the global comment string of the ZipFile, in the szComment buffer. - uSizeBuf is the size of the szComment buffer. - return the number of byte copied or an error code <0 -*/ -extern int unzGetGlobalComment (unzFile file, char *szComment, uLong uSizeBuf) -{ - unz_s* s; - uLong uReadThis ; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - - uReadThis = uSizeBuf; - if (uReadThis>s->gi.size_comment) - uReadThis = s->gi.size_comment; - - if (fseek(s->file,s->central_pos+22,SEEK_SET)!=0) - return UNZ_ERRNO; - - if (uReadThis>0) - { - *szComment='\0'; - if (fread(szComment,(uInt)uReadThis,1,s->file)!=1) - return UNZ_ERRNO; - } - - if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) - *(szComment+s->gi.size_comment)='\0'; - return (int)uReadThis; -} - -/* crc32.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - - -#ifdef DYNAMIC_CRC_TABLE - -static int crc_table_empty = 1; -static uLong crc_table[256]; -static void make_crc_table OF((void)); - -/* - Generate a table for a byte-wise 32-bit CRC calculation on the polynomial: - x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. - - Polynomials over GF(2) are represented in binary, one bit per coefficient, - with the lowest powers in the most significant bit. Then adding polynomials - is just exclusive-or, and multiplying a polynomial by x is a right shift by - one. If we call the above polynomial p, and represent a byte as the - polynomial q, also with the lowest power in the most significant bit (so the - byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, - where a mod b means the remainder after dividing a by b. - - This calculation is done using the shift-register method of multiplying and - taking the remainder. The register is initialized to zero, and for each - incoming bit, x^32 is added mod p to the register if the bit is a one (where - x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by - x (which is shifting right by one and adding x^32 mod p if the bit shifted - out is a one). We start with the highest power (least significant bit) of - q and repeat for all eight bits of q. - - The table is simply the CRC of all possible eight bit values. This is all - the information needed to generate CRC's on data a byte at a time for all - combinations of CRC register values and incoming bytes. -*/ -static void make_crc_table() -{ - uLong c; - int n, k; - uLong poly; /* polynomial exclusive-or pattern */ - /* terms of polynomial defining this crc (except x^32): */ - static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; - - /* make exclusive-or pattern from polynomial (0xedb88320L) */ - poly = 0L; - for (n = 0; n < sizeof(p)/sizeof(Byte); n++) - poly |= 1L << (31 - p[n]); - - for (n = 0; n < 256; n++) - { - c = (uLong)n; - for (k = 0; k < 8; k++) - c = c & 1 ? poly ^ (c >> 1) : c >> 1; - crc_table[n] = c; - } - crc_table_empty = 0; -} -#else -/* ======================================================================== - * Table of CRC-32's of all single-byte values (made by make_crc_table) - */ -static const uLong crc_table[256] = { - 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, - 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, - 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, - 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, - 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, - 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, - 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, - 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, - 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, - 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, - 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, - 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, - 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, - 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, - 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, - 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, - 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, - 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, - 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, - 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, - 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, - 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, - 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, - 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, - 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, - 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, - 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, - 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, - 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, - 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, - 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, - 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, - 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, - 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, - 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, - 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, - 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, - 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, - 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, - 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, - 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, - 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, - 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, - 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, - 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, - 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, - 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, - 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, - 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, - 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, - 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, - 0x2d02ef8dL -}; -#endif - -/* ========================================================================= - * This function can be used by asm versions of crc32() - */ -const uLong * get_crc_table() -{ -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) make_crc_table(); -#endif - return (const uLong *)crc_table; -} - -/* ========================================================================= */ -#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); -#define DO2(buf) DO1(buf); DO1(buf); -#define DO4(buf) DO2(buf); DO2(buf); -#define DO8(buf) DO4(buf); DO4(buf); - -/* ========================================================================= */ -uLong crc32(uLong crc, const Byte *buf, uInt len) -{ - if (buf == Z_NULL) return 0L; -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) - make_crc_table(); -#endif - crc = crc ^ 0xffffffffL; - while (len >= 8) - { - DO8(buf); - len -= 8; - } - if (len) do { - DO1(buf); - } while (--len); - return crc ^ 0xffffffffL; -} - -/* infblock.h -- header to use infblock.c - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -struct inflate_blocks_state; -typedef struct inflate_blocks_state inflate_blocks_statef; - -extern inflate_blocks_statef * inflate_blocks_new OF(( - z_streamp z, - check_func c, /* check function */ - uInt w)); /* window size */ - -extern int inflate_blocks OF(( - inflate_blocks_statef *, - z_streamp , - int)); /* initial return code */ - -extern void inflate_blocks_reset OF(( - inflate_blocks_statef *, - z_streamp , - uLong *)); /* check value on output */ - -extern int inflate_blocks_free OF(( - inflate_blocks_statef *, - z_streamp)); - -extern void inflate_set_dictionary OF(( - inflate_blocks_statef *s, - const Byte *d, /* dictionary */ - uInt n)); /* dictionary length */ - -extern int inflate_blocks_sync_point OF(( - inflate_blocks_statef *s)); - -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits - -/* Table for deflate from PKZIP's appnote.txt. */ -static const uInt border[] = { /* Order of the bit length code lengths */ - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - -/* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* Huffman code lookup table entry--this entry is four bytes for machines - that have 16-bit pointers (e.g. PC's in the small or medium model). */ - -typedef struct inflate_huft_s inflate_huft; - -struct inflate_huft_s { - union { - struct { - Byte Exop; /* number of extra bits or operation */ - Byte Bits; /* number of bits in this code or subcode */ - } what; - uInt pad; /* pad structure to a power of 2 (4 bytes for */ - } word; /* 16-bit, 8 bytes for 32-bit int's) */ - uInt base; /* literal, length base, distance base, - or table offset */ -}; - -/* Maximum size of dynamic tree. The maximum found in a long but non- - exhaustive search was 1004 huft structures (850 for length/literals - and 154 for distances, the latter actually the result of an - exhaustive search). The actual maximum is not known, but the - value below is more than safe. */ -#define MANY 1440 - -extern int inflate_trees_bits OF(( - uInt *, /* 19 code lengths */ - uInt *, /* bits tree desired/actual depth */ - inflate_huft * *, /* bits tree result */ - inflate_huft *, /* space for trees */ - z_streamp)); /* for messages */ - -extern int inflate_trees_dynamic OF(( - uInt, /* number of literal/length codes */ - uInt, /* number of distance codes */ - uInt *, /* that many (total) code lengths */ - uInt *, /* literal desired/actual bit depth */ - uInt *, /* distance desired/actual bit depth */ - inflate_huft * *, /* literal/length tree result */ - inflate_huft * *, /* distance tree result */ - inflate_huft *, /* space for trees */ - z_streamp)); /* for messages */ - -extern int inflate_trees_fixed OF(( - uInt *, /* literal desired/actual bit depth */ - uInt *, /* distance desired/actual bit depth */ - inflate_huft * *, /* literal/length tree result */ - inflate_huft * *, /* distance tree result */ - z_streamp)); /* for memory allocation */ - - -/* infcodes.h -- header to use infcodes.c - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -struct inflate_codes_state; -typedef struct inflate_codes_state inflate_codes_statef; - -extern inflate_codes_statef *inflate_codes_new OF(( - uInt, uInt, - inflate_huft *, inflate_huft *, - z_streamp )); - -extern int inflate_codes OF(( - inflate_blocks_statef *, - z_streamp , - int)); - -extern void inflate_codes_free OF(( - inflate_codes_statef *, - z_streamp )); - -/* infutil.h -- types and macros common to blocks and codes - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -#ifndef _INFUTIL_H -#define _INFUTIL_H - -typedef enum { - TYPE, /* get type bits (3, including end bit) */ - LENS, /* get lengths for stored */ - STORED, /* processing stored block */ - TABLE, /* get table lengths */ - BTREE, /* get bit lengths tree for a dynamic block */ - DTREE, /* get length, distance trees for a dynamic block */ - CODES, /* processing fixed or dynamic block */ - DRY, /* output remaining window bytes */ - DONE, /* finished last block, done */ - BAD} /* got a data error--stuck here */ -inflate_block_mode; - -/* inflate blocks semi-private state */ -struct inflate_blocks_state { - - /* mode */ - inflate_block_mode mode; /* current inflate_block mode */ - - /* mode dependent information */ - union { - uInt left; /* if STORED, bytes left to copy */ - struct { - uInt table; /* table lengths (14 bits) */ - uInt index; /* index into blens (or border) */ - uInt *blens; /* bit lengths of codes */ - uInt bb; /* bit length tree depth */ - inflate_huft *tb; /* bit length decoding tree */ - } trees; /* if DTREE, decoding info for trees */ - struct { - inflate_codes_statef - *codes; - } decode; /* if CODES, current state */ - } sub; /* submode */ - uInt last; /* true if this block is the last block */ - - /* mode independent information */ - uInt bitk; /* bits in bit buffer */ - uLong bitb; /* bit buffer */ - inflate_huft *hufts; /* single malloc for tree space */ - Byte *window; /* sliding window */ - Byte *end; /* one byte after sliding window */ - Byte *read; /* window read pointer */ - Byte *write; /* window write pointer */ - check_func checkfn; /* check function */ - uLong check; /* check on output */ - -}; - - -/* defines for inflate input/output */ -/* update pointers and return */ -#define UPDBITS {s->bitb=b;s->bitk=k;} -#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} -#define UPDOUT {s->write=q;} -#define UPDATE {UPDBITS UPDIN UPDOUT} -#define LEAVE {UPDATE return inflate_flush(s,z,r);} -/* get bytes and bits */ -#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} -#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} -#define NEXTBYTE (n--,*p++) -#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} -/* output bytes */ -#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) -#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} -#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} -#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} -#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} -#define OUTBYTE(a) {*q++=(Byte)(a);m--;} -/* load static pointers */ -#define LOAD {LOADIN LOADOUT} - -/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ -extern uInt inflate_mask[17]; - -/* copy as much as possible from the sliding window to the output area */ -extern int inflate_flush OF(( - inflate_blocks_statef *, - z_streamp , - int)); - -#endif - - -/* - Notes beyond the 1.93a appnote.txt: - - 1. Distance pointers never point before the beginning of the output - stream. - 2. Distance pointers can point back across blocks, up to 32k away. - 3. There is an implied maximum of 7 bits for the bit length table and - 15 bits for the actual data. - 4. If only one code exists, then it is encoded using one bit. (Zero - would be more efficient, but perhaps a little confusing.) If two - codes exist, they are coded using one bit each (0 and 1). - 5. There is no way of sending zero distance codes--a dummy must be - sent if there are none. (History: a pre 2.0 version of PKZIP would - store blocks with no distance codes, but this was discovered to be - too harsh a criterion.) Valid only for 1.93a. 2.04c does allow - zero distance codes, which is sent as one code of zero bits in - length. - 6. There are up to 286 literal/length codes. Code 256 represents the - end-of-block. Note however that the static length tree defines - 288 codes just to fill out the Huffman codes. Codes 286 and 287 - cannot be used though, since there is no length base or extra bits - defined for them. Similarily, there are up to 30 distance codes. - However, static trees define 32 codes (all 5 bits) to fill out the - Huffman codes, but the last two had better not show up in the data. - 7. Unzip can check dynamic Huffman blocks for complete code sets. - The exception is that a single code would not be complete (see #4). - 8. The five bits following the block type is really the number of - literal codes sent minus 257. - 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits - (1+6+6). Therefore, to output three times the length, you output - three codes (1+1+1), whereas to output four times the same length, - you only need two codes (1+3). Hmm. - 10. In the tree reconstruction algorithm, Code = Code + Increment - only if BitLength(i) is not zero. (Pretty obvious.) - 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) - 12. Note: length code 284 can represent 227-258, but length code 285 - really is 258. The last length deserves its own, short code - since it gets used a lot in very redundant files. The length - 258 is special since 258 - 3 (the min match length) is 255. - 13. The literal/length and distance code bit lengths are read as a - single stream of lengths. It is possible (and advantageous) for - a repeat code (16, 17, or 18) to go across the boundary between - the two sets of lengths. - */ - - -void inflate_blocks_reset(inflate_blocks_statef *s, z_streamp z, uLong *c) -{ - if (c != Z_NULL) - *c = s->check; - if (s->mode == BTREE || s->mode == DTREE) - ZFREE(z, s->sub.trees.blens); - if (s->mode == CODES) - inflate_codes_free(s->sub.decode.codes, z); - s->mode = TYPE; - s->bitk = 0; - s->bitb = 0; - s->read = s->write = s->window; - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(0L, (const Byte *)Z_NULL, 0); - Tracev(("inflate: blocks reset\n")); -} - - -inflate_blocks_statef *inflate_blocks_new(z_streamp z, check_func c, uInt w) -{ - inflate_blocks_statef *s; - - if ((s = (inflate_blocks_statef *)ZALLOC - (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) - return s; - if ((s->hufts = - (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) - { - ZFREE(z, s); - return Z_NULL; - } - if ((s->window = (Byte *)ZALLOC(z, 1, w)) == Z_NULL) - { - ZFREE(z, s->hufts); - ZFREE(z, s); - return Z_NULL; - } - s->end = s->window + w; - s->checkfn = c; - s->mode = TYPE; - Tracev(("inflate: blocks allocated\n")); - inflate_blocks_reset(s, z, Z_NULL); - return s; -} - - -int inflate_blocks(inflate_blocks_statef *s, z_streamp z, int r) -{ - uInt t; /* temporary storage */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Byte *p; /* input data pointer */ - uInt n; /* bytes available there */ - Byte *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - - /* copy input/output information to locals (UPDATE macro restores) */ - LOAD - - /* process input based on current state */ - while (1) switch (s->mode) - { - case TYPE: - NEEDBITS(3) - t = (uInt)b & 7; - s->last = t & 1; - switch (t >> 1) - { - case 0: /* stored */ - Tracev(("inflate: stored block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - t = k & 7; /* go to byte boundary */ - DUMPBITS(t) - s->mode = LENS; /* get length of stored block */ - break; - case 1: /* fixed */ - Tracev(("inflate: fixed codes block%s\n", - s->last ? " (last)" : "")); - { - uInt bl, bd; - inflate_huft *tl, *td; - - inflate_trees_fixed(&bl, &bd, &tl, &td, z); - s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); - if (s->sub.decode.codes == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - } - DUMPBITS(3) - s->mode = CODES; - break; - case 2: /* dynamic */ - Tracev(("inflate: dynamic codes block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - s->mode = TABLE; - break; - case 3: /* illegal */ - DUMPBITS(3) - s->mode = BAD; - z->msg = (char*)"invalid block type"; - r = Z_DATA_ERROR; - LEAVE - } - break; - case LENS: - NEEDBITS(32) - if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) - { - s->mode = BAD; - z->msg = (char*)"invalid stored block lengths"; - r = Z_DATA_ERROR; - LEAVE - } - s->sub.left = (uInt)b & 0xffff; - b = k = 0; /* dump bits */ - Tracev(("inflate: stored length %u\n", s->sub.left)); - s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); - break; - case STORED: - if (n == 0) - LEAVE - NEEDOUT - t = s->sub.left; - if (t > n) t = n; - if (t > m) t = m; - zmemcpy(q, p, t); - p += t; n -= t; - q += t; m -= t; - if ((s->sub.left -= t) != 0) - break; - Tracev(("inflate: stored end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - s->mode = s->last ? DRY : TYPE; - break; - case TABLE: - NEEDBITS(14) - s->sub.trees.table = t = (uInt)b & 0x3fff; -#ifndef PKZIP_BUG_WORKAROUND - if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) - { - s->mode = BAD; - z->msg = (char*)"too many length or distance symbols"; - r = Z_DATA_ERROR; - LEAVE - } -#endif - t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); - if ((s->sub.trees.blens = (uInt*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - DUMPBITS(14) - s->sub.trees.index = 0; - Tracev(("inflate: table sizes ok\n")); - s->mode = BTREE; - case BTREE: - while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) - { - NEEDBITS(3) - s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; - DUMPBITS(3) - } - while (s->sub.trees.index < 19) - s->sub.trees.blens[border[s->sub.trees.index++]] = 0; - s->sub.trees.bb = 7; - t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, - &s->sub.trees.tb, s->hufts, z); - if (t != Z_OK) - { - ZFREE(z, s->sub.trees.blens); - r = t; - if (r == Z_DATA_ERROR) - s->mode = BAD; - LEAVE - } - s->sub.trees.index = 0; - Tracev(("inflate: bits tree ok\n")); - s->mode = DTREE; - case DTREE: - while (t = s->sub.trees.table, - s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) - { - inflate_huft *h; - uInt i, j, c; - - t = s->sub.trees.bb; - NEEDBITS(t) - h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); - t = h->bits; - c = h->base; - if (c < 16) - { - DUMPBITS(t) - s->sub.trees.blens[s->sub.trees.index++] = c; - } - else /* c == 16..18 */ - { - i = c == 18 ? 7 : c - 14; - j = c == 18 ? 11 : 3; - NEEDBITS(t + i) - DUMPBITS(t) - j += (uInt)b & inflate_mask[i]; - DUMPBITS(i) - i = s->sub.trees.index; - t = s->sub.trees.table; - if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || - (c == 16 && i < 1)) - { - ZFREE(z, s->sub.trees.blens); - s->mode = BAD; - z->msg = (char*)"invalid bit length repeat"; - r = Z_DATA_ERROR; - LEAVE - } - c = c == 16 ? s->sub.trees.blens[i - 1] : 0; - do { - s->sub.trees.blens[i++] = c; - } while (--j); - s->sub.trees.index = i; - } - } - s->sub.trees.tb = Z_NULL; - { - uInt bl, bd; - inflate_huft *tl, *td; - inflate_codes_statef *c; - - bl = 9; /* must be <= 9 for lookahead assumptions */ - bd = 6; /* must be <= 9 for lookahead assumptions */ - t = s->sub.trees.table; - t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), - s->sub.trees.blens, &bl, &bd, &tl, &td, - s->hufts, z); - ZFREE(z, s->sub.trees.blens); - if (t != Z_OK) - { - if (t == (uInt)Z_DATA_ERROR) - s->mode = BAD; - r = t; - LEAVE - } - Tracev(("inflate: trees ok\n")); - if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - s->sub.decode.codes = c; - } - s->mode = CODES; - case CODES: - UPDATE - if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) - return inflate_flush(s, z, r); - r = Z_OK; - inflate_codes_free(s->sub.decode.codes, z); - LOAD - Tracev(("inflate: codes end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - if (!s->last) - { - s->mode = TYPE; - break; - } - s->mode = DRY; - case DRY: - FLUSH - if (s->read != s->write) - LEAVE - s->mode = DONE; - case DONE: - r = Z_STREAM_END; - LEAVE - case BAD: - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -} - - -int inflate_blocks_free(inflate_blocks_statef *s, z_streamp z) -{ - inflate_blocks_reset(s, z, Z_NULL); - ZFREE(z, s->window); - ZFREE(z, s->hufts); - ZFREE(z, s); - Tracev(("inflate: blocks freed\n")); - return Z_OK; -} - - -void inflate_set_dictionary(inflate_blocks_statef *s, const Byte *d, uInt n) -{ - zmemcpy(s->window, d, n); - s->read = s->write = s->window + n; -} - - -/* Returns true if inflate is currently at the end of a block generated - * by Z_SYNC_FLUSH or Z_FULL_FLUSH. - * IN assertion: s != Z_NULL - */ -int inflate_blocks_sync_point(inflate_blocks_statef *s) -{ - return s->mode == LENS; -} - -/* And'ing with mask[n] masks the lower n bits */ -uInt inflate_mask[17] = { - 0x0000, - 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, - 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff -}; - -/* copy as much as possible from the sliding window to the output area */ -int inflate_flush(inflate_blocks_statef *s, z_streamp z, int r) -{ - uInt n; - Byte *p; - Byte *q; - - /* static copies of source and destination pointers */ - p = z->next_out; - q = s->read; - - /* compute number of bytes to copy as as end of window */ - n = (uInt)((q <= s->write ? s->write : s->end) - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - /* update counters */ - z->avail_out -= n; - z->total_out += n; - - /* update check information */ - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(s->check, q, n); - - /* copy as as end of window */ - zmemcpy(p, q, n); - p += n; - q += n; - - /* see if more to copy at beginning of window */ - if (q == s->end) - { - /* wrap pointers */ - q = s->window; - if (s->write == s->end) - s->write = s->window; - - /* compute bytes to copy */ - n = (uInt)(s->write - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - /* update counters */ - z->avail_out -= n; - z->total_out += n; - - /* update check information */ - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(s->check, q, n); - - /* copy */ - zmemcpy(p, q, n); - p += n; - q += n; - } - - /* update pointers */ - z->next_out = p; - s->read = q; - - /* done */ - return r; -} - -/* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -const char inflate_copyright[] = - " inflate 1.1.3 Copyright 1995-1998 Mark Adler "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits - - -static int huft_build OF(( - uInt *, /* code lengths in bits */ - uInt, /* number of codes */ - uInt, /* number of "simple" codes */ - const uInt *, /* list of base values for non-simple codes */ - const uInt *, /* list of extra bits for non-simple codes */ - inflate_huft **, /* result: starting table */ - uInt *, /* maximum lookup bits (returns actual) */ - inflate_huft *, /* space for trees */ - uInt *, /* hufts used in space */ - uInt * )); /* space for values */ - -/* Tables for deflate from PKZIP's appnote.txt. */ -static const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - /* see note #13 above about 258 */ -static const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ -static const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577}; -static const uInt cpdext[30] = { /* Extra bits for distance codes */ - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13}; - -/* - Huffman code decoding is performed using a multi-level table lookup. - The fastest way to decode is to simply build a lookup table whose - size is determined by the longest code. However, the time it takes - to build this table can also be a factor if the data being decoded - is not very long. The most common codes are necessarily the - shortest codes, so those codes dominate the decoding time, and hence - the speed. The idea is you can have a shorter table that decodes the - shorter, more probable codes, and then point to subsidiary tables for - the longer codes. The time it costs to decode the longer codes is - then traded against the time it takes to make longer tables. - - This results of this trade are in the variables lbits and dbits - below. lbits is the number of bits the first level table for literal/ - length codes can decode in one step, and dbits is the same thing for - the distance codes. Subsequent tables are also less than or equal to - those sizes. These values may be adjusted either when all of the - codes are shorter than that, in which case the longest code length in - bits is used, or when the shortest code is *longer* than the requested - table size, in which case the length of the shortest code in bits is - used. - - There are two different values for the two tables, since they code a - different number of possibilities each. The literal/length table - codes 286 possible values, or in a flat code, a little over eight - bits. The distance table codes 30 possible values, or a little less - than five bits, flat. The optimum values for speed end up being - about one bit more than those, so lbits is 8+1 and dbits is 5+1. - The optimum values may differ though from machine to machine, and - possibly even between compilers. Your mileage may vary. - */ - - -/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ -#define BMAX 15 /* maximum bit length of any code */ - -static int huft_build(uInt *b, uInt n, uInt s, const uInt *d, const uInt *e, inflate_huft ** t, uInt *m, inflate_huft *hp, uInt *hn, uInt *v) -//uInt *b; /* code lengths in bits (all assumed <= BMAX) */ -//uInt n; /* number of codes (assumed <= 288) */ -//uInt s; /* number of simple-valued codes (0..s-1) */ -//const uInt *d; /* list of base values for non-simple codes */ -//const uInt *e; /* list of extra bits for non-simple codes */ -//inflate_huft ** t; /* result: starting table */ -//uInt *m; /* maximum lookup bits, returns actual */ -//inflate_huft *hp; /* space for trees */ -//uInt *hn; /* hufts used in space */ -//uInt *v; /* working area: values in order of bit length */ -/* Given a list of code lengths and a maximum table size, make a set of - tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR - if the given code set is incomplete (the tables are still built in this - case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of - lengths), or Z_MEM_ERROR if not enough memory. */ -{ - - uInt a; /* counter for codes of length k */ - uInt c[BMAX+1]; /* bit length count table */ - uInt f; /* i repeats in table every f entries */ - int g; /* maximum code length */ - int h; /* table level */ - register uInt i; /* counter, current code */ - register uInt j; /* counter */ - register int k; /* number of bits in current code */ - int l; /* bits per table (returned in m) */ - uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */ - register uInt *p; /* pointer into c[], b[], or v[] */ - inflate_huft *q; /* points to current table */ - struct inflate_huft_s r; /* table entry for structure assignment */ - inflate_huft *u[BMAX]; /* table stack */ - register int w; /* bits before this table == (l * h) */ - uInt x[BMAX+1]; /* bit offsets, then code stack */ - uInt *xp; /* pointer into x */ - int y; /* number of dummy codes added */ - uInt z; /* number of entries in current table */ - - - /* Generate counts for each bit length */ - p = c; -#define C0 *p++ = 0; -#define C2 C0 C0 C0 C0 -#define C4 C2 C2 C2 C2 - C4 /* clear c[]--assume BMAX+1 is 16 */ - p = b; i = n; - do { - c[*p++]++; /* assume all entries <= BMAX */ - } while (--i); - if (c[0] == n) /* null input--all zero length codes */ - { - *t = (inflate_huft *)Z_NULL; - *m = 0; - return Z_OK; - } - - - /* Find minimum and maximum length, bound *m by those */ - l = *m; - for (j = 1; j <= BMAX; j++) - if (c[j]) - break; - k = j; /* minimum code length */ - if ((uInt)l < j) - l = j; - for (i = BMAX; i; i--) - if (c[i]) - break; - g = i; /* maximum code length */ - if ((uInt)l > i) - l = i; - *m = l; - - - /* Adjust last length count to fill out codes, if needed */ - for (y = 1 << j; j < i; j++, y <<= 1) - if ((y -= c[j]) < 0) - return Z_DATA_ERROR; - if ((y -= c[i]) < 0) - return Z_DATA_ERROR; - c[i] += y; - - - /* Generate starting offsets into the value table for each length */ - x[1] = j = 0; - p = c + 1; xp = x + 2; - while (--i) { /* note that i == g from above */ - *xp++ = (j += *p++); - } - - - /* Make a table of values in order of bit lengths */ - p = b; i = 0; - do { - if ((j = *p++) != 0) - v[x[j]++] = i; - } while (++i < n); - n = x[g]; /* set n to length of v */ - - - /* Generate the Huffman codes and for each, make the table entries */ - x[0] = i = 0; /* first Huffman code is zero */ - p = v; /* grab values in bit order */ - h = -1; /* no tables yet--level -1 */ - w = -l; /* bits decoded == (l * h) */ - u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ - q = (inflate_huft *)Z_NULL; /* ditto */ - z = 0; /* ditto */ - - /* go through the bit lengths (k already is bits in shortest code) */ - for (; k <= g; k++) - { - a = c[k]; - while (a--) - { - /* here i is the Huffman code of length k bits for value *p */ - /* make tables up to required level */ - while (k > w + l) - { - h++; - w += l; /* previous table always l bits */ - - /* compute minimum size table less than or equal to l bits */ - z = g - w; - z = z > (uInt)l ? l : z; /* table size upper limit */ - if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ - { /* too few codes for k-w bit table */ - f -= a + 1; /* deduct codes from patterns left */ - xp = c + k; - if (j < z) - while (++j < z) /* try smaller tables up to z bits */ - { - if ((f <<= 1) <= *++xp) - break; /* enough codes to use up j bits */ - f -= *xp; /* else deduct codes from patterns */ - } - } - z = 1 << j; /* table entries for j-bit table */ - - /* allocate new table */ - if (*hn + z > MANY) /* (note: doesn't matter for fixed) */ - return Z_MEM_ERROR; /* not enough memory */ - u[h] = q = hp + *hn; - *hn += z; - - /* connect to last table, if there is one */ - if (h) - { - x[h] = i; /* save pattern for backing up */ - r.bits = (Byte)l; /* bits to dump before this table */ - r.exop = (Byte)j; /* bits in this table */ - j = i >> (w - l); - r.base = (uInt)(q - u[h-1] - j); /* offset to this table */ - u[h-1][j] = r; /* connect to last table */ - } - else - *t = q; /* first table is returned result */ - } - - /* set up table entry in r */ - r.bits = (Byte)(k - w); - if (p >= v + n) - r.exop = 128 + 64; /* out of values--invalid code */ - else if (*p < s) - { - r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ - r.base = *p++; /* simple code is just the value */ - } - else - { - r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ - r.base = d[*p++ - s]; - } - - /* fill code-like entries with r */ - f = 1 << (k - w); - for (j = i >> w; j < z; j += f) - q[j] = r; - - /* backwards increment the k-bit code i */ - for (j = 1 << (k - 1); i & j; j >>= 1) - i ^= j; - i ^= j; - - /* backup over finished tables */ - mask = (1 << w) - 1; /* needed on HP, cc -O bug */ - while ((i & mask) != x[h]) - { - h--; /* don't need to update q */ - w -= l; - mask = (1 << w) - 1; - } - } - } - - - /* Return Z_BUF_ERROR if we were given an incomplete table */ - return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; -} - - -int inflate_trees_bits(uInt *c, uInt *bb, inflate_huft * *tb, inflate_huft *hp, z_streamp z) -//uInt *c; /* 19 code lengths */ -//uInt *bb; /* bits tree desired/actual depth */ -//inflate_huft * *tb; /* bits tree result */ -//inflate_huft *hp; /* space for trees */ -//z_streamp z; /* for messages */ -{ - int r; - uInt hn = 0; /* hufts used in space */ - uInt *v; /* work area for huft_build */ - - if ((v = (uInt*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) - return Z_MEM_ERROR; - r = huft_build(c, 19, 19, (uInt*)Z_NULL, (uInt*)Z_NULL, - tb, bb, hp, &hn, v); - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed dynamic bit lengths tree"; - else if (r == Z_BUF_ERROR || *bb == 0) - { - z->msg = (char*)"incomplete dynamic bit lengths tree"; - r = Z_DATA_ERROR; - } - ZFREE(z, v); - return r; -} - - -int inflate_trees_dynamic(uInt nl, uInt nd, uInt *c, uInt *bl, uInt *bd, inflate_huft * *tl, inflate_huft * *td, inflate_huft *hp, z_streamp z) -//uInt nl; /* number of literal/length codes */ -//uInt nd; /* number of distance codes */ -//uInt *c; /* that many (total) code lengths */ -//uInt *bl; /* literal desired/actual bit depth */ -//uInt *bd; /* distance desired/actual bit depth */ -//inflate_huft * *tl; /* literal/length tree result */ -//inflate_huft * *td; /* distance tree result */ -//inflate_huft *hp; /* space for trees */ -//z_streamp z; /* for messages */ -{ - int r; - uInt hn = 0; /* hufts used in space */ - uInt *v; /* work area for huft_build */ - - /* allocate work area */ - if ((v = (uInt*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) - return Z_MEM_ERROR; - - /* build literal/length tree */ - r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); - if (r != Z_OK || *bl == 0) - { - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed literal/length tree"; - else if (r != Z_MEM_ERROR) - { - z->msg = (char*)"incomplete literal/length tree"; - r = Z_DATA_ERROR; - } - ZFREE(z, v); - return r; - } - - /* build distance tree */ - r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); - if (r != Z_OK || (*bd == 0 && nl > 257)) - { - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed distance tree"; - else if (r == Z_BUF_ERROR) { -#ifdef PKZIP_BUG_WORKAROUND - r = Z_OK; - } -#else - z->msg = (char*)"incomplete distance tree"; - r = Z_DATA_ERROR; - } - else if (r != Z_MEM_ERROR) - { - z->msg = (char*)"empty distance tree with lengths"; - r = Z_DATA_ERROR; - } - ZFREE(z, v); - return r; -#endif - } - - /* done */ - ZFREE(z, v); - return Z_OK; -} - -/* inffixed.h -- table for decoding fixed codes - * Generated automatically by the maketree.c program - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -static uInt fixed_bl = 9; -static uInt fixed_bd = 5; -static inflate_huft fixed_tl[] = { - {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, - {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, - {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, - {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, - {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, - {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, - {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, - {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, - {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, - {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, - {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, - {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, - {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, - {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, - {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, - {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, - {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, - {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, - {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, - {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, - {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, - {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, - {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, - {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, - {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, - {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, - {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, - {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, - {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, - {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, - {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, - {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, - {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, - {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, - {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, - {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, - {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, - {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, - {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, - {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, - {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, - {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, - {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, - {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, - {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, - {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, - {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, - {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, - {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, - {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, - {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, - {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, - {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, - {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, - {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, - {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, - {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, - {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, - {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, - {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, - {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, - {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, - {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, - {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, - {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, - {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, - {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, - {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, - {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, - {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, - {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, - {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, - {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, - {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, - {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, - {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, - {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, - {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, - {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, - {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, - {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, - {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, - {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, - {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, - {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, - {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, - {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, - {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, - {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, - {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, - {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, - {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, - {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, - {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, - {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, - {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, - {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, - {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, - {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, - {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, - {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, - {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, - {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, - {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, - {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, - {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, - {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, - {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, - {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, - {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, - {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, - {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, - {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, - {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, - {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, - {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, - {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, - {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, - {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, - {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, - {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, - {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, - {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, - {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, - {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, - {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, - {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, - {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} - }; -static inflate_huft fixed_td[] = { - {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, - {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, - {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, - {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, - {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, - {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, - {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, - {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} - }; - -int inflate_trees_fixed(uInt *bl, uInt *bd, inflate_huft * *tl, inflate_huft * *td, z_streamp z) -//uInt *bl; /* literal desired/actual bit depth */ -//uInt *bd; /* distance desired/actual bit depth */ -//inflate_huft * *tl; /* literal/length tree result */ -//inflate_huft * *td; /* distance tree result */ -//z_streamp z; /* for memory allocation */ -{ - *bl = fixed_bl; - *bd = fixed_bd; - *tl = fixed_tl; - *td = fixed_td; - return Z_OK; -} - -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits - -/* macros for bit input with no checking and for returning unused bytes */ -#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;} - -/* Called with number of bytes left to write in window at least 258 - (the maximum string length) and number of input bytes available - at least ten. The ten bytes are six bytes for the longest length/ - distance pair plus four bytes for overloading the bit buffer. */ - -int inflate_fast(uInt bl, uInt bd, inflate_huft *tl, inflate_huft *td, inflate_blocks_statef *s, z_streamp z) -{ - inflate_huft *t; /* temporary pointer */ - uInt e; /* extra bits or operation */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Byte *p; /* input data pointer */ - uInt n; /* bytes available there */ - Byte *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - uInt ml; /* mask for literal/length tree */ - uInt md; /* mask for distance tree */ - uInt c; /* bytes to copy */ - uInt d; /* distance back to copy from */ - Byte *r; /* copy source pointer */ - - /* load input, output, bit values */ - LOAD - - /* initialize masks */ - ml = inflate_mask[bl]; - md = inflate_mask[bd]; - - /* do until not enough input or output space for fast loop */ - do { /* assume called with m >= 258 && n >= 10 */ - /* get literal/length code */ - GRABBITS(20) /* max bits for literal/length code */ - if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) - { - DUMPBITS(t->bits) - Tracevv((t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - continue; - } - do { - DUMPBITS(t->bits) - if (e & 16) - { - /* get extra bits for length */ - e &= 15; - c = t->base + ((uInt)b & inflate_mask[e]); - DUMPBITS(e) - Tracevv(("inflate: * length %u\n", c)); - - /* decode distance base of block to copy */ - GRABBITS(15); /* max bits for distance code */ - e = (t = td + ((uInt)b & md))->exop; - do { - DUMPBITS(t->bits) - if (e & 16) - { - /* get extra bits to add to distance base */ - e &= 15; - GRABBITS(e) /* get extra bits (up to 13) */ - d = t->base + ((uInt)b & inflate_mask[e]); - DUMPBITS(e) - Tracevv(("inflate: * distance %u\n", d)); - - /* do the copy */ - m -= c; - if ((uInt)(q - s->window) >= d) /* offset before dest */ - { /* just copy */ - r = q - d; - *q++ = *r++; c--; /* minimum count is three, */ - *q++ = *r++; c--; /* so unroll loop a little */ - } - else /* else offset after destination */ - { - e = d - (uInt)(q - s->window); /* bytes from offset to end */ - r = s->end - e; /* pointer to offset */ - if (c > e) /* if source crosses, */ - { - c -= e; /* copy to end of window */ - do { - *q++ = *r++; - } while (--e); - r = s->window; /* copy rest from start of window */ - } - } - do { /* copy all or what's left */ - *q++ = *r++; - } while (--c); - break; - } - else if ((e & 64) == 0) - { - t += t->base; - e = (t += ((uInt)b & inflate_mask[e]))->exop; - } - else - { - z->msg = (char*)"invalid distance code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - } while (1); - break; - } - if ((e & 64) == 0) - { - t += t->base; - if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) - { - DUMPBITS(t->bits) - Tracevv((t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - break; - } - } - else if (e & 32) - { - Tracevv(("inflate: * end of block\n")); - UNGRAB - UPDATE - return Z_STREAM_END; - } - else - { - z->msg = (char*)"invalid literal/length code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - } while (1); - } while (m >= 258 && n >= 10); - - /* not enough input or output--restore pointers and return */ - UNGRAB - UPDATE - return Z_OK; -} - -/* infcodes.c -- process literals and length/distance pairs - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits - -typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ - START, /* x: set up for LEN */ - LEN, /* i: get length/literal/eob next */ - LENEXT, /* i: getting length extra (have base) */ - DIST, /* i: get distance next */ - DISTEXT, /* i: getting distance extra */ - COPY, /* o: copying bytes in window, waiting for space */ - LIT, /* o: got literal, waiting for output space */ - WASH, /* o: got eob, possibly still output waiting */ - END, /* x: got eob and all data flushed */ - BADCODE} /* x: got error */ -inflate_codes_mode; - -/* inflate codes private state */ -struct inflate_codes_state { - - /* mode */ - inflate_codes_mode mode; /* current inflate_codes mode */ - - /* mode dependent information */ - uInt len; - union { - struct { - inflate_huft *tree; /* pointer into tree */ - uInt need; /* bits needed */ - } code; /* if LEN or DIST, where in tree */ - uInt lit; /* if LIT, literal */ - struct { - uInt get; /* bits to get for extra */ - uInt dist; /* distance back to copy from */ - } copy; /* if EXT or COPY, where and how much */ - } sub; /* submode */ - - /* mode independent information */ - Byte lbits; /* ltree bits decoded per branch */ - Byte dbits; /* dtree bits decoder per branch */ - inflate_huft *ltree; /* literal/length/eob tree */ - inflate_huft *dtree; /* distance tree */ - -}; - - -inflate_codes_statef *inflate_codes_new(uInt bl, uInt bd, inflate_huft *tl, inflate_huft *td, z_streamp z) -{ - inflate_codes_statef *c; - - if ((c = (inflate_codes_statef *) - ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) - { - c->mode = START; - c->lbits = (Byte)bl; - c->dbits = (Byte)bd; - c->ltree = tl; - c->dtree = td; - Tracev(("inflate: codes new\n")); - } - return c; -} - - -int inflate_codes(inflate_blocks_statef *s, z_streamp z, int r) -{ - uInt j; /* temporary storage */ - inflate_huft *t; /* temporary pointer */ - uInt e; /* extra bits or operation */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Byte *p; /* input data pointer */ - uInt n; /* bytes available there */ - Byte *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - Byte *f; /* pointer to copy strings from */ - inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ - - /* copy input/output information to locals (UPDATE macro restores) */ - LOAD - - /* process input and output based on current state */ - while (1) switch (c->mode) - { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ - case START: /* x: set up for LEN */ -#ifndef SLOW - if (m >= 258 && n >= 10) - { - UPDATE - r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); - LOAD - if (r != Z_OK) - { - c->mode = r == Z_STREAM_END ? WASH : BADCODE; - break; - } - } -#endif /* !SLOW */ - c->sub.code.need = c->lbits; - c->sub.code.tree = c->ltree; - c->mode = LEN; - case LEN: /* i: get length/literal/eob next */ - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e == 0) /* literal */ - { - c->sub.lit = t->base; - Tracevv((t->base >= 0x20 && t->base < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", t->base)); - c->mode = LIT; - break; - } - if (e & 16) /* length */ - { - c->sub.copy.get = e & 15; - c->len = t->base; - c->mode = LENEXT; - break; - } - if ((e & 64) == 0) /* next table */ - { - c->sub.code.need = e; - c->sub.code.tree = t + t->base; - break; - } - if (e & 32) /* end of block */ - { - Tracevv(("inflate: end of block\n")); - c->mode = WASH; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = (char*)"invalid literal/length code"; - r = Z_DATA_ERROR; - LEAVE - case LENEXT: /* i: getting length extra (have base) */ - j = c->sub.copy.get; - NEEDBITS(j) - c->len += (uInt)b & inflate_mask[j]; - DUMPBITS(j) - c->sub.code.need = c->dbits; - c->sub.code.tree = c->dtree; - Tracevv(("inflate: length %u\n", c->len)); - c->mode = DIST; - case DIST: /* i: get distance next */ - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e & 16) /* distance */ - { - c->sub.copy.get = e & 15; - c->sub.copy.dist = t->base; - c->mode = DISTEXT; - break; - } - if ((e & 64) == 0) /* next table */ - { - c->sub.code.need = e; - c->sub.code.tree = t + t->base; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = (char*)"invalid distance code"; - r = Z_DATA_ERROR; - LEAVE - case DISTEXT: /* i: getting distance extra */ - j = c->sub.copy.get; - NEEDBITS(j) - c->sub.copy.dist += (uInt)b & inflate_mask[j]; - DUMPBITS(j) - Tracevv(("inflate: distance %u\n", c->sub.copy.dist)); - c->mode = COPY; - case COPY: /* o: copying bytes in window, waiting for space */ -#ifndef __TURBOC__ /* Turbo C bug for following expression */ - f = (uInt)(q - s->window) < c->sub.copy.dist ? - s->end - (c->sub.copy.dist - (q - s->window)) : - q - c->sub.copy.dist; -#else - f = q - c->sub.copy.dist; - if ((uInt)(q - s->window) < c->sub.copy.dist) - f = s->end - (c->sub.copy.dist - (uInt)(q - s->window)); -#endif - while (c->len) - { - NEEDOUT - OUTBYTE(*f++) - if (f == s->end) - f = s->window; - c->len--; - } - c->mode = START; - break; - case LIT: /* o: got literal, waiting for output space */ - NEEDOUT - OUTBYTE(c->sub.lit) - c->mode = START; - break; - case WASH: /* o: got eob, possibly more output */ - if (k > 7) /* return unused byte, if any */ - { - Assert(k < 16, "inflate_codes grabbed too many bytes") - k -= 8; - n++; - p--; /* can always return one */ - } - FLUSH - if (s->read != s->write) - LEAVE - c->mode = END; - case END: - r = Z_STREAM_END; - LEAVE - case BADCODE: /* x: got error */ - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -#ifdef NEED_DUMMY_RETURN - return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ -#endif -} - - -void inflate_codes_free(inflate_codes_statef *c, z_streamp z) -{ - ZFREE(z, c); - Tracev(("inflate: codes free\n")); -} - -/* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#define BASE 65521L /* largest prime smaller than 65536 */ -#define NMAX 5552 -/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ - -#undef DO1 -#undef DO2 -#undef DO4 -#undef DO8 - -#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} -#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); -#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); -#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); -#define DO16(buf) DO8(buf,0); DO8(buf,8); - -/* ========================================================================= */ -uLong adler32(uLong adler, const Byte *buf, uInt len) -{ - unsigned long s1 = adler & 0xffff; - unsigned long s2 = (adler >> 16) & 0xffff; - int k; - - if (buf == Z_NULL) return 1L; - - while (len > 0) { - k = len < NMAX ? len : NMAX; - len -= k; - while (k >= 16) { - DO16(buf); - buf += 16; - k -= 16; - } - if (k != 0) do { - s1 += *buf++; - s2 += s1; - } while (--k); - s1 %= BASE; - s2 %= BASE; - } - return (s2 << 16) | s1; -} - - -/* infblock.h -- header to use infblock.c - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -extern inflate_blocks_statef * inflate_blocks_new OF(( - z_streamp z, - check_func c, /* check function */ - uInt w)); /* window size */ - -extern int inflate_blocks OF(( - inflate_blocks_statef *, - z_streamp , - int)); /* initial return code */ - -extern void inflate_blocks_reset OF(( - inflate_blocks_statef *, - z_streamp , - uLong *)); /* check value on output */ - -extern int inflate_blocks_free OF(( - inflate_blocks_statef *, - z_streamp)); - -extern void inflate_set_dictionary OF(( - inflate_blocks_statef *s, - const Byte *d, /* dictionary */ - uInt n)); /* dictionary length */ - -extern int inflate_blocks_sync_point OF(( - inflate_blocks_statef *s)); - -typedef enum { - imMETHOD, /* waiting for method byte */ - imFLAG, /* waiting for flag byte */ - imDICT4, /* four dictionary check bytes to go */ - imDICT3, /* three dictionary check bytes to go */ - imDICT2, /* two dictionary check bytes to go */ - imDICT1, /* one dictionary check byte to go */ - imDICT0, /* waiting for inflateSetDictionary */ - imBLOCKS, /* decompressing blocks */ - imCHECK4, /* four check bytes to go */ - imCHECK3, /* three check bytes to go */ - imCHECK2, /* two check bytes to go */ - imCHECK1, /* one check byte to go */ - imDONE, /* finished check, done */ - imBAD} /* got an error--stay here */ -inflate_mode; - -/* inflate private state */ -struct internal_state { - - /* mode */ - inflate_mode mode; /* current inflate mode */ - - /* mode dependent information */ - union { - uInt method; /* if FLAGS, method byte */ - struct { - uLong was; /* computed check value */ - uLong need; /* stream check value */ - } check; /* if CHECK, check values to compare */ - uInt marker; /* if BAD, inflateSync's marker bytes count */ - } sub; /* submode */ - - /* mode independent information */ - int nowrap; /* flag for no wrapper */ - uInt wbits; /* log2(window size) (8..15, defaults to 15) */ - inflate_blocks_statef - *blocks; /* current inflate_blocks state */ - -}; - - -int inflateReset(z_streamp z) -{ - if (z == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - z->total_in = z->total_out = 0; - z->msg = Z_NULL; - z->state->mode = z->state->nowrap ? imBLOCKS : imMETHOD; - inflate_blocks_reset(z->state->blocks, z, Z_NULL); - Tracev(("inflate: reset\n")); - return Z_OK; -} - - -int inflateEnd(z_streamp z) -{ - if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) - return Z_STREAM_ERROR; - if (z->state->blocks != Z_NULL) - inflate_blocks_free(z->state->blocks, z); - ZFREE(z, z->state); - z->state = Z_NULL; - Tracev(("inflate: end\n")); - return Z_OK; -} - - - -int inflateInit2_(z_streamp z, int w, const char *version, int stream_size) -{ - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != sizeof(z_stream)) - return Z_VERSION_ERROR; - - /* initialize state */ - if (z == Z_NULL) - return Z_STREAM_ERROR; - z->msg = Z_NULL; - if (z->zalloc == Z_NULL) - { - z->zalloc = (void *(*)(void *, unsigned, unsigned))zcalloc; - z->opaque = (voidp)0; - } - if (z->zfree == Z_NULL) z->zfree = (void (*)(void *, void *))zcfree; - if ((z->state = (struct internal_state *) - ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) - return Z_MEM_ERROR; - z->state->blocks = Z_NULL; - - /* handle undocumented nowrap option (no zlib header or check) */ - z->state->nowrap = 0; - if (w < 0) - { - w = - w; - z->state->nowrap = 1; - } - - /* set window size */ - if (w < 8 || w > 15) - { - inflateEnd(z); - return Z_STREAM_ERROR; - } - z->state->wbits = (uInt)w; - - /* create inflate_blocks state */ - if ((z->state->blocks = - inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) - == Z_NULL) - { - inflateEnd(z); - return Z_MEM_ERROR; - } - Tracev(("inflate: allocated\n")); - - /* reset state */ - inflateReset(z); - return Z_OK; -} - - -int inflateInit_(z_streamp z, const char *version, int stream_size) -{ - return inflateInit2_(z, DEF_WBITS, version, stream_size); -} - - -#define iNEEDBYTE {if(z->avail_in==0)return r;r=f;} -#define iNEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) - -int inflate(z_streamp z, int f) -{ - int r; - uInt b; - - if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) - return Z_STREAM_ERROR; - f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; - r = Z_BUF_ERROR; - while (1) switch (z->state->mode) - { - case imMETHOD: - iNEEDBYTE - if (((z->state->sub.method = iNEXTBYTE) & 0xf) != Z_DEFLATED) - { - z->state->mode = imBAD; - z->msg = (char*)"unknown compression method"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - if ((z->state->sub.method >> 4) + 8 > z->state->wbits) - { - z->state->mode = imBAD; - z->msg = (char*)"invalid window size"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - z->state->mode = imFLAG; - case imFLAG: - iNEEDBYTE - b = iNEXTBYTE; - if (((z->state->sub.method << 8) + b) % 31) - { - z->state->mode = imBAD; - z->msg = (char*)"incorrect header check"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - Tracev(("inflate: zlib header ok\n")); - if (!(b & PRESET_DICT)) - { - z->state->mode = imBLOCKS; - break; - } - z->state->mode = imDICT4; - case imDICT4: - iNEEDBYTE - z->state->sub.check.need = (uLong)iNEXTBYTE << 24; - z->state->mode = imDICT3; - case imDICT3: - iNEEDBYTE - z->state->sub.check.need += (uLong)iNEXTBYTE << 16; - z->state->mode = imDICT2; - case imDICT2: - iNEEDBYTE - z->state->sub.check.need += (uLong)iNEXTBYTE << 8; - z->state->mode = imDICT1; - case imDICT1: - iNEEDBYTE - z->state->sub.check.need += (uLong)iNEXTBYTE; - z->adler = z->state->sub.check.need; - z->state->mode = imDICT0; - return Z_NEED_DICT; - case imDICT0: - z->state->mode = imBAD; - z->msg = (char*)"need dictionary"; - z->state->sub.marker = 0; /* can try inflateSync */ - return Z_STREAM_ERROR; - case imBLOCKS: - r = inflate_blocks(z->state->blocks, z, r); - if (r == Z_DATA_ERROR) - { - z->state->mode = imBAD; - z->state->sub.marker = 0; /* can try inflateSync */ - break; - } - if (r == Z_OK) - r = f; - if (r != Z_STREAM_END) - return r; - r = f; - inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); - if (z->state->nowrap) - { - z->state->mode = imDONE; - break; - } - z->state->mode = imCHECK4; - case imCHECK4: - iNEEDBYTE - z->state->sub.check.need = (uLong)iNEXTBYTE << 24; - z->state->mode = imCHECK3; - case imCHECK3: - iNEEDBYTE - z->state->sub.check.need += (uLong)iNEXTBYTE << 16; - z->state->mode = imCHECK2; - case imCHECK2: - iNEEDBYTE - z->state->sub.check.need += (uLong)iNEXTBYTE << 8; - z->state->mode = imCHECK1; - case imCHECK1: - iNEEDBYTE - z->state->sub.check.need += (uLong)iNEXTBYTE; - - if (z->state->sub.check.was != z->state->sub.check.need) - { - z->state->mode = imBAD; - z->msg = (char*)"incorrect data check"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - Tracev(("inflate: zlib check ok\n")); - z->state->mode = imDONE; - case imDONE: - return Z_STREAM_END; - case imBAD: - return Z_DATA_ERROR; - default: - return Z_STREAM_ERROR; - } -#ifdef NEED_DUMMY_RETURN - return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ -#endif -} - - -int inflateSetDictionary(z_streamp z, const Byte *dictionary, uInt dictLength) -{ - uInt length = dictLength; - - if (z == Z_NULL || z->state == Z_NULL || z->state->mode != imDICT0) - return Z_STREAM_ERROR; - - if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; - z->adler = 1L; - - if (length >= ((uInt)1<state->wbits)) - { - length = (1<state->wbits)-1; - dictionary += dictLength - length; - } - inflate_set_dictionary(z->state->blocks, dictionary, length); - z->state->mode = imBLOCKS; - return Z_OK; -} - - -int inflateSync(z_streamp z) -{ - uInt n; /* number of bytes to look at */ - Byte *p; /* pointer to bytes */ - uInt m; /* number of marker bytes found in a row */ - uLong r, w; /* temporaries to save total_in and total_out */ - - /* set up */ - if (z == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - if (z->state->mode != imBAD) - { - z->state->mode = imBAD; - z->state->sub.marker = 0; - } - if ((n = z->avail_in) == 0) - return Z_BUF_ERROR; - p = z->next_in; - m = z->state->sub.marker; - - /* search */ - while (n && m < 4) - { - static const Byte mark[4] = {0, 0, 0xff, 0xff}; - if (*p == mark[m]) - m++; - else if (*p) - m = 0; - else - m = 4 - m; - p++, n--; - } - - /* restore */ - z->total_in += p - z->next_in; - z->next_in = p; - z->avail_in = n; - z->state->sub.marker = m; - - /* return no joy or set up to restart on a new block */ - if (m != 4) - return Z_DATA_ERROR; - r = z->total_in; w = z->total_out; - inflateReset(z); - z->total_in = r; z->total_out = w; - z->state->mode = imBLOCKS; - return Z_OK; -} - - -/* Returns true if inflate is currently at the end of a block generated - * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP - * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH - * but removes the length bytes of the resulting empty stored block. When - * decompressing, PPP checks that at the end of input packet, inflate is - * waiting for these length bytes. - */ -int inflateSyncPoint(z_streamp z) -{ - if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL) - return Z_STREAM_ERROR; - return inflate_blocks_sync_point(z->state->blocks); -} - -voidp zcalloc (voidp opaque, unsigned items, unsigned size) -{ - if (opaque) items += size - size; /* make compiler happy */ - return (voidp)malloc(items*size); -} - -void zcfree (voidp opaque, voidp ptr) -{ - free(ptr); - if (opaque) return; /* make compiler happy */ -} - +/***************************************************************************** + * name: unzip.c + * + * desc: IO on .zip files using portions of zlib + * + * + *****************************************************************************/ + +#include +#include +#include +#include "unzip-vfspk3.h" + +typedef unsigned char byte; + +/* unzip.h -- IO for uncompress .zip files using zlib + Version 0.15 beta, Mar 19th, 1998, + + Copyright (C) 1998 Gilles Vollant + + This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + Encryption and multi volume ZipFile (span) are not supported. + Old compressions used by old PKZip 1.x are not supported + + THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE + CAN CHANGE IN FUTURE VERSION !! + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + +*/ +/* for more info about .ZIP format, see + ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip */ + +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.1.3, July 9th, 1998 + + Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + + +#ifndef _ZCONF_H +#define _ZCONF_H + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +#define OF(args) args +#endif + +typedef unsigned char Byte; /* 8 bits */ +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ +typedef Byte *voidp; + +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#endif /* _ZCONF_H */ + +#define ZLIB_VERSION "1.1.3" + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +/* Allowed flush values; see deflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +const char * zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +int deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +int deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + 0.1% larger than avail_in plus 12 bytes. If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so (that is, total_in bytes). + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). +*/ + + +int deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +int inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +int inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may some + introduce some output latency (reading input without producing any output) + except when forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much + output as possible to the output buffer. The flushing behavior of inflate is + not specified for values of the flush parameter other than Z_SYNC_FLUSH + and Z_FINISH, but the current implementation actually flushes as much output + as possible anyway. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster routine + may be used for the single inflate() call. + + If a preset dictionary is needed at this point (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the + dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise + it sets strm->adler to the adler32 checksum of all output produced + so (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or + an error code as described below. At the end of the stream, inflate() + checks that its computed adler32 checksum is equal to that saved by the + compressor and returns Z_STREAM_END only if the checksum is correct. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect + adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent + (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if no progress is possible or if there was not + enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR + case, the application may then call inflateSync to look for a good + compression block. +*/ + + +int inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +int deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match). Filtered data consists mostly of small values with a + somewhat random distribution. In this case, the compression algorithm is + tuned to compress them better. The effect of Z_FILTERED is to force more + Huffman coding and less string matching; it is somewhat intermediate + between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects + the compression ratio but not the correctness of the compressed output even + if it is not set appropriately. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +int deflateSetDictionary OF((z_streamp strm, + const Byte *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. + + Upon return of this function, strm->adler is set to the Adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +int deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +int deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +int deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +/* +int inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. If a compressed stream with a larger window size is given as + input, inflate() will return with the error code Z_DATA_ERROR instead of + trying to allocate a larger window. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative + memLevel). msg is set to null if there is no error message. inflateInit2 + does not perform any decompression apart from reading the zlib header if + present: this will be done by inflate(). (So next_in and avail_in may be + modified, but next_out and avail_out are unchanged.) +*/ + +int inflateSetDictionary OF((z_streamp strm, + const Byte *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate + if this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +int inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +int inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +int compress OF((Byte *dest, uLong *destLen, + const Byte *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least 0.1% larger than + sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +int compress2 OF((Byte *dest, uLong *destLen, + const Byte *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +int uncompress OF((Byte *dest, uLong *destLen, + const Byte *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ + + +typedef voidp gzFile; + +gzFile gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h". (See the description + of deflateInit2 for more information about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +gzFile gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +int gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +int gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +int gzwrite OF((gzFile file, + const voidp buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +int gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ + +int gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +char * gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +int gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +int gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +int gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +long gzseek OF((gzFile file, + long offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +int gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +long gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +int gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +int gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +const char * gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +uLong adler32 OF((uLong adler, const Byte *buf, uInt len)); + +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +uLong crc32 OF((uLong crc, const Byte *buf, uInt len)); +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +// private stuff to not include cmdlib.h +/* +============================================================================ + + BYTE ORDER FUNCTIONS + +============================================================================ +*/ + +#ifdef _SGI_SOURCE +#define __BIG_ENDIAN__ +#endif + +#ifdef __BIG_ENDIAN__ + +short __LittleShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short __BigShort (short l) +{ + return l; +} + + +int __LittleLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int __BigLong (int l) +{ + return l; +} + + +float __LittleFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float __BigFloat (float l) +{ + return l; +} + + +#else + + +short __BigShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short __LittleShort (short l) +{ + return l; +} + + +int __BigLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int __LittleLong (int l) +{ + return l; +} + +float __BigFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float __LittleFloat (float l) +{ + return l; +} + + + +#endif + + + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +int deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +int inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +int deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +int inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) + + +const char * zError OF((int err)); +int inflateSyncPoint OF((z_streamp z)); +const uLong * get_crc_table OF((void)); + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + + /* Common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#define zmemcpy memcpy +#define zmemcmp memcmp +#define zmemzero(dest, len) memset(dest, 0, len) + +/* Diagnostic functions */ +#ifdef _ZIP_DEBUG_ + int z_verbose = 0; +# define Assert(cond,msg) assert(cond); + //{if(!(cond)) Sys_Error(msg);} +# define Trace(x) {if (z_verbose>=0) Sys_Error x ;} +# define Tracev(x) {if (z_verbose>0) Sys_Error x ;} +# define Tracevv(x) {if (z_verbose>1) Sys_Error x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) Sys_Error x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) Sys_Error x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +typedef uLong (*check_func) OF((uLong check, const Byte *buf, uInt len)); +voidp zcalloc OF((voidp opaque, unsigned items, unsigned size)); +void zcfree OF((voidp opaque, voidp ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidp)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + + +#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \ + !defined(CASESENSITIVITYDEFAULT_NO) +#define CASESENSITIVITYDEFAULT_NO +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (65536) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + +/* +static int unzlocal_getByte(FILE *fin,int *pi) +{ + unsigned char c; + int err = fread(&c, 1, 1, fin); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ferror(fin)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} +*/ + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +static int unzlocal_getShort (FILE* fin, uLong *pX) +{ + short v; + + fread( &v, sizeof(v), 1, fin ); + + *pX = __LittleShort( v); + return UNZ_OK; + +/* + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +*/ +} + +static int unzlocal_getLong (FILE *fin, uLong *pX) +{ + int v; + + fread( &v, sizeof(v), 1, fin ); + + *pX = __LittleLong( v); + return UNZ_OK; + +/* + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +*/ +} + + +/* My own strcmpi / strcasecmp */ +static int strcmpcasenosensitive_internal (const char* fileName1,const char* fileName2) +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int unzStringFileNameCompare (const char* fileName1,const char* fileName2,int iCaseSensitivity) +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#define BUFREADCOMMENT (0x400) + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +static uLong unzlocal_SearchCentralDir(FILE *fin) +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack=0xffff; /* maximum size of global comment */ + uLong uPosFound=0; + + if (fseek(fin,0,SEEK_END) != 0) + return 0; + + + uSizeFile = ftell( fin ); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)malloc(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (fseek(fin,uReadPos,SEEK_SET)!=0) + break; + + if (fread(buf,(uInt)uReadSize,1,fin)!=1) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + free(buf); + return uPosFound; +} + +extern unzFile unzReOpen (const char* path, unzFile file) +{ + unz_s *s; + FILE * fin; + + fin=fopen(path,"rb"); + if (fin==NULL) + return NULL; + + s=(unz_s*)malloc(sizeof(unz_s)); + memcpy(s, (unz_s*)file, sizeof(unz_s)); + + s->file = fin; + return (unzFile)s; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer + "zlib/zlib109.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +extern unzFile unzOpen (const char* path) +{ + unz_s us; + unz_s *s; + uLong central_pos,uL; + FILE * fin ; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + fin=fopen(path,"rb"); + if (fin==NULL) + return NULL; + + central_pos = unzlocal_SearchCentralDir(fin); + if (central_pos==0) + err=UNZ_ERRNO; + + if (fseek(fin,central_pos,SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unzlocal_getLong(fin,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir */ + if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* zipfile comment length */ + if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + fclose(s->file); + free(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int unzGetGlobalInfo (unzFile file,unz_global_info *pglobal_info) +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + + +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +static void unzlocal_DosDateToTmuDate (uLong ulDosDate, tm_unz* ptm) +{ + uLong uDate; + uDate = (uLong)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +static int unzlocal_GetCurrentFileInfoInternal (unzFile file, + unz_file_info *pfile_info, + unz_file_info_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize) +{ + unz_s* s; + unz_file_info file_info; + unz_file_info_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + + if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + + if ((err==UNZ_OK) && (extraField!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_extrafile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek += file_info.size_file_extra - uSizeRead; + } + else + lSeek+=file_info.size_file_extra; + + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentfile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int unzGetCurrentFileInfo ( unzFile file, unz_file_info *pfile_info, + char *szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char *szComment, uLong commentBufferSize) +{ + return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int unzGoToFirstFile (unzFile file) +{ + int err=UNZ_OK; + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int unzGoToNextFile (unzFile file) +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) +{ + unz_s* s; + int err; + + + uLong num_fileSaved; + uLong pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + unzGetCurrentFileInfo(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + return err; +} + + +/* + Read the static header of the current zipfile + Check the coherency of the static header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in static header + (filename and size of extra field data) +*/ +static int unzlocal_CheckCurrentFileCoherencyHeader (unz_s* s, uInt* piSizeVar, + uLong *poffset_local_extrafield, + uInt *psize_local_extrafield) +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (fseek(s->file,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + + if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int unzOpenCurrentFile (unzFile file) +{ + int err=UNZ_OK; + int Store; + uInt iSizeVar; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uLong offset_local_extrafield; /* offset of the static extra field */ + uInt size_local_extrafield; /* size of the static extra field */ + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, + &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip_read_info_s*) + malloc(sizeof(file_in_zip_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)malloc(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + free(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if ((s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + Store = s->cur_file_info.compression_method==0; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->compression_method = + s->cur_file_info.compression_method; + pfile_in_zip_read_info->file=s->file; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if (!Store) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidp)0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=1; + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + + s->pfile_in_zip_read = pfile_in_zip_read_info; + return UNZ_OK; +} + + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int unzReadCurrentFile (unzFile file, void *buf, unsigned len) +{ + int err=UNZ_OK; + uInt iRead = 0; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->read_buffer == NULL)) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Byte*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if (len>pfile_in_zip_read_info->rest_read_uncompressed) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (s->cur_file_info.compressed_size == pfile_in_zip_read_info->rest_read_compressed) + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + if (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1, + pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Byte*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if (pfile_in_zip_read_info->compression_method==0) + { + uInt uDoCopy,i ; + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else + { + uLong uTotalOutBefore,uTotalOutAfter; + const Byte *bufBefore; + uLong uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern long unztell (unzFile file) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (long)pfile_in_zip_read_info->stream.total_out; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int unzeof (unzFile file) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the static-header version of the extra field (sometimes, there is + more info in the static-header version than in the central-header) + + if buf==NULL, it return the size of the static extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int unzGetLocalExtrafield (unzFile file,void *buf,unsigned len) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uInt read_now; + uLong size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int unzCloseCurrentFile (unzFile file) +{ + int err=UNZ_OK; + + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + free(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised) + inflateEnd(&pfile_in_zip_read_info->stream); + + pfile_in_zip_read_info->stream_initialised = 0; + free(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int unzGetGlobalComment (unzFile file, char *szComment, uLong uSizeBuf) +{ + unz_s* s; + uLong uReadThis ; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (fseek(s->file,s->central_pos+22,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (fread(szComment,(uInt)uReadThis,1,s->file)!=1) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + + +#ifdef DYNAMIC_CRC_TABLE + +static int crc_table_empty = 1; +static uLong crc_table[256]; +static void make_crc_table OF((void)); + +/* + Generate a table for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The table is simply the CRC of all possible eight bit values. This is all + the information needed to generate CRC's on data a byte at a time for all + combinations of CRC register values and incoming bytes. +*/ +static void make_crc_table() +{ + uLong c; + int n, k; + uLong poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* make exclusive-or pattern from polynomial (0xedb88320L) */ + poly = 0L; + for (n = 0; n < sizeof(p)/sizeof(Byte); n++) + poly |= 1L << (31 - p[n]); + + for (n = 0; n < 256; n++) + { + c = (uLong)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[n] = c; + } + crc_table_empty = 0; +} +#else +/* ======================================================================== + * Table of CRC-32's of all single-byte values (made by make_crc_table) + */ +static const uLong crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; +#endif + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const uLong * get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) make_crc_table(); +#endif + return (const uLong *)crc_table; +} + +/* ========================================================================= */ +#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); + +/* ========================================================================= */ +uLong crc32(uLong crc, const Byte *buf, uInt len) +{ + if (buf == Z_NULL) return 0L; +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif + crc = crc ^ 0xffffffffL; + while (len >= 8) + { + DO8(buf); + len -= 8; + } + if (len) do { + DO1(buf); + } while (--len); + return crc ^ 0xffffffffL; +} + +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_blocks_state; +typedef struct inflate_blocks_state inflate_blocks_statef; + +extern inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +extern int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +extern void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLong *)); /* check value on output */ + +extern int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp)); + +extern void inflate_set_dictionary OF(( + inflate_blocks_statef *s, + const Byte *d, /* dictionary */ + uInt n)); /* dictionary length */ + +extern int inflate_blocks_sync_point OF(( + inflate_blocks_statef *s)); + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* Table for deflate from PKZIP's appnote.txt. */ +static const uInt border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). */ + +typedef struct inflate_huft_s inflate_huft; + +struct inflate_huft_s { + union { + struct { + Byte Exop; /* number of extra bits or operation */ + Byte Bits; /* number of bits in this code or subcode */ + } what; + uInt pad; /* pad structure to a power of 2 (4 bytes for */ + } word; /* 16-bit, 8 bytes for 32-bit int's) */ + uInt base; /* literal, length base, distance base, + or table offset */ +}; + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1004 huft structures (850 for length/literals + and 154 for distances, the latter actually the result of an + exhaustive search). The actual maximum is not known, but the + value below is more than safe. */ +#define MANY 1440 + +extern int inflate_trees_bits OF(( + uInt *, /* 19 code lengths */ + uInt *, /* bits tree desired/actual depth */ + inflate_huft * *, /* bits tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +extern int inflate_trees_dynamic OF(( + uInt, /* number of literal/length codes */ + uInt, /* number of distance codes */ + uInt *, /* that many (total) code lengths */ + uInt *, /* literal desired/actual bit depth */ + uInt *, /* distance desired/actual bit depth */ + inflate_huft * *, /* literal/length tree result */ + inflate_huft * *, /* distance tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +extern int inflate_trees_fixed OF(( + uInt *, /* literal desired/actual bit depth */ + uInt *, /* distance desired/actual bit depth */ + inflate_huft * *, /* literal/length tree result */ + inflate_huft * *, /* distance tree result */ + z_streamp)); /* for memory allocation */ + + +/* infcodes.h -- header to use infcodes.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_codes_state; +typedef struct inflate_codes_state inflate_codes_statef; + +extern inflate_codes_statef *inflate_codes_new OF(( + uInt, uInt, + inflate_huft *, inflate_huft *, + z_streamp )); + +extern int inflate_codes OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +extern void inflate_codes_free OF(( + inflate_codes_statef *, + z_streamp )); + +/* infutil.h -- types and macros common to blocks and codes + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#ifndef _INFUTIL_H +#define _INFUTIL_H + +typedef enum { + TYPE, /* get type bits (3, including end bit) */ + LENS, /* get lengths for stored */ + STORED, /* processing stored block */ + TABLE, /* get table lengths */ + BTREE, /* get bit lengths tree for a dynamic block */ + DTREE, /* get length, distance trees for a dynamic block */ + CODES, /* processing fixed or dynamic block */ + DRY, /* output remaining window bytes */ + DONE, /* finished last block, done */ + BAD} /* got a data error--stuck here */ +inflate_block_mode; + +/* inflate blocks semi-private state */ +struct inflate_blocks_state { + + /* mode */ + inflate_block_mode mode; /* current inflate_block mode */ + + /* mode dependent information */ + union { + uInt left; /* if STORED, bytes left to copy */ + struct { + uInt table; /* table lengths (14 bits) */ + uInt index; /* index into blens (or border) */ + uInt *blens; /* bit lengths of codes */ + uInt bb; /* bit length tree depth */ + inflate_huft *tb; /* bit length decoding tree */ + } trees; /* if DTREE, decoding info for trees */ + struct { + inflate_codes_statef + *codes; + } decode; /* if CODES, current state */ + } sub; /* submode */ + uInt last; /* true if this block is the last block */ + + /* mode independent information */ + uInt bitk; /* bits in bit buffer */ + uLong bitb; /* bit buffer */ + inflate_huft *hufts; /* single malloc for tree space */ + Byte *window; /* sliding window */ + Byte *end; /* one byte after sliding window */ + Byte *read; /* window read pointer */ + Byte *write; /* window write pointer */ + check_func checkfn; /* check function */ + uLong check; /* check on output */ + +}; + + +/* defines for inflate input/output */ +/* update pointers and return */ +#define UPDBITS {s->bitb=b;s->bitk=k;} +#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} +#define UPDOUT {s->write=q;} +#define UPDATE {UPDBITS UPDIN UPDOUT} +#define LEAVE {UPDATE return inflate_flush(s,z,r);} +/* get bytes and bits */ +#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} +#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} +#define NEXTBYTE (n--,*p++) +#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} +/* output bytes */ +#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) +#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} +#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} +#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} +#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} +#define OUTBYTE(a) {*q++=(Byte)(a);m--;} +/* load static pointers */ +#define LOAD {LOADIN LOADOUT} + +/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ +extern uInt inflate_mask[17]; + +/* copy as much as possible from the sliding window to the output area */ +extern int inflate_flush OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +#endif + + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarily, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + + +void inflate_blocks_reset(inflate_blocks_statef *s, z_streamp z, uLong *c) +{ + if (c != Z_NULL) + *c = s->check; + if (s->mode == BTREE || s->mode == DTREE) + ZFREE(z, s->sub.trees.blens); + if (s->mode == CODES) + inflate_codes_free(s->sub.decode.codes, z); + s->mode = TYPE; + s->bitk = 0; + s->bitb = 0; + s->read = s->write = s->window; + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(0L, (const Byte *)Z_NULL, 0); + Tracev(("inflate: blocks reset\n")); +} + + +inflate_blocks_statef *inflate_blocks_new(z_streamp z, check_func c, uInt w) +{ + inflate_blocks_statef *s; + + if ((s = (inflate_blocks_statef *)ZALLOC + (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) + return s; + if ((s->hufts = + (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) + { + ZFREE(z, s); + return Z_NULL; + } + if ((s->window = (Byte *)ZALLOC(z, 1, w)) == Z_NULL) + { + ZFREE(z, s->hufts); + ZFREE(z, s); + return Z_NULL; + } + s->end = s->window + w; + s->checkfn = c; + s->mode = TYPE; + Tracev(("inflate: blocks allocated\n")); + inflate_blocks_reset(s, z, Z_NULL); + return s; +} + + +int inflate_blocks(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt t; /* temporary storage */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Byte *p; /* input data pointer */ + uInt n; /* bytes available there */ + Byte *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input based on current state */ + while (1) switch (s->mode) + { + case TYPE: + NEEDBITS(3) + t = (uInt)b & 7; + s->last = t & 1; + switch (t >> 1) + { + case 0: /* stored */ + Tracev(("inflate: stored block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + t = k & 7; /* go to byte boundary */ + DUMPBITS(t) + s->mode = LENS; /* get length of stored block */ + break; + case 1: /* fixed */ + Tracev(("inflate: fixed codes block%s\n", + s->last ? " (last)" : "")); + { + uInt bl, bd; + inflate_huft *tl, *td; + + inflate_trees_fixed(&bl, &bd, &tl, &td, z); + s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); + if (s->sub.decode.codes == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + } + DUMPBITS(3) + s->mode = CODES; + break; + case 2: /* dynamic */ + Tracev(("inflate: dynamic codes block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + s->mode = TABLE; + break; + case 3: /* illegal */ + DUMPBITS(3) + s->mode = BAD; + z->msg = (char*)"invalid block type"; + r = Z_DATA_ERROR; + LEAVE + } + break; + case LENS: + NEEDBITS(32) + if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) + { + s->mode = BAD; + z->msg = (char*)"invalid stored block lengths"; + r = Z_DATA_ERROR; + LEAVE + } + s->sub.left = (uInt)b & 0xffff; + b = k = 0; /* dump bits */ + Tracev(("inflate: stored length %u\n", s->sub.left)); + s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); + break; + case STORED: + if (n == 0) + LEAVE + NEEDOUT + t = s->sub.left; + if (t > n) t = n; + if (t > m) t = m; + zmemcpy(q, p, t); + p += t; n -= t; + q += t; m -= t; + if ((s->sub.left -= t) != 0) + break; + Tracev(("inflate: stored end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + s->mode = s->last ? DRY : TYPE; + break; + case TABLE: + NEEDBITS(14) + s->sub.trees.table = t = (uInt)b & 0x3fff; +#ifndef PKZIP_BUG_WORKAROUND + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) + { + s->mode = BAD; + z->msg = (char*)"too many length or distance symbols"; + r = Z_DATA_ERROR; + LEAVE + } +#endif + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if ((s->sub.trees.blens = (uInt*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + DUMPBITS(14) + s->sub.trees.index = 0; + Tracev(("inflate: table sizes ok\n")); + s->mode = BTREE; + case BTREE: + while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) + { + NEEDBITS(3) + s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; + DUMPBITS(3) + } + while (s->sub.trees.index < 19) + s->sub.trees.blens[border[s->sub.trees.index++]] = 0; + s->sub.trees.bb = 7; + t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, + &s->sub.trees.tb, s->hufts, z); + if (t != Z_OK) + { + ZFREE(z, s->sub.trees.blens); + r = t; + if (r == Z_DATA_ERROR) + s->mode = BAD; + LEAVE + } + s->sub.trees.index = 0; + Tracev(("inflate: bits tree ok\n")); + s->mode = DTREE; + case DTREE: + while (t = s->sub.trees.table, + s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) + { + inflate_huft *h; + uInt i, j, c; + + t = s->sub.trees.bb; + NEEDBITS(t) + h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); + t = h->bits; + c = h->base; + if (c < 16) + { + DUMPBITS(t) + s->sub.trees.blens[s->sub.trees.index++] = c; + } + else /* c == 16..18 */ + { + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + NEEDBITS(t + i) + DUMPBITS(t) + j += (uInt)b & inflate_mask[i]; + DUMPBITS(i) + i = s->sub.trees.index; + t = s->sub.trees.table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)) + { + ZFREE(z, s->sub.trees.blens); + s->mode = BAD; + z->msg = (char*)"invalid bit length repeat"; + r = Z_DATA_ERROR; + LEAVE + } + c = c == 16 ? s->sub.trees.blens[i - 1] : 0; + do { + s->sub.trees.blens[i++] = c; + } while (--j); + s->sub.trees.index = i; + } + } + s->sub.trees.tb = Z_NULL; + { + uInt bl, bd; + inflate_huft *tl, *td; + inflate_codes_statef *c; + + bl = 9; /* must be <= 9 for lookahead assumptions */ + bd = 6; /* must be <= 9 for lookahead assumptions */ + t = s->sub.trees.table; + t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + s->sub.trees.blens, &bl, &bd, &tl, &td, + s->hufts, z); + ZFREE(z, s->sub.trees.blens); + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) + s->mode = BAD; + r = t; + LEAVE + } + Tracev(("inflate: trees ok\n")); + if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.codes = c; + } + s->mode = CODES; + case CODES: + UPDATE + if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) + return inflate_flush(s, z, r); + r = Z_OK; + inflate_codes_free(s->sub.decode.codes, z); + LOAD + Tracev(("inflate: codes end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + if (!s->last) + { + s->mode = TYPE; + break; + } + s->mode = DRY; + case DRY: + FLUSH + if (s->read != s->write) + LEAVE + s->mode = DONE; + case DONE: + r = Z_STREAM_END; + LEAVE + case BAD: + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +int inflate_blocks_free(inflate_blocks_statef *s, z_streamp z) +{ + inflate_blocks_reset(s, z, Z_NULL); + ZFREE(z, s->window); + ZFREE(z, s->hufts); + ZFREE(z, s); + Tracev(("inflate: blocks freed\n")); + return Z_OK; +} + + +void inflate_set_dictionary(inflate_blocks_statef *s, const Byte *d, uInt n) +{ + zmemcpy(s->window, d, n); + s->read = s->write = s->window + n; +} + + +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. + * IN assertion: s != Z_NULL + */ +int inflate_blocks_sync_point(inflate_blocks_statef *s) +{ + return s->mode == LENS; +} + +/* And'ing with mask[n] masks the lower n bits */ +uInt inflate_mask[17] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +/* copy as much as possible from the sliding window to the output area */ +int inflate_flush(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt n; + Byte *p; + Byte *q; + + /* static copies of source and destination pointers */ + p = z->next_out; + q = s->read; + + /* compute number of bytes to copy as as end of window */ + n = (uInt)((q <= s->write ? s->write : s->end) - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy as as end of window */ + zmemcpy(p, q, n); + p += n; + q += n; + + /* see if more to copy at beginning of window */ + if (q == s->end) + { + /* wrap pointers */ + q = s->window; + if (s->write == s->end) + s->write = s->window; + + /* compute bytes to copy */ + n = (uInt)(s->write - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy */ + zmemcpy(p, q, n); + p += n; + q += n; + } + + /* update pointers */ + z->next_out = p; + s->read = q; + + /* done */ + return r; +} + +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +const char inflate_copyright[] = + " inflate 1.1.3 Copyright 1995-1998 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + + +static int huft_build OF(( + uInt *, /* code lengths in bits */ + uInt, /* number of codes */ + uInt, /* number of "simple" codes */ + const uInt *, /* list of base values for non-simple codes */ + const uInt *, /* list of extra bits for non-simple codes */ + inflate_huft **, /* result: starting table */ + uInt *, /* maximum lookup bits (returns actual) */ + inflate_huft *, /* space for trees */ + uInt *, /* hufts used in space */ + uInt * )); /* space for values */ + +/* Tables for deflate from PKZIP's appnote.txt. */ +static const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* see note #13 above about 258 */ +static const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ +static const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +static const uInt cpdext[30] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ +#define BMAX 15 /* maximum bit length of any code */ + +static int huft_build(uInt *b, uInt n, uInt s, const uInt *d, const uInt *e, inflate_huft ** t, uInt *m, inflate_huft *hp, uInt *hn, uInt *v) +//uInt *b; /* code lengths in bits (all assumed <= BMAX) */ +//uInt n; /* number of codes (assumed <= 288) */ +//uInt s; /* number of simple-valued codes (0..s-1) */ +//const uInt *d; /* list of base values for non-simple codes */ +//const uInt *e; /* list of extra bits for non-simple codes */ +//inflate_huft ** t; /* result: starting table */ +//uInt *m; /* maximum lookup bits, returns actual */ +//inflate_huft *hp; /* space for trees */ +//uInt *hn; /* hufts used in space */ +//uInt *v; /* working area: values in order of bit length */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + if the given code set is incomplete (the tables are still built in this + case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of + lengths), or Z_MEM_ERROR if not enough memory. */ +{ + + uInt a; /* counter for codes of length k */ + uInt c[BMAX+1]; /* bit length count table */ + uInt f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register uInt i; /* counter, current code */ + register uInt j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */ + register uInt *p; /* pointer into c[], b[], or v[] */ + inflate_huft *q; /* points to current table */ + struct inflate_huft_s r; /* table entry for structure assignment */ + inflate_huft *u[BMAX]; /* table stack */ + register int w; /* bits before this table == (l * h) */ + uInt x[BMAX+1]; /* bit offsets, then code stack */ + uInt *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + uInt z; /* number of entries in current table */ + + + /* Generate counts for each bit length */ + p = c; +#define C0 *p++ = 0; +#define C2 C0 C0 C0 C0 +#define C4 C2 C2 C2 C2 + C4 /* clear c[]--assume BMAX+1 is 16 */ + p = b; i = n; + do { + c[*p++]++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (inflate_huft *)Z_NULL; + *m = 0; + return Z_OK; + } + + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((uInt)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((uInt)l > i) + l = i; + *m = l; + + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return Z_DATA_ERROR; + if ((y -= c[i]) < 0) + return Z_DATA_ERROR; + c[i] += y; + + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + n = x[g]; /* set n to length of v */ + + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ + q = (inflate_huft *)Z_NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = g - w; + z = z > (uInt)l ? l : z; /* table size upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + if (j < z) + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate new table */ + if (*hn + z > MANY) /* (note: doesn't matter for fixed) */ + return Z_MEM_ERROR; /* not enough memory */ + u[h] = q = hp + *hn; + *hn += z; + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.bits = (Byte)l; /* bits to dump before this table */ + r.exop = (Byte)j; /* bits in this table */ + j = i >> (w - l); + r.base = (uInt)(q - u[h-1] - j); /* offset to this table */ + u[h-1][j] = r; /* connect to last table */ + } + else + *t = q; /* first table is returned result */ + } + + /* set up table entry in r */ + r.bits = (Byte)(k - w); + if (p >= v + n) + r.exop = 128 + 64; /* out of values--invalid code */ + else if (*p < s) + { + r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ + r.base = *p++; /* simple code is just the value */ + } + else + { + r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ + r.base = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + mask = (1 << w) - 1; /* needed on HP, cc -O bug */ + while ((i & mask) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + mask = (1 << w) - 1; + } + } + } + + + /* Return Z_BUF_ERROR if we were given an incomplete table */ + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; +} + + +int inflate_trees_bits(uInt *c, uInt *bb, inflate_huft * *tb, inflate_huft *hp, z_streamp z) +//uInt *c; /* 19 code lengths */ +//uInt *bb; /* bits tree desired/actual depth */ +//inflate_huft * *tb; /* bits tree result */ +//inflate_huft *hp; /* space for trees */ +//z_streamp z; /* for messages */ +{ + int r; + uInt hn = 0; /* hufts used in space */ + uInt *v; /* work area for huft_build */ + + if ((v = (uInt*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + r = huft_build(c, 19, 19, (uInt*)Z_NULL, (uInt*)Z_NULL, + tb, bb, hp, &hn, v); + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed dynamic bit lengths tree"; + else if (r == Z_BUF_ERROR || *bb == 0) + { + z->msg = (char*)"incomplete dynamic bit lengths tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +} + + +int inflate_trees_dynamic(uInt nl, uInt nd, uInt *c, uInt *bl, uInt *bd, inflate_huft * *tl, inflate_huft * *td, inflate_huft *hp, z_streamp z) +//uInt nl; /* number of literal/length codes */ +//uInt nd; /* number of distance codes */ +//uInt *c; /* that many (total) code lengths */ +//uInt *bl; /* literal desired/actual bit depth */ +//uInt *bd; /* distance desired/actual bit depth */ +//inflate_huft * *tl; /* literal/length tree result */ +//inflate_huft * *td; /* distance tree result */ +//inflate_huft *hp; /* space for trees */ +//z_streamp z; /* for messages */ +{ + int r; + uInt hn = 0; /* hufts used in space */ + uInt *v; /* work area for huft_build */ + + /* allocate work area */ + if ((v = (uInt*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + + /* build literal/length tree */ + r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); + if (r != Z_OK || *bl == 0) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed literal/length tree"; + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; + } + + /* build distance tree */ + r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); + if (r != Z_OK || (*bd == 0 && nl > 257)) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed distance tree"; + else if (r == Z_BUF_ERROR) { +#ifdef PKZIP_BUG_WORKAROUND + r = Z_OK; + } +#else + z->msg = (char*)"incomplete distance tree"; + r = Z_DATA_ERROR; + } + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"empty distance tree with lengths"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +#endif + } + + /* done */ + ZFREE(z, v); + return Z_OK; +} + +/* inffixed.h -- table for decoding fixed codes + * Generated automatically by the maketree.c program + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +static uInt fixed_bl = 9; +static uInt fixed_bd = 5; +static inflate_huft fixed_tl[] = { + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} + }; +static inflate_huft fixed_td[] = { + {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, + {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, + {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, + {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, + {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, + {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, + {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, + {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} + }; + +int inflate_trees_fixed(uInt *bl, uInt *bd, inflate_huft * *tl, inflate_huft * *td, z_streamp z) +//uInt *bl; /* literal desired/actual bit depth */ +//uInt *bd; /* distance desired/actual bit depth */ +//inflate_huft * *tl; /* literal/length tree result */ +//inflate_huft * *td; /* distance tree result */ +//z_streamp z; /* for memory allocation */ +{ + *bl = fixed_bl; + *bd = fixed_bd; + *tl = fixed_tl; + *td = fixed_td; + return Z_OK; +} + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* macros for bit input with no checking and for returning unused bytes */ +#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;} + +/* Called with number of bytes left to write in window at least 258 + (the maximum string length) and number of input bytes available + at least ten. The ten bytes are six bytes for the longest length/ + distance pair plus four bytes for overloading the bit buffer. */ + +int inflate_fast(uInt bl, uInt bd, inflate_huft *tl, inflate_huft *td, inflate_blocks_statef *s, z_streamp z) +{ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Byte *p; /* input data pointer */ + uInt n; /* bytes available there */ + Byte *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + uInt ml; /* mask for literal/length tree */ + uInt md; /* mask for distance tree */ + uInt c; /* bytes to copy */ + uInt d; /* distance back to copy from */ + Byte *r; /* copy source pointer */ + + /* load input, output, bit values */ + LOAD + + /* initialize masks */ + ml = inflate_mask[bl]; + md = inflate_mask[bd]; + + /* do until not enough input or output space for fast loop */ + do { /* assume called with m >= 258 && n >= 10 */ + /* get literal/length code */ + GRABBITS(20) /* max bits for literal/length code */ + if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + continue; + } + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits for length */ + e &= 15; + c = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv(("inflate: * length %u\n", c)); + + /* decode distance base of block to copy */ + GRABBITS(15); /* max bits for distance code */ + e = (t = td + ((uInt)b & md))->exop; + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits to add to distance base */ + e &= 15; + GRABBITS(e) /* get extra bits (up to 13) */ + d = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv(("inflate: * distance %u\n", d)); + + /* do the copy */ + m -= c; + if ((uInt)(q - s->window) >= d) /* offset before dest */ + { /* just copy */ + r = q - d; + *q++ = *r++; c--; /* minimum count is three, */ + *q++ = *r++; c--; /* so unroll loop a little */ + } + else /* else offset after destination */ + { + e = d - (uInt)(q - s->window); /* bytes from offset to end */ + r = s->end - e; /* pointer to offset */ + if (c > e) /* if source crosses, */ + { + c -= e; /* copy to end of window */ + do { + *q++ = *r++; + } while (--e); + r = s->window; /* copy rest from start of window */ + } + } + do { /* copy all or what's left */ + *q++ = *r++; + } while (--c); + break; + } + else if ((e & 64) == 0) + { + t += t->base; + e = (t += ((uInt)b & inflate_mask[e]))->exop; + } + else + { + z->msg = (char*)"invalid distance code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + break; + } + if ((e & 64) == 0) + { + t += t->base; + if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + break; + } + } + else if (e & 32) + { + Tracevv(("inflate: * end of block\n")); + UNGRAB + UPDATE + return Z_STREAM_END; + } + else + { + z->msg = (char*)"invalid literal/length code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + } while (m >= 258 && n >= 10); + + /* not enough input or output--restore pointers and return */ + UNGRAB + UPDATE + return Z_OK; +} + +/* infcodes.c -- process literals and length/distance pairs + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + START, /* x: set up for LEN */ + LEN, /* i: get length/literal/eob next */ + LENEXT, /* i: getting length extra (have base) */ + DIST, /* i: get distance next */ + DISTEXT, /* i: getting distance extra */ + COPY, /* o: copying bytes in window, waiting for space */ + LIT, /* o: got literal, waiting for output space */ + WASH, /* o: got eob, possibly still output waiting */ + END, /* x: got eob and all data flushed */ + BADCODE} /* x: got error */ +inflate_codes_mode; + +/* inflate codes private state */ +struct inflate_codes_state { + + /* mode */ + inflate_codes_mode mode; /* current inflate_codes mode */ + + /* mode dependent information */ + uInt len; + union { + struct { + inflate_huft *tree; /* pointer into tree */ + uInt need; /* bits needed */ + } code; /* if LEN or DIST, where in tree */ + uInt lit; /* if LIT, literal */ + struct { + uInt get; /* bits to get for extra */ + uInt dist; /* distance back to copy from */ + } copy; /* if EXT or COPY, where and how much */ + } sub; /* submode */ + + /* mode independent information */ + Byte lbits; /* ltree bits decoded per branch */ + Byte dbits; /* dtree bits decoder per branch */ + inflate_huft *ltree; /* literal/length/eob tree */ + inflate_huft *dtree; /* distance tree */ + +}; + + +inflate_codes_statef *inflate_codes_new(uInt bl, uInt bd, inflate_huft *tl, inflate_huft *td, z_streamp z) +{ + inflate_codes_statef *c; + + if ((c = (inflate_codes_statef *) + ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) + { + c->mode = START; + c->lbits = (Byte)bl; + c->dbits = (Byte)bd; + c->ltree = tl; + c->dtree = td; + Tracev(("inflate: codes new\n")); + } + return c; +} + + +int inflate_codes(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt j; /* temporary storage */ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Byte *p; /* input data pointer */ + uInt n; /* bytes available there */ + Byte *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + Byte *f; /* pointer to copy strings from */ + inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input and output based on current state */ + while (1) switch (c->mode) + { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + case START: /* x: set up for LEN */ +#ifndef SLOW + if (m >= 258 && n >= 10) + { + UPDATE + r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); + LOAD + if (r != Z_OK) + { + c->mode = r == Z_STREAM_END ? WASH : BADCODE; + break; + } + } +#endif /* !SLOW */ + c->sub.code.need = c->lbits; + c->sub.code.tree = c->ltree; + c->mode = LEN; + case LEN: /* i: get length/literal/eob next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e == 0) /* literal */ + { + c->sub.lit = t->base; + Tracevv((t->base >= 0x20 && t->base < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", t->base)); + c->mode = LIT; + break; + } + if (e & 16) /* length */ + { + c->sub.copy.get = e & 15; + c->len = t->base; + c->mode = LENEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + if (e & 32) /* end of block */ + { + Tracevv(("inflate: end of block\n")); + c->mode = WASH; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid literal/length code"; + r = Z_DATA_ERROR; + LEAVE + case LENEXT: /* i: getting length extra (have base) */ + j = c->sub.copy.get; + NEEDBITS(j) + c->len += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + c->sub.code.need = c->dbits; + c->sub.code.tree = c->dtree; + Tracevv(("inflate: length %u\n", c->len)); + c->mode = DIST; + case DIST: /* i: get distance next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e & 16) /* distance */ + { + c->sub.copy.get = e & 15; + c->sub.copy.dist = t->base; + c->mode = DISTEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid distance code"; + r = Z_DATA_ERROR; + LEAVE + case DISTEXT: /* i: getting distance extra */ + j = c->sub.copy.get; + NEEDBITS(j) + c->sub.copy.dist += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + Tracevv(("inflate: distance %u\n", c->sub.copy.dist)); + c->mode = COPY; + case COPY: /* o: copying bytes in window, waiting for space */ +#ifndef __TURBOC__ /* Turbo C bug for following expression */ + f = (uInt)(q - s->window) < c->sub.copy.dist ? + s->end - (c->sub.copy.dist - (q - s->window)) : + q - c->sub.copy.dist; +#else + f = q - c->sub.copy.dist; + if ((uInt)(q - s->window) < c->sub.copy.dist) + f = s->end - (c->sub.copy.dist - (uInt)(q - s->window)); +#endif + while (c->len) + { + NEEDOUT + OUTBYTE(*f++) + if (f == s->end) + f = s->window; + c->len--; + } + c->mode = START; + break; + case LIT: /* o: got literal, waiting for output space */ + NEEDOUT + OUTBYTE(c->sub.lit) + c->mode = START; + break; + case WASH: /* o: got eob, possibly more output */ + if (k > 7) /* return unused byte, if any */ + { + Assert(k < 16, "inflate_codes grabbed too many bytes") + k -= 8; + n++; + p--; /* can always return one */ + } + FLUSH + if (s->read != s->write) + LEAVE + c->mode = END; + case END: + r = Z_STREAM_END; + LEAVE + case BADCODE: /* x: got error */ + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} + + +void inflate_codes_free(inflate_codes_statef *c, z_streamp z) +{ + ZFREE(z, c); + Tracev(("inflate: codes free\n")); +} + +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#define BASE 65521L /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#undef DO1 +#undef DO2 +#undef DO4 +#undef DO8 + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* ========================================================================= */ +uLong adler32(uLong adler, const Byte *buf, uInt len) +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} + + +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +extern inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +extern int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +extern void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLong *)); /* check value on output */ + +extern int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp)); + +extern void inflate_set_dictionary OF(( + inflate_blocks_statef *s, + const Byte *d, /* dictionary */ + uInt n)); /* dictionary length */ + +extern int inflate_blocks_sync_point OF(( + inflate_blocks_statef *s)); + +typedef enum { + imMETHOD, /* waiting for method byte */ + imFLAG, /* waiting for flag byte */ + imDICT4, /* four dictionary check bytes to go */ + imDICT3, /* three dictionary check bytes to go */ + imDICT2, /* two dictionary check bytes to go */ + imDICT1, /* one dictionary check byte to go */ + imDICT0, /* waiting for inflateSetDictionary */ + imBLOCKS, /* decompressing blocks */ + imCHECK4, /* four check bytes to go */ + imCHECK3, /* three check bytes to go */ + imCHECK2, /* two check bytes to go */ + imCHECK1, /* one check byte to go */ + imDONE, /* finished check, done */ + imBAD} /* got an error--stay here */ +inflate_mode; + +/* inflate private state */ +struct internal_state { + + /* mode */ + inflate_mode mode; /* current inflate mode */ + + /* mode dependent information */ + union { + uInt method; /* if FLAGS, method byte */ + struct { + uLong was; /* computed check value */ + uLong need; /* stream check value */ + } check; /* if CHECK, check values to compare */ + uInt marker; /* if BAD, inflateSync's marker bytes count */ + } sub; /* submode */ + + /* mode independent information */ + int nowrap; /* flag for no wrapper */ + uInt wbits; /* log2(window size) (8..15, defaults to 15) */ + inflate_blocks_statef + *blocks; /* current inflate_blocks state */ + +}; + + +int inflateReset(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + z->total_in = z->total_out = 0; + z->msg = Z_NULL; + z->state->mode = z->state->nowrap ? imBLOCKS : imMETHOD; + inflate_blocks_reset(z->state->blocks, z, Z_NULL); + Tracev(("inflate: reset\n")); + return Z_OK; +} + + +int inflateEnd(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->blocks != Z_NULL) + inflate_blocks_free(z->state->blocks, z); + ZFREE(z, z->state); + z->state = Z_NULL; + Tracev(("inflate: end\n")); + return Z_OK; +} + + + +int inflateInit2_(z_streamp z, int w, const char *version, int stream_size) +{ + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != sizeof(z_stream)) + return Z_VERSION_ERROR; + + /* initialize state */ + if (z == Z_NULL) + return Z_STREAM_ERROR; + z->msg = Z_NULL; + if (z->zalloc == Z_NULL) + { + z->zalloc = (void *(*)(void *, unsigned, unsigned))zcalloc; + z->opaque = (voidp)0; + } + if (z->zfree == Z_NULL) z->zfree = (void (*)(void *, void *))zcfree; + if ((z->state = (struct internal_state *) + ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) + return Z_MEM_ERROR; + z->state->blocks = Z_NULL; + + /* handle undocumented nowrap option (no zlib header or check) */ + z->state->nowrap = 0; + if (w < 0) + { + w = - w; + z->state->nowrap = 1; + } + + /* set window size */ + if (w < 8 || w > 15) + { + inflateEnd(z); + return Z_STREAM_ERROR; + } + z->state->wbits = (uInt)w; + + /* create inflate_blocks state */ + if ((z->state->blocks = + inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) + == Z_NULL) + { + inflateEnd(z); + return Z_MEM_ERROR; + } + Tracev(("inflate: allocated\n")); + + /* reset state */ + inflateReset(z); + return Z_OK; +} + + +int inflateInit_(z_streamp z, const char *version, int stream_size) +{ + return inflateInit2_(z, DEF_WBITS, version, stream_size); +} + + +#define iNEEDBYTE {if(z->avail_in==0)return r;r=f;} +#define iNEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) + +int inflate(z_streamp z, int f) +{ + int r; + uInt b; + + if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) + return Z_STREAM_ERROR; + f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; + r = Z_BUF_ERROR; + while (1) switch (z->state->mode) + { + case imMETHOD: + iNEEDBYTE + if (((z->state->sub.method = iNEXTBYTE) & 0xf) != Z_DEFLATED) + { + z->state->mode = imBAD; + z->msg = (char*)"unknown compression method"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + if ((z->state->sub.method >> 4) + 8 > z->state->wbits) + { + z->state->mode = imBAD; + z->msg = (char*)"invalid window size"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + z->state->mode = imFLAG; + case imFLAG: + iNEEDBYTE + b = iNEXTBYTE; + if (((z->state->sub.method << 8) + b) % 31) + { + z->state->mode = imBAD; + z->msg = (char*)"incorrect header check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev(("inflate: zlib header ok\n")); + if (!(b & PRESET_DICT)) + { + z->state->mode = imBLOCKS; + break; + } + z->state->mode = imDICT4; + case imDICT4: + iNEEDBYTE + z->state->sub.check.need = (uLong)iNEXTBYTE << 24; + z->state->mode = imDICT3; + case imDICT3: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 16; + z->state->mode = imDICT2; + case imDICT2: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 8; + z->state->mode = imDICT1; + case imDICT1: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE; + z->adler = z->state->sub.check.need; + z->state->mode = imDICT0; + return Z_NEED_DICT; + case imDICT0: + z->state->mode = imBAD; + z->msg = (char*)"need dictionary"; + z->state->sub.marker = 0; /* can try inflateSync */ + return Z_STREAM_ERROR; + case imBLOCKS: + r = inflate_blocks(z->state->blocks, z, r); + if (r == Z_DATA_ERROR) + { + z->state->mode = imBAD; + z->state->sub.marker = 0; /* can try inflateSync */ + break; + } + if (r == Z_OK) + r = f; + if (r != Z_STREAM_END) + return r; + r = f; + inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); + if (z->state->nowrap) + { + z->state->mode = imDONE; + break; + } + z->state->mode = imCHECK4; + case imCHECK4: + iNEEDBYTE + z->state->sub.check.need = (uLong)iNEXTBYTE << 24; + z->state->mode = imCHECK3; + case imCHECK3: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 16; + z->state->mode = imCHECK2; + case imCHECK2: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 8; + z->state->mode = imCHECK1; + case imCHECK1: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE; + + if (z->state->sub.check.was != z->state->sub.check.need) + { + z->state->mode = imBAD; + z->msg = (char*)"incorrect data check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev(("inflate: zlib check ok\n")); + z->state->mode = imDONE; + case imDONE: + return Z_STREAM_END; + case imBAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} + + +int inflateSetDictionary(z_streamp z, const Byte *dictionary, uInt dictLength) +{ + uInt length = dictLength; + + if (z == Z_NULL || z->state == Z_NULL || z->state->mode != imDICT0) + return Z_STREAM_ERROR; + + if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; + z->adler = 1L; + + if (length >= ((uInt)1<state->wbits)) + { + length = (1<state->wbits)-1; + dictionary += dictLength - length; + } + inflate_set_dictionary(z->state->blocks, dictionary, length); + z->state->mode = imBLOCKS; + return Z_OK; +} + + +int inflateSync(z_streamp z) +{ + uInt n; /* number of bytes to look at */ + Byte *p; /* pointer to bytes */ + uInt m; /* number of marker bytes found in a row */ + uLong r, w; /* temporaries to save total_in and total_out */ + + /* set up */ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->mode != imBAD) + { + z->state->mode = imBAD; + z->state->sub.marker = 0; + } + if ((n = z->avail_in) == 0) + return Z_BUF_ERROR; + p = z->next_in; + m = z->state->sub.marker; + + /* search */ + while (n && m < 4) + { + static const Byte mark[4] = {0, 0, 0xff, 0xff}; + if (*p == mark[m]) + m++; + else if (*p) + m = 0; + else + m = 4 - m; + p++, n--; + } + + /* restore */ + z->total_in += p - z->next_in; + z->next_in = p; + z->avail_in = n; + z->state->sub.marker = m; + + /* return no joy or set up to restart on a new block */ + if (m != 4) + return Z_DATA_ERROR; + r = z->total_in; w = z->total_out; + inflateReset(z); + z->total_in = r; z->total_out = w; + z->state->mode = imBLOCKS; + return Z_OK; +} + + +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH + * but removes the length bytes of the resulting empty stored block. When + * decompressing, PPP checks that at the end of input packet, inflate is + * waiting for these length bytes. + */ +int inflateSyncPoint(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL) + return Z_STREAM_ERROR; + return inflate_blocks_sync_point(z->state->blocks); +} + +voidp zcalloc (voidp opaque, unsigned items, unsigned size) +{ + if (opaque) items += size - size; /* make compiler happy */ + return (voidp)malloc(items*size); +} + +void zcfree (voidp opaque, voidp ptr) +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + diff --git a/plugins/vfspk3/vfs.cpp b/plugins/vfspk3/vfs.cpp index c2afbefd..69578298 100644 --- a/plugins/vfspk3/vfs.cpp +++ b/plugins/vfspk3/vfs.cpp @@ -1,854 +1,854 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -// -// Rules: -// -// - Directories should be searched in the following order: ~/.q3a/baseq3, -// install dir (/usr/local/games/quake3/baseq3) and cd_path (/mnt/cdrom/baseq3). -// -// - Pak files are searched first inside the directories. -// - Case insensitive. -// - Unix-style slashes (/) (windows is backwards .. everyone knows that) -// -// Leonardo Zide (leo@lokigames.com) -// - -#include -#include - -#if defined (__linux__) || defined (__APPLE__) - #include - #include -#else - #include - #include - #define R_OK 04 - #define S_ISDIR(mode) (mode & _S_IFDIR) -#endif - -// TTimo: String functions -// see http://www.qeradiant.com/faq/index.cgi?file=175 -#include "str.h" - -#include -#include - -#include "vfspk3.h" -#include "vfs.h" -#include "unzip-vfspk3.h" - -typedef struct -{ - char* name; - unz_s zipinfo; - unzFile zipfile; - guint32 size; -} VFS_PAKFILE; - -// ============================================================================= -// Global variables - -static GSList* g_unzFiles; -static GSList* g_pakFiles; -static char g_strDirs[VFS_MAXDIRS][PATH_MAX]; -static int g_numDirs; -static bool g_bUsePak = true; - -// ============================================================================= -// Static functions - -static void vfsAddSlash (char *str) -{ - int n = strlen (str); - if (n > 0) - { - if (str[n-1] != '\\' && str[n-1] != '/') - strcat (str, "/"); - } -} - -static void vfsFixDOSName (char *src) -{ - if (src == NULL) - return; - - while (*src) - { - if (*src == '\\') - *src = '/'; - src++; - } -} - -static void vfsInitPakFile (const char *filename) -{ - unz_global_info gi; - unzFile uf; - guint32 i; - int err; - - uf = unzOpen (filename); - if (uf == NULL) - { - g_FuncTable.m_pfnSysFPrintf(SYS_WRN, " failed to init pak file %s\n", filename); - return; - } - g_FuncTable.m_pfnSysPrintf(" pak file: %s\n", filename); - - g_unzFiles = g_slist_append (g_unzFiles, uf); - - err = unzGetGlobalInfo (uf,&gi); - if (err != UNZ_OK) - return; - unzGoToFirstFile(uf); - - for (i = 0; i < gi.number_entry; i++) - { - char filename_inzip[NAME_MAX]; - unz_file_info file_info; - VFS_PAKFILE* file; - - err = unzGetCurrentFileInfo (uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0); - if (err != UNZ_OK) - break; - - file = (VFS_PAKFILE*)g_malloc (sizeof (VFS_PAKFILE)); - g_pakFiles = g_slist_append (g_pakFiles, file); - - vfsFixDOSName (filename_inzip); - g_strdown (filename_inzip); - - file->name = g_strdup (filename_inzip); - file->size = file_info.uncompressed_size; - file->zipfile = uf; - memcpy (&file->zipinfo, uf, sizeof (unz_s)); - - if ((i+1) < gi.number_entry) - { - err = unzGoToNextFile(uf); - if (err!=UNZ_OK) - break; - } - } -} - -static GSList* vfsGetListInternal (const char *refdir, const char *ext, bool directories) -{ - GSList *lst, *lst_aux, *files = NULL; - char dirname[NAME_MAX], extension[NAME_MAX], filename[NAME_MAX]; - char basedir[NAME_MAX]; - int dirlen; - char *ptr; - char *dirlist; - struct stat st; - GDir *diskdir; - int i; - - if (refdir != NULL) - { - strcpy (dirname, refdir); - g_strdown (dirname); - vfsFixDOSName (dirname); - vfsAddSlash (dirname); - } else - dirname[0] = '\0'; - dirlen = strlen (dirname); - - if (ext != NULL) - strcpy (extension, ext); - else - extension[0] = '\0'; - g_strdown (extension); - - for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) - { - VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; - gboolean found = FALSE; - ptr = file->name; - - // check that the file name begins with dirname - for (i = 0; (*ptr && i < dirlen); i++, ptr++) - if (*ptr != dirname[i]) - break; - - if (i != dirlen) - continue; - - if (directories) - { - char *sep = strchr (ptr, '/'); - if (sep == NULL) - continue; - - i = sep-ptr; - - // check for duplicates - for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) - if (strncmp ((char*)lst_aux->data, ptr, i) == 0) - { - found = TRUE; - break; - } - - if (!found) - { - char *name = g_strndup (ptr, i+1); - name[i] = '\0'; - files = g_slist_append (files, name); - } - } else - { - // check extension - char *ptr_ext = strrchr (ptr, '.'); - if ((ext != NULL) && ((ptr_ext == NULL) || (strcmp (ptr_ext+1, extension) != 0))) - continue; - - // check for duplicates - for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) - if (strcmp ((char*)lst_aux->data, ptr) == 0) - { - found = TRUE; - break; - } - - if (!found) - files = g_slist_append (files, g_strdup (ptr)); - } - } - - for (i = 0; i < g_numDirs; i++) - { - strcpy (basedir, g_strDirs[i]); - strcat (basedir, dirname); - - diskdir = g_dir_open (basedir, 0, NULL); - - if (diskdir != NULL) - { - while (1) - { - const char* name = g_dir_read_name(diskdir); - if(name == NULL) - break; - - if (directories && (name[0] == '.')) - continue; - - sprintf (filename, "%s%s", basedir, name); - stat (filename, &st); - - if ((S_ISDIR (st.st_mode) != 0) != directories) - continue; - - gboolean found = FALSE; - - dirlist = g_strdup(name); - - g_strdown (dirlist); - - char *ptr_ext = strrchr (dirlist, '.'); - if(ext == NULL - || (ext != NULL && ptr_ext != NULL && ptr_ext[0] != '\0' && strcmp (ptr_ext+1, extension) == 0)) - { - - // check for duplicates - for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) - if (strcmp ((char*)lst_aux->data, dirlist) == 0) - { - found = TRUE; - break; - } - - if (!found) - files = g_slist_append (files, g_strdup (dirlist)); - } - - g_free(dirlist); - } - g_dir_close (diskdir); - } - } - - return files; -} - -/*! -This behaves identically to -stricmp(a,b), except that ASCII chars -[\]^`_ come AFTER alphabet chars instead of before. This is because -it effectively converts all alphabet chars to uppercase before comparison, -while stricmp converts them to lowercase. -*/ -//!\todo Analyse the code in rtcw/q3 to see how it behaves. -static int vfsPakSort (const void *a, const void *b) -{ - char *s1, *s2; - int c1, c2; - - s1 = (char*)a; - s2 = (char*)b; - - do { - c1 = *s1++; - c2 = *s2++; - - if (c1 >= 'a' && c1 <= 'z') - { - c1 -= ('a' - 'A'); - } - if (c2 >= 'a' && c2 <= 'z') - { - c2 -= ('a' - 'A'); - } - - if ( c1 == '\\' || c1 == ':' ) - { - c1 = '/'; - } - if ( c2 == '\\' || c2 == ':' ) - { - c2 = '/'; - } - - // Arnout: note - sort pakfiles in reverse order. This ensures that - // later pakfiles override earlier ones. This because the vfs module - // returns a filehandle to the first file it can find (while it should - // return the filehandle to the file in the most overriding pakfile, the - // last one in the list that is). - if (c1 < c2) - { - //return -1; // strings not equal - return 1; // strings not equal - } - if (c1 > c2) - { - //return 1; - return -1; - } - } while (c1); - - return 0; // strings are equal -} - -// ============================================================================= -// Global functions - -// reads all pak files from a dir -/*! -The gamemode hacks in here will do undefined things with files called zz_*. -This is simple to fix by cleaning up the hacks, but may be better left alone -if the engine code does the same thing. -*/ -void vfsInitDirectory (const char *path) -{ - char filename[PATH_MAX]; - GDir *dir; - GSList *dirlistptr, *dirlist = NULL; - int iGameMode; // 0: no filtering 1: SP 2: MP - - if (g_numDirs == (VFS_MAXDIRS-1)) - return; - - // See if we are in "sp" or "mp" mapping mode - const char* gamemode = g_FuncTable.m_pfnReadProjectKey("gamemode"); - - if (gamemode) - { - if (strcmp (gamemode, "sp") == 0) - iGameMode = 1; - else if (strcmp (gamemode, "mp") == 0) - iGameMode = 2; - else - iGameMode = 0; - } else - iGameMode = 0; - - strcpy (g_strDirs[g_numDirs], path); - vfsFixDOSName (g_strDirs[g_numDirs]); - vfsAddSlash (g_strDirs[g_numDirs]); - g_numDirs++; - - if (g_bUsePak) - { - dir = g_dir_open (path, 0, NULL); - - if (dir != NULL) - { - g_FuncTable.m_pfnSysPrintf("vfs directory: %s\n", path); - - for(;;) - { - const char* name = g_dir_read_name(dir); - if(name == NULL) - break; - - char *ext = (char*)strrchr(name, '.'); - if ((ext == NULL) || (strcasecmp (ext, ".pk3") != 0)) - continue; - - char* direntry = g_strdup(name); - - // using the same kludge as in engine to ensure consistency - switch (iGameMode) - { - case 1: // SP - if (strncmp(direntry,"sp_",3) == 0) - memcpy(direntry,"zz",2); - break; - case 2: // MP - if (strncmp(direntry,"mp_",3) == 0) - memcpy(direntry,"zz",2); - break; - } - - dirlist = g_slist_append (dirlist, direntry); - } - - g_dir_close (dir); - - // sort them - dirlist = g_slist_sort (dirlist, vfsPakSort); - - // add the entries to the vfs and free the list - while (dirlist) - { - GSList *cur = dirlist; - char* name = (char*)cur->data; - - switch (iGameMode) - { - case 1: // SP - if (strncmp(name,"mp_",3) == 0) - { - g_free (name); - dirlist = g_slist_remove (cur, name); - continue; - } else if (strncmp(name,"zz_",3) == 0) - memcpy(name,"sp",2); - break; - case 2: // MP - if (strncmp(name,"sp_",3) == 0) - { - g_free (name); - dirlist = g_slist_remove (cur, name); - continue; - } else if (strncmp(name,"zz_",3) == 0) - memcpy(name,"mp",2); - break; - } - - sprintf (filename, "%s/%s", path, name); - vfsInitPakFile (filename); - - g_free (name); - dirlist = g_slist_remove (cur, name); - } - } - else - g_FuncTable.m_pfnSysFPrintf(SYS_WRN, "vfs directory not found: %s\n", path); - } -} - -// frees all memory that we allocated -// FIXME TTimo this should be improved so that we can shutdown and restart the VFS without exiting Radiant? -// (for instance when modifying the project settings) -void vfsShutdown () -{ - while (g_unzFiles) - { - unzClose ((unzFile)g_unzFiles->data); - g_unzFiles = g_slist_remove (g_unzFiles, g_unzFiles->data); - } - - // avoid dangling pointer operation (makes BC hangry) - GSList *cur = g_pakFiles; - GSList *next = cur; - while (next) - { - cur = next; - VFS_PAKFILE* file = (VFS_PAKFILE*)cur->data; - g_free (file->name); - g_free (file); - next = g_slist_remove (cur, file); - } - g_pakFiles = NULL; -} - -void vfsFreeFile (void *p) -{ - g_free(p); -} - -GSList* vfsGetFileList (const char *dir, const char *ext) -{ - return vfsGetListInternal (dir, ext, false); -} - -GSList* vfsGetDirList (const char *dir) -{ - return vfsGetListInternal (dir, NULL, true); -} - -void vfsClearFileDirList (GSList **lst) -{ - while (*lst) - { - g_free ((*lst)->data); - *lst = g_slist_remove (*lst, (*lst)->data); - } -} - -int vfsGetFileCount (const char *filename, int flag) -{ - int i, count = 0; - char fixed[NAME_MAX], tmp[NAME_MAX]; - GSList *lst; - - strcpy (fixed, filename); - vfsFixDOSName (fixed); - g_strdown (fixed); - - if (!flag || (flag & VFS_SEARCH_PAK)) - { - for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) - { - VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; - - if (strcmp (file->name, fixed) == 0) - count++; - } - } - - if (!flag || (flag & VFS_SEARCH_DIR)) - { - for (i = 0; i < g_numDirs; i++) - { - strcpy (tmp, g_strDirs[i]); - strcat (tmp, fixed); - if (access (tmp, R_OK) == 0) - count++; - } - } - - return count; -} - -// open a full path file -int vfsLoadFullPathFile (const char *filename, void **bufferptr) -{ - FILE *f; - long len; - - f = fopen (filename, "rb"); - if (f == NULL) - return -1; - - fseek (f, 0, SEEK_END); - len = ftell (f); - rewind (f); - - *bufferptr = g_malloc (len+1); - if (*bufferptr == NULL) - return -1; - - fread (*bufferptr, 1, len, f); - fclose (f); - - // we need to end the buffer with a 0 - ((char*) (*bufferptr))[len] = 0; - - return len; -} - -// NOTE: when loading a file, you have to allocate one extra byte and set it to \0 -int vfsLoadFile (const char *filename, void **bufferptr, int index) -{ - int i, count = 0; - char tmp[NAME_MAX], fixed[NAME_MAX]; - GSList *lst; - - *bufferptr = NULL; - strcpy (fixed, filename); - vfsFixDOSName (fixed); - g_strdown (fixed); - - for (i = 0; i < g_numDirs; i++) - { - strcpy (tmp, g_strDirs[i]); - strcat (tmp, filename); - if (access (tmp, R_OK) == 0) - { - if (count == index) - { - return vfsLoadFullPathFile(tmp,bufferptr); - } - - count++; - } - } - - for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) - { - VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; - - if (strcmp (file->name, fixed) != 0) - continue; - - if (count == index) - { - memcpy (file->zipfile, &file->zipinfo, sizeof (unz_s)); - - if (unzOpenCurrentFile (file->zipfile) != UNZ_OK) - return -1; - - *bufferptr = g_malloc (file->size+1); - // we need to end the buffer with a 0 - ((char*) (*bufferptr))[file->size] = 0; - - i = unzReadCurrentFile (file->zipfile , *bufferptr, file->size); - unzCloseCurrentFile (file->zipfile); - if (i > 0) - return file->size; - else - return -1; - } - - count++; - } - - return -1; -} - -//#ifdef _DEBUG -#if 1 - #define DBG_RLTPATH -#endif - -/*! -\param shorten will try to match against the short version -http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=144 -recent switch back to short path names in project settings has broken some stuff -with shorten == true, we will convert in to short version before looking for root -FIXME WAAA .. the stuff below is much more simple on linux .. add appropriate #ifdef -*/ -char* vfsExtractRelativePath_short(const char *in, bool shorten) -{ - int i; - char l_in[PATH_MAX]; - char check[PATH_MAX]; - static char out[PATH_MAX]; - out[0] = 0; - -#ifdef DBG_RLTPATH - Sys_Printf("vfsExtractRelativePath: %s\n", in); -#endif - -#ifdef _WIN32 - if (shorten) - { - // make it short - if (GetShortPathName(in, l_in, PATH_MAX) == 0) - { -#ifdef DBG_RLTPATH - Sys_Printf("GetShortPathName failed\n"); -#endif - return NULL; - } - } - else - { - strcpy(l_in,in); - } - vfsCleanFileName(l_in); -#else - strcpy(l_in, in); - vfsCleanFileName(l_in); -#endif // ifdef WIN32 - - -#ifdef DBG_RLTPATH - Sys_Printf("cleaned path: %s\n", l_in); -#endif - - for (i = 0; i < g_numDirs; i++) - { - strcpy(check,g_strDirs[i]); - vfsCleanFileName(check); -#ifdef DBG_RLTPATH - Sys_Printf("Matching against %s\n", check); -#endif - - // try to find a match - if (strstr(l_in, check)) - { - strcpy(out,l_in+strlen(check)+1); - break; - } - - } - if (out[0]!=0) - { -#ifdef DBG_RLTPATH - Sys_Printf("vfsExtractRelativePath: success\n"); -#endif - return out; - } -#ifdef DBG_RLTPATH - Sys_Printf("vfsExtractRelativePath: failed\n"); -#endif - return NULL; -} - - -// FIXME TTimo: this and the above should be merged at some point -char* vfsExtractRelativePath(const char *in) -{ - static char out[PATH_MAX]; - unsigned int i, count; - char *chunk, *backup = NULL; // those point to out stuff - char *ret = vfsExtractRelativePath_short(in, false); - if (!ret) - { -#ifdef DBG_RLTPATH - Sys_Printf("trying with a short version\n"); -#endif - ret = vfsExtractRelativePath_short(in, true); - if (ret) - { - // ok, but we have a relative short version now - // hack the long relative version out of here - count = 0; - for(i=0;idata; - - char *ptr,*lastptr; - lastptr = file->name; - - while (ptr = strchr(lastptr,'/')) - lastptr = ptr+1; - - if (strcmp (lastptr, fixed) == 0) - { - strncpy(out,file->name,PATH_MAX); - return out; - } - } - - } - - if (!flag || (flag & VFS_SEARCH_DIR)) - { - for (i = 0; i < g_numDirs; i++) - { - strcpy (tmp, g_strDirs[i]); - strcat (tmp, in); - if (access (tmp, R_OK) == 0) - { - if (count == index) - { - strcpy (out, tmp); - return out; - } - count++; - } - } - } - return NULL; -} - - -// TODO TTimo on linux the base prompt is ~/.q3a/ -// given the file dialog, we could push the strFSBasePath and ~/.q3a into the directory shortcuts -// FIXME TTimo is this really a VFS functionality? -// actually .. this should be the decision of the core isn't it? -// or .. add an API so that the base prompt can be set during VFS init -const char* vfsBasePromptPath() -{ -#ifdef _WIN32 - static char* path = "C:"; -#else - static char* path = "/"; -#endif - return path; -} - +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// +// Rules: +// +// - Directories should be searched in the following order: ~/.q3a/baseq3, +// install dir (/usr/local/games/quake3/baseq3) and cd_path (/mnt/cdrom/baseq3). +// +// - Pak files are searched first inside the directories. +// - Case insensitive. +// - Unix-style slashes (/) (windows is backwards .. everyone knows that) +// +// Leonardo Zide (leo@lokigames.com) +// + +#include +#include + +#if defined (__linux__) || defined (__APPLE__) + #include + #include +#else + #include + #include + #define R_OK 04 + #define S_ISDIR(mode) (mode & _S_IFDIR) +#endif + +// TTimo: String functions +// see http://www.qeradiant.com/faq/index.cgi?file=175 +#include "str.h" + +#include +#include + +#include "vfspk3.h" +#include "vfs.h" +#include "unzip-vfspk3.h" + +typedef struct +{ + char* name; + unz_s zipinfo; + unzFile zipfile; + guint32 size; +} VFS_PAKFILE; + +// ============================================================================= +// Global variables + +static GSList* g_unzFiles; +static GSList* g_pakFiles; +static char g_strDirs[VFS_MAXDIRS][PATH_MAX]; +static int g_numDirs; +static bool g_bUsePak = true; + +// ============================================================================= +// Static functions + +static void vfsAddSlash (char *str) +{ + int n = strlen (str); + if (n > 0) + { + if (str[n-1] != '\\' && str[n-1] != '/') + strcat (str, "/"); + } +} + +static void vfsFixDOSName (char *src) +{ + if (src == NULL) + return; + + while (*src) + { + if (*src == '\\') + *src = '/'; + src++; + } +} + +static void vfsInitPakFile (const char *filename) +{ + unz_global_info gi; + unzFile uf; + guint32 i; + int err; + + uf = unzOpen (filename); + if (uf == NULL) + { + g_FuncTable.m_pfnSysFPrintf(SYS_WRN, " failed to init pak file %s\n", filename); + return; + } + g_FuncTable.m_pfnSysPrintf(" pak file: %s\n", filename); + + g_unzFiles = g_slist_append (g_unzFiles, uf); + + err = unzGetGlobalInfo (uf,&gi); + if (err != UNZ_OK) + return; + unzGoToFirstFile(uf); + + for (i = 0; i < gi.number_entry; i++) + { + char filename_inzip[NAME_MAX]; + unz_file_info file_info; + VFS_PAKFILE* file; + + err = unzGetCurrentFileInfo (uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0); + if (err != UNZ_OK) + break; + + file = (VFS_PAKFILE*)g_malloc (sizeof (VFS_PAKFILE)); + g_pakFiles = g_slist_append (g_pakFiles, file); + + vfsFixDOSName (filename_inzip); + g_strdown (filename_inzip); + + file->name = g_strdup (filename_inzip); + file->size = file_info.uncompressed_size; + file->zipfile = uf; + memcpy (&file->zipinfo, uf, sizeof (unz_s)); + + if ((i+1) < gi.number_entry) + { + err = unzGoToNextFile(uf); + if (err!=UNZ_OK) + break; + } + } +} + +static GSList* vfsGetListInternal (const char *refdir, const char *ext, bool directories) +{ + GSList *lst, *lst_aux, *files = NULL; + char dirname[NAME_MAX], extension[NAME_MAX], filename[NAME_MAX]; + char basedir[NAME_MAX]; + int dirlen; + char *ptr; + char *dirlist; + struct stat st; + GDir *diskdir; + int i; + + if (refdir != NULL) + { + strcpy (dirname, refdir); + g_strdown (dirname); + vfsFixDOSName (dirname); + vfsAddSlash (dirname); + } else + dirname[0] = '\0'; + dirlen = strlen (dirname); + + if (ext != NULL) + strcpy (extension, ext); + else + extension[0] = '\0'; + g_strdown (extension); + + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + gboolean found = FALSE; + ptr = file->name; + + // check that the file name begins with dirname + for (i = 0; (*ptr && i < dirlen); i++, ptr++) + if (*ptr != dirname[i]) + break; + + if (i != dirlen) + continue; + + if (directories) + { + char *sep = strchr (ptr, '/'); + if (sep == NULL) + continue; + + i = sep-ptr; + + // check for duplicates + for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) + if (strncmp ((char*)lst_aux->data, ptr, i) == 0) + { + found = TRUE; + break; + } + + if (!found) + { + char *name = g_strndup (ptr, i+1); + name[i] = '\0'; + files = g_slist_append (files, name); + } + } else + { + // check extension + char *ptr_ext = strrchr (ptr, '.'); + if ((ext != NULL) && ((ptr_ext == NULL) || (strcmp (ptr_ext+1, extension) != 0))) + continue; + + // check for duplicates + for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) + if (strcmp ((char*)lst_aux->data, ptr) == 0) + { + found = TRUE; + break; + } + + if (!found) + files = g_slist_append (files, g_strdup (ptr)); + } + } + + for (i = 0; i < g_numDirs; i++) + { + strcpy (basedir, g_strDirs[i]); + strcat (basedir, dirname); + + diskdir = g_dir_open (basedir, 0, NULL); + + if (diskdir != NULL) + { + while (1) + { + const char* name = g_dir_read_name(diskdir); + if(name == NULL) + break; + + if (directories && (name[0] == '.')) + continue; + + sprintf (filename, "%s%s", basedir, name); + stat (filename, &st); + + if ((S_ISDIR (st.st_mode) != 0) != directories) + continue; + + gboolean found = FALSE; + + dirlist = g_strdup(name); + + g_strdown (dirlist); + + char *ptr_ext = strrchr (dirlist, '.'); + if(ext == NULL + || (ext != NULL && ptr_ext != NULL && ptr_ext[0] != '\0' && strcmp (ptr_ext+1, extension) == 0)) + { + + // check for duplicates + for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) + if (strcmp ((char*)lst_aux->data, dirlist) == 0) + { + found = TRUE; + break; + } + + if (!found) + files = g_slist_append (files, g_strdup (dirlist)); + } + + g_free(dirlist); + } + g_dir_close (diskdir); + } + } + + return files; +} + +/*! +This behaves identically to -stricmp(a,b), except that ASCII chars +[\]^`_ come AFTER alphabet chars instead of before. This is because +it effectively converts all alphabet chars to uppercase before comparison, +while stricmp converts them to lowercase. +*/ +//!\todo Analyse the code in rtcw/q3 to see how it behaves. +static int vfsPakSort (const void *a, const void *b) +{ + char *s1, *s2; + int c1, c2; + + s1 = (char*)a; + s2 = (char*)b; + + do { + c1 = *s1++; + c2 = *s2++; + + if (c1 >= 'a' && c1 <= 'z') + { + c1 -= ('a' - 'A'); + } + if (c2 >= 'a' && c2 <= 'z') + { + c2 -= ('a' - 'A'); + } + + if ( c1 == '\\' || c1 == ':' ) + { + c1 = '/'; + } + if ( c2 == '\\' || c2 == ':' ) + { + c2 = '/'; + } + + // Arnout: note - sort pakfiles in reverse order. This ensures that + // later pakfiles override earlier ones. This because the vfs module + // returns a filehandle to the first file it can find (while it should + // return the filehandle to the file in the most overriding pakfile, the + // last one in the list that is). + if (c1 < c2) + { + //return -1; // strings not equal + return 1; // strings not equal + } + if (c1 > c2) + { + //return 1; + return -1; + } + } while (c1); + + return 0; // strings are equal +} + +// ============================================================================= +// Global functions + +// reads all pak files from a dir +/*! +The gamemode hacks in here will do undefined things with files called zz_*. +This is simple to fix by cleaning up the hacks, but may be better left alone +if the engine code does the same thing. +*/ +void vfsInitDirectory (const char *path) +{ + char filename[PATH_MAX]; + GDir *dir; + GSList *dirlistptr, *dirlist = NULL; + int iGameMode; // 0: no filtering 1: SP 2: MP + + if (g_numDirs == (VFS_MAXDIRS-1)) + return; + + // See if we are in "sp" or "mp" mapping mode + const char* gamemode = g_FuncTable.m_pfnReadProjectKey("gamemode"); + + if (gamemode) + { + if (strcmp (gamemode, "sp") == 0) + iGameMode = 1; + else if (strcmp (gamemode, "mp") == 0) + iGameMode = 2; + else + iGameMode = 0; + } else + iGameMode = 0; + + strcpy (g_strDirs[g_numDirs], path); + vfsFixDOSName (g_strDirs[g_numDirs]); + vfsAddSlash (g_strDirs[g_numDirs]); + g_numDirs++; + + if (g_bUsePak) + { + dir = g_dir_open (path, 0, NULL); + + if (dir != NULL) + { + g_FuncTable.m_pfnSysPrintf("vfs directory: %s\n", path); + + for(;;) + { + const char* name = g_dir_read_name(dir); + if(name == NULL) + break; + + char *ext = (char*)strrchr(name, '.'); + if ((ext == NULL) || (strcasecmp (ext, ".pk3") != 0)) + continue; + + char* direntry = g_strdup(name); + + // using the same kludge as in engine to ensure consistency + switch (iGameMode) + { + case 1: // SP + if (strncmp(direntry,"sp_",3) == 0) + memcpy(direntry,"zz",2); + break; + case 2: // MP + if (strncmp(direntry,"mp_",3) == 0) + memcpy(direntry,"zz",2); + break; + } + + dirlist = g_slist_append (dirlist, direntry); + } + + g_dir_close (dir); + + // sort them + dirlist = g_slist_sort (dirlist, vfsPakSort); + + // add the entries to the vfs and free the list + while (dirlist) + { + GSList *cur = dirlist; + char* name = (char*)cur->data; + + switch (iGameMode) + { + case 1: // SP + if (strncmp(name,"mp_",3) == 0) + { + g_free (name); + dirlist = g_slist_remove (cur, name); + continue; + } else if (strncmp(name,"zz_",3) == 0) + memcpy(name,"sp",2); + break; + case 2: // MP + if (strncmp(name,"sp_",3) == 0) + { + g_free (name); + dirlist = g_slist_remove (cur, name); + continue; + } else if (strncmp(name,"zz_",3) == 0) + memcpy(name,"mp",2); + break; + } + + sprintf (filename, "%s/%s", path, name); + vfsInitPakFile (filename); + + g_free (name); + dirlist = g_slist_remove (cur, name); + } + } + else + g_FuncTable.m_pfnSysFPrintf(SYS_WRN, "vfs directory not found: %s\n", path); + } +} + +// frees all memory that we allocated +// FIXME TTimo this should be improved so that we can shutdown and restart the VFS without exiting Radiant? +// (for instance when modifying the project settings) +void vfsShutdown () +{ + while (g_unzFiles) + { + unzClose ((unzFile)g_unzFiles->data); + g_unzFiles = g_slist_remove (g_unzFiles, g_unzFiles->data); + } + + // avoid dangling pointer operation (makes BC hangry) + GSList *cur = g_pakFiles; + GSList *next = cur; + while (next) + { + cur = next; + VFS_PAKFILE* file = (VFS_PAKFILE*)cur->data; + g_free (file->name); + g_free (file); + next = g_slist_remove (cur, file); + } + g_pakFiles = NULL; +} + +void vfsFreeFile (void *p) +{ + g_free(p); +} + +GSList* vfsGetFileList (const char *dir, const char *ext) +{ + return vfsGetListInternal (dir, ext, false); +} + +GSList* vfsGetDirList (const char *dir) +{ + return vfsGetListInternal (dir, NULL, true); +} + +void vfsClearFileDirList (GSList **lst) +{ + while (*lst) + { + g_free ((*lst)->data); + *lst = g_slist_remove (*lst, (*lst)->data); + } +} + +int vfsGetFileCount (const char *filename, int flag) +{ + int i, count = 0; + char fixed[NAME_MAX], tmp[NAME_MAX]; + GSList *lst; + + strcpy (fixed, filename); + vfsFixDOSName (fixed); + g_strdown (fixed); + + if (!flag || (flag & VFS_SEARCH_PAK)) + { + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + + if (strcmp (file->name, fixed) == 0) + count++; + } + } + + if (!flag || (flag & VFS_SEARCH_DIR)) + { + for (i = 0; i < g_numDirs; i++) + { + strcpy (tmp, g_strDirs[i]); + strcat (tmp, fixed); + if (access (tmp, R_OK) == 0) + count++; + } + } + + return count; +} + +// open a full path file +int vfsLoadFullPathFile (const char *filename, void **bufferptr) +{ + FILE *f; + long len; + + f = fopen (filename, "rb"); + if (f == NULL) + return -1; + + fseek (f, 0, SEEK_END); + len = ftell (f); + rewind (f); + + *bufferptr = g_malloc (len+1); + if (*bufferptr == NULL) + return -1; + + fread (*bufferptr, 1, len, f); + fclose (f); + + // we need to end the buffer with a 0 + ((char*) (*bufferptr))[len] = 0; + + return len; +} + +// NOTE: when loading a file, you have to allocate one extra byte and set it to \0 +int vfsLoadFile (const char *filename, void **bufferptr, int index) +{ + int i, count = 0; + char tmp[NAME_MAX], fixed[NAME_MAX]; + GSList *lst; + + *bufferptr = NULL; + strcpy (fixed, filename); + vfsFixDOSName (fixed); + g_strdown (fixed); + + for (i = 0; i < g_numDirs; i++) + { + strcpy (tmp, g_strDirs[i]); + strcat (tmp, filename); + if (access (tmp, R_OK) == 0) + { + if (count == index) + { + return vfsLoadFullPathFile(tmp,bufferptr); + } + + count++; + } + } + + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + + if (strcmp (file->name, fixed) != 0) + continue; + + if (count == index) + { + memcpy (file->zipfile, &file->zipinfo, sizeof (unz_s)); + + if (unzOpenCurrentFile (file->zipfile) != UNZ_OK) + return -1; + + *bufferptr = g_malloc (file->size+1); + // we need to end the buffer with a 0 + ((char*) (*bufferptr))[file->size] = 0; + + i = unzReadCurrentFile (file->zipfile , *bufferptr, file->size); + unzCloseCurrentFile (file->zipfile); + if (i > 0) + return file->size; + else + return -1; + } + + count++; + } + + return -1; +} + +//#ifdef _DEBUG +#if 1 + #define DBG_RLTPATH +#endif + +/*! +\param shorten will try to match against the short version +http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=144 +recent switch back to short path names in project settings has broken some stuff +with shorten == true, we will convert in to short version before looking for root +FIXME WAAA .. the stuff below is much more simple on linux .. add appropriate #ifdef +*/ +char* vfsExtractRelativePath_short(const char *in, bool shorten) +{ + int i; + char l_in[PATH_MAX]; + char check[PATH_MAX]; + static char out[PATH_MAX]; + out[0] = 0; + +#ifdef DBG_RLTPATH + Sys_Printf("vfsExtractRelativePath: %s\n", in); +#endif + +#ifdef _WIN32 + if (shorten) + { + // make it short + if (GetShortPathName(in, l_in, PATH_MAX) == 0) + { +#ifdef DBG_RLTPATH + Sys_Printf("GetShortPathName failed\n"); +#endif + return NULL; + } + } + else + { + strcpy(l_in,in); + } + vfsCleanFileName(l_in); +#else + strcpy(l_in, in); + vfsCleanFileName(l_in); +#endif // ifdef WIN32 + + +#ifdef DBG_RLTPATH + Sys_Printf("cleaned path: %s\n", l_in); +#endif + + for (i = 0; i < g_numDirs; i++) + { + strcpy(check,g_strDirs[i]); + vfsCleanFileName(check); +#ifdef DBG_RLTPATH + Sys_Printf("Matching against %s\n", check); +#endif + + // try to find a match + if (strstr(l_in, check)) + { + strcpy(out,l_in+strlen(check)+1); + break; + } + + } + if (out[0]!=0) + { +#ifdef DBG_RLTPATH + Sys_Printf("vfsExtractRelativePath: success\n"); +#endif + return out; + } +#ifdef DBG_RLTPATH + Sys_Printf("vfsExtractRelativePath: failed\n"); +#endif + return NULL; +} + + +// FIXME TTimo: this and the above should be merged at some point +char* vfsExtractRelativePath(const char *in) +{ + static char out[PATH_MAX]; + unsigned int i, count; + char *chunk, *backup = NULL; // those point to out stuff + char *ret = vfsExtractRelativePath_short(in, false); + if (!ret) + { +#ifdef DBG_RLTPATH + Sys_Printf("trying with a short version\n"); +#endif + ret = vfsExtractRelativePath_short(in, true); + if (ret) + { + // ok, but we have a relative short version now + // hack the long relative version out of here + count = 0; + for(i=0;idata; + + char *ptr,*lastptr; + lastptr = file->name; + + while (ptr = strchr(lastptr,'/')) + lastptr = ptr+1; + + if (strcmp (lastptr, fixed) == 0) + { + strncpy(out,file->name,PATH_MAX); + return out; + } + } + + } + + if (!flag || (flag & VFS_SEARCH_DIR)) + { + for (i = 0; i < g_numDirs; i++) + { + strcpy (tmp, g_strDirs[i]); + strcat (tmp, in); + if (access (tmp, R_OK) == 0) + { + if (count == index) + { + strcpy (out, tmp); + return out; + } + count++; + } + } + } + return NULL; +} + + +// TODO TTimo on linux the base prompt is ~/.q3a/ +// given the file dialog, we could push the strFSBasePath and ~/.q3a into the directory shortcuts +// FIXME TTimo is this really a VFS functionality? +// actually .. this should be the decision of the core isn't it? +// or .. add an API so that the base prompt can be set during VFS init +const char* vfsBasePromptPath() +{ +#ifdef _WIN32 + static char* path = "C:"; +#else + static char* path = "/"; +#endif + return path; +} + diff --git a/plugins/vfspk3/vfspk3.cpp b/plugins/vfspk3/vfspk3.cpp index dad98fee..23d8bae1 100644 --- a/plugins/vfspk3/vfspk3.cpp +++ b/plugins/vfspk3/vfspk3.cpp @@ -1,104 +1,104 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -// -// Quake 3 Virtual FileSystem - reads files from different dirs and inside pak files -// -// Leonardo Zide (leo@lokigames.com) -// - -#ifdef _WIN32 -#include -#endif - -#include -#include "vfspk3.h" -#include "vfs.h" - -// ============================================================================= -// SYNAPSE - -_QERFuncTable_1 g_FuncTable; - -CSynapseServer* g_pSynapseServer = NULL; -CSynapseClientVFS 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( VFS_MAJOR, "pk3", sizeof( _QERFileSystemTable ) ); - g_SynapseClient.AddAPI( RADIANT_MAJOR, NULL, sizeof( _QERFuncTable_1 ), SYN_REQUIRE, &g_FuncTable ); - - return &g_SynapseClient; -} - -bool CSynapseClientVFS::RequestAPI(APIDescriptor_t *pAPI) -{ - if (!strcmp(pAPI->major_name, VFS_MAJOR)) - { - _QERFileSystemTable* pTable= static_cast<_QERFileSystemTable*>(pAPI->mpTable); - pTable->m_pfnInitDirectory = &vfsInitDirectory; - pTable->m_pfnShutdown = &vfsShutdown; - pTable->m_pfnFreeFile = &vfsFreeFile; - pTable->m_pfnGetDirList = &vfsGetDirList; - pTable->m_pfnGetFileList = &vfsGetFileList; - pTable->m_pfnClearFileDirList = &vfsClearFileDirList; - pTable->m_pfnGetFileCount = &vfsGetFileCount; - pTable->m_pfnLoadFile = &vfsLoadFile; - pTable->m_pfnLoadFullPathFile = &vfsLoadFullPathFile; - pTable->m_pfnExtractRelativePath = &vfsExtractRelativePath; - pTable->m_pfnGetFullPath = &vfsGetFullPath; - pTable->m_pfnBasePromptPath = &vfsBasePromptPath; - return true; - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -#include "version.h" - -const char* CSynapseClientVFS::GetInfo() -{ - return "PK3 VFS module built " __DATE__ " " RADIANT_VERSION; -} +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// +// Quake 3 Virtual FileSystem - reads files from different dirs and inside pak files +// +// Leonardo Zide (leo@lokigames.com) +// + +#ifdef _WIN32 +#include +#endif + +#include +#include "vfspk3.h" +#include "vfs.h" + +// ============================================================================= +// SYNAPSE + +_QERFuncTable_1 g_FuncTable; + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientVFS 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( VFS_MAJOR, "pk3", sizeof( _QERFileSystemTable ) ); + g_SynapseClient.AddAPI( RADIANT_MAJOR, NULL, sizeof( _QERFuncTable_1 ), SYN_REQUIRE, &g_FuncTable ); + + return &g_SynapseClient; +} + +bool CSynapseClientVFS::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, VFS_MAJOR)) + { + _QERFileSystemTable* pTable= static_cast<_QERFileSystemTable*>(pAPI->mpTable); + pTable->m_pfnInitDirectory = &vfsInitDirectory; + pTable->m_pfnShutdown = &vfsShutdown; + pTable->m_pfnFreeFile = &vfsFreeFile; + pTable->m_pfnGetDirList = &vfsGetDirList; + pTable->m_pfnGetFileList = &vfsGetFileList; + pTable->m_pfnClearFileDirList = &vfsClearFileDirList; + pTable->m_pfnGetFileCount = &vfsGetFileCount; + pTable->m_pfnLoadFile = &vfsLoadFile; + pTable->m_pfnLoadFullPathFile = &vfsLoadFullPathFile; + pTable->m_pfnExtractRelativePath = &vfsExtractRelativePath; + pTable->m_pfnGetFullPath = &vfsGetFullPath; + pTable->m_pfnBasePromptPath = &vfsBasePromptPath; + return true; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientVFS::GetInfo() +{ + return "PK3 VFS module built " __DATE__ " " RADIANT_VERSION; +} diff --git a/plugins/vfswad/unwad.cpp b/plugins/vfswad/unwad.cpp index e6c36b7e..36a7ee9d 100644 --- a/plugins/vfswad/unwad.cpp +++ b/plugins/vfswad/unwad.cpp @@ -1,251 +1,251 @@ -#include -#include -#include - -#include "unwad.h" - - -wadFile_t *wadCleanup(wadFile_t *wf) -{ - if (wf) - { - if (wf->fin) fclose(wf->fin); - if (wf->lpHeader) free(wf->lpHeader); - if (wf->lpLump) free(wf->lpLump); - if (wf->lpMip) free(wf->lpMip); - if (wf->wadfilename) free(wf->wadfilename); - free (wf); - wf = NULL; - } - return wf; -} - -int wadGetCurrentFileInfo ( wadFile_t *wf, char *szFileName, unsigned long fileNameBufferSize, unsigned long *filesize) -{ - /* returns 0 if error, or 1 for sucess */ - // if this fails you'll need to re-position the fileposition - // before attempting any other calls. e.g. call wadGoToFirstFile() - - if (fread(wf->lpLump,sizeof(WAD3_LUMP),1,wf->fin)!=1) - return 0; - strncpy(szFileName, wf->lpLump->name, fileNameBufferSize); - szFileName[fileNameBufferSize-1] = 0; // null terminate - - *filesize = wf->lpLump->size; - - return 1; -} - -int wadGoToFile(wadFile_t *wf, unsigned long filenum) -{ - if (!wf) - return 0; - - if (!wf->fin) - return 0; - - if (filenum >= wf->lpHeader->numlumps) - return 0; - - if (fseek(wf->fin,wf->lpHeader->infotableofs + (filenum * sizeof(WAD3_LUMP)),SEEK_SET) != 0) - return 0; - - wf->currentfile = filenum; - - return 1; -} - -int wadGoToNextFile(wadFile_t *wf) -{ - return(wadGoToFile(wf, wf->currentfile + 1)); -} - -int wadGoToFirstFile(wadFile_t *wf) -{ - /* returns 0 if error, or 1 for sucess */ - - if (!wf) - return 0; - - if (!wf->fin) - return 0; - - if (fseek(wf->fin,wf->lpHeader->infotableofs,SEEK_SET) != 0) - return 0; - - wf->currentfile = 0; - - return 1; -} - -wadFile_t *wadOpen(const char* path) -{ - - wadFile_t *wf = NULL; - - if (!path) - return NULL; - - wf = new wadFile_s; - memset (wf, 0, sizeof(*wf)); - - if (!wf) - return NULL; - - wf->fin=fopen(path,"rb"); - if (wf->fin==NULL) - return wadCleanup(wf); - - // get the file size - if (fseek(wf->fin,0,SEEK_END) != 0) - return wadCleanup(wf); - - wf->FileSize = ftell( wf->fin ); - - // Make sure it's at least big enough to manipulate the header - if (wf->FileSize < sizeof(WAD3_HEADER)) - { - // WAD3 file is malformed. - return wadCleanup(wf); - } - - // go back to the start - if (fseek(wf->fin,0,SEEK_SET)!=0) - return wadCleanup(wf); - - // allocate buffers - wf->lpHeader = (LPWAD3_HEADER) malloc(sizeof(WAD3_HEADER)); - wf->lpLump = (LPWAD3_LUMP) malloc(sizeof(WAD3_LUMP)); - wf->lpMip = (LPWAD3_MIP) malloc(sizeof(WAD3_MIP)); - - if (!(wf->lpHeader) || !(wf->lpLump) || !(wf->lpMip)) - return wadCleanup(wf); - - // read the header. - if (fread(wf->lpHeader,sizeof(WAD3_HEADER),1,wf->fin)!=1) - return wadCleanup(wf); - - if (wf->lpHeader->identification != WAD2_ID && wf->lpHeader->identification != WAD3_ID) - { - // Invalid WAD3 header id. - return wadCleanup(wf); - } - - // Make sure our table is really there - if ( ((wf->lpHeader->numlumps * sizeof(WAD3_LUMP)) + wf->lpHeader->infotableofs) > wf->FileSize) - { - // WAD3 file is malformed. - return wadCleanup(wf); - } - - // Store the name of the wadfile - if (!(wf->wadfilename = strdup(path))) - return wadCleanup(wf); - - return wf; -} - -int wadOpenCurrentFileByNum (wadFile_t *wf, unsigned long filenumber) -{ - /* returns 0 if error, or 1 for sucess */ - return(wadGoToFile(wf, filenumber)); -} - -void wadCloseCurrentFile (wadFile_t *wf) -{ - // nothing to do really... -} - -unsigned long wadReadCurrentFile (wadFile_t *wf , char *bufferptr, unsigned long size) -{ - // returns 0 if error, or the amount of data read into the buffer - if (fread(wf->lpLump,sizeof(WAD3_LUMP),1,wf->fin)!=1) - return 0; - - // dunno how to handle any other image types but this (yet) - if (wf->lpLump->type != WAD2_TYPE_MIP && wf->lpLump->type != WAD3_TYPE_MIP) - return 0; - - // go to first mip - if (fseek(wf->fin, wf->lpLump->filepos, SEEK_SET) != 0) - return 0; - - if (fread(bufferptr,size,1,wf->fin) == 1) - return (size); - else - return 0; -} - -/* - -.. or we could do it the long way, and process the file as we go.. - - -*/ -/* -unsigned long wadReadCurrentFile (wadFile_t *wf , char *bufferptr, unsigned long size) -{ - // returns 0 if error, or the amount of data read into the buffer - unsigned long bufferpos; - unsigned long mipdatasize; - WORD palettesize; - - if (fread(wf->lpLump,sizeof(WAD3_LUMP),1,wf->fin)!=1) - return 0; - - if (wf->lpLump->type == WAD3_TYPE_MIP) // can we handle it ? - { - - // bounds check. - if (wf->lpLump->filepos >= wf->FileSize) - return 0; // malformed wad3 - - // go to first mip - if (fseek(wf->fin, wf->lpLump->filepos, SEEK_SET) != 0) - return 0; - - // and read it - if (fread(wf->lpMip,sizeof(WAD3_MIP),1,wf->fin)!=1) - return 0; - - // store in buffer. - memcpy(bufferptr, wf->lpMip, sizeof(WAD3_MIP)); - bufferpos = sizeof(WAD3_MIP); - - // now read the MIP data. - // mip data - if (fseek(wf->fin, wf->lpLump->filepos + wf->lpMip->offsets[0], SEEK_SET) != 0) - return 0; - - mipdatasize = GET_MIP_DATA_SIZE(wf->lpMip->width,wf->lpMip->height); - - if (fread(bufferptr+bufferpos, mipdatasize, 1, wf->fin)!=1) - return 0; - - bufferpos += mipdatasize; - - // ok, that's the mip data itself, now grab the palette size. - if (fread(bufferptr+bufferpos,sizeof(WORD),1,wf->fin)!=1) - return 0; - - palettesize = *(WORD *)(bufferptr+bufferpos); - - bufferpos += sizeof(WORD); - - // grab the palette itself - if (fread(bufferptr+bufferpos,palettesize*3,1,wf->fin)!=1) - return 0; - - bufferpos += palettesize*3; - - // and finally the one-word padding. - if (fread(bufferptr+bufferpos,sizeof(WORD),1,wf->fin)!=1) - return 0; - - bufferpos += sizeof(WORD); - - return(bufferpos); // return the amount of bytes read. - } - return 0; -} -*/ +#include +#include +#include + +#include "unwad.h" + + +wadFile_t *wadCleanup(wadFile_t *wf) +{ + if (wf) + { + if (wf->fin) fclose(wf->fin); + if (wf->lpHeader) free(wf->lpHeader); + if (wf->lpLump) free(wf->lpLump); + if (wf->lpMip) free(wf->lpMip); + if (wf->wadfilename) free(wf->wadfilename); + free (wf); + wf = NULL; + } + return wf; +} + +int wadGetCurrentFileInfo ( wadFile_t *wf, char *szFileName, unsigned long fileNameBufferSize, unsigned long *filesize) +{ + /* returns 0 if error, or 1 for sucess */ + // if this fails you'll need to re-position the fileposition + // before attempting any other calls. e.g. call wadGoToFirstFile() + + if (fread(wf->lpLump,sizeof(WAD3_LUMP),1,wf->fin)!=1) + return 0; + strncpy(szFileName, wf->lpLump->name, fileNameBufferSize); + szFileName[fileNameBufferSize-1] = 0; // null terminate + + *filesize = wf->lpLump->size; + + return 1; +} + +int wadGoToFile(wadFile_t *wf, unsigned long filenum) +{ + if (!wf) + return 0; + + if (!wf->fin) + return 0; + + if (filenum >= wf->lpHeader->numlumps) + return 0; + + if (fseek(wf->fin,wf->lpHeader->infotableofs + (filenum * sizeof(WAD3_LUMP)),SEEK_SET) != 0) + return 0; + + wf->currentfile = filenum; + + return 1; +} + +int wadGoToNextFile(wadFile_t *wf) +{ + return(wadGoToFile(wf, wf->currentfile + 1)); +} + +int wadGoToFirstFile(wadFile_t *wf) +{ + /* returns 0 if error, or 1 for sucess */ + + if (!wf) + return 0; + + if (!wf->fin) + return 0; + + if (fseek(wf->fin,wf->lpHeader->infotableofs,SEEK_SET) != 0) + return 0; + + wf->currentfile = 0; + + return 1; +} + +wadFile_t *wadOpen(const char* path) +{ + + wadFile_t *wf = NULL; + + if (!path) + return NULL; + + wf = new wadFile_s; + memset (wf, 0, sizeof(*wf)); + + if (!wf) + return NULL; + + wf->fin=fopen(path,"rb"); + if (wf->fin==NULL) + return wadCleanup(wf); + + // get the file size + if (fseek(wf->fin,0,SEEK_END) != 0) + return wadCleanup(wf); + + wf->FileSize = ftell( wf->fin ); + + // Make sure it's at least big enough to manipulate the header + if (wf->FileSize < sizeof(WAD3_HEADER)) + { + // WAD3 file is malformed. + return wadCleanup(wf); + } + + // go back to the start + if (fseek(wf->fin,0,SEEK_SET)!=0) + return wadCleanup(wf); + + // allocate buffers + wf->lpHeader = (LPWAD3_HEADER) malloc(sizeof(WAD3_HEADER)); + wf->lpLump = (LPWAD3_LUMP) malloc(sizeof(WAD3_LUMP)); + wf->lpMip = (LPWAD3_MIP) malloc(sizeof(WAD3_MIP)); + + if (!(wf->lpHeader) || !(wf->lpLump) || !(wf->lpMip)) + return wadCleanup(wf); + + // read the header. + if (fread(wf->lpHeader,sizeof(WAD3_HEADER),1,wf->fin)!=1) + return wadCleanup(wf); + + if (wf->lpHeader->identification != WAD2_ID && wf->lpHeader->identification != WAD3_ID) + { + // Invalid WAD3 header id. + return wadCleanup(wf); + } + + // Make sure our table is really there + if ( ((wf->lpHeader->numlumps * sizeof(WAD3_LUMP)) + wf->lpHeader->infotableofs) > wf->FileSize) + { + // WAD3 file is malformed. + return wadCleanup(wf); + } + + // Store the name of the wadfile + if (!(wf->wadfilename = strdup(path))) + return wadCleanup(wf); + + return wf; +} + +int wadOpenCurrentFileByNum (wadFile_t *wf, unsigned long filenumber) +{ + /* returns 0 if error, or 1 for sucess */ + return(wadGoToFile(wf, filenumber)); +} + +void wadCloseCurrentFile (wadFile_t *wf) +{ + // nothing to do really... +} + +unsigned long wadReadCurrentFile (wadFile_t *wf , char *bufferptr, unsigned long size) +{ + // returns 0 if error, or the amount of data read into the buffer + if (fread(wf->lpLump,sizeof(WAD3_LUMP),1,wf->fin)!=1) + return 0; + + // dunno how to handle any other image types but this (yet) + if (wf->lpLump->type != WAD2_TYPE_MIP && wf->lpLump->type != WAD3_TYPE_MIP) + return 0; + + // go to first mip + if (fseek(wf->fin, wf->lpLump->filepos, SEEK_SET) != 0) + return 0; + + if (fread(bufferptr,size,1,wf->fin) == 1) + return (size); + else + return 0; +} + +/* + +.. or we could do it the long way, and process the file as we go.. + + +*/ +/* +unsigned long wadReadCurrentFile (wadFile_t *wf , char *bufferptr, unsigned long size) +{ + // returns 0 if error, or the amount of data read into the buffer + unsigned long bufferpos; + unsigned long mipdatasize; + WORD palettesize; + + if (fread(wf->lpLump,sizeof(WAD3_LUMP),1,wf->fin)!=1) + return 0; + + if (wf->lpLump->type == WAD3_TYPE_MIP) // can we handle it ? + { + + // bounds check. + if (wf->lpLump->filepos >= wf->FileSize) + return 0; // malformed wad3 + + // go to first mip + if (fseek(wf->fin, wf->lpLump->filepos, SEEK_SET) != 0) + return 0; + + // and read it + if (fread(wf->lpMip,sizeof(WAD3_MIP),1,wf->fin)!=1) + return 0; + + // store in buffer. + memcpy(bufferptr, wf->lpMip, sizeof(WAD3_MIP)); + bufferpos = sizeof(WAD3_MIP); + + // now read the MIP data. + // mip data + if (fseek(wf->fin, wf->lpLump->filepos + wf->lpMip->offsets[0], SEEK_SET) != 0) + return 0; + + mipdatasize = GET_MIP_DATA_SIZE(wf->lpMip->width,wf->lpMip->height); + + if (fread(bufferptr+bufferpos, mipdatasize, 1, wf->fin)!=1) + return 0; + + bufferpos += mipdatasize; + + // ok, that's the mip data itself, now grab the palette size. + if (fread(bufferptr+bufferpos,sizeof(WORD),1,wf->fin)!=1) + return 0; + + palettesize = *(WORD *)(bufferptr+bufferpos); + + bufferpos += sizeof(WORD); + + // grab the palette itself + if (fread(bufferptr+bufferpos,palettesize*3,1,wf->fin)!=1) + return 0; + + bufferpos += palettesize*3; + + // and finally the one-word padding. + if (fread(bufferptr+bufferpos,sizeof(WORD),1,wf->fin)!=1) + return 0; + + bufferpos += sizeof(WORD); + + return(bufferpos); // return the amount of bytes read. + } + return 0; +} +*/ diff --git a/plugins/vfswad/vfs.cpp b/plugins/vfswad/vfs.cpp index 5a1ab58c..251fc704 100644 --- a/plugins/vfswad/vfs.cpp +++ b/plugins/vfswad/vfs.cpp @@ -1,759 +1,759 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -// -// Rules: -// -// - Directories should be searched in the following order: ~/.q3a/baseq3, -// install dir (/usr/local/games/quake3/baseq3) and cd_path (/mnt/cdrom/baseq3). -// -// - Pak files are searched first inside the directories. -// - Case insensitive. -// - Unix-style slashes (/) (windows is backwards .. everyone knows that) -// -// Leonardo Zide (leo@lokigames.com) -// - -#include -#include - -#if defined (__linux__) || defined (__APPLE__) - #include - #include -#else - #include - #include - #define R_OK 04 - #define S_ISDIR(mode) (mode & _S_IFDIR) -#endif - -// TTimo: String functions -// see http://www.qeradiant.com/faq/index.cgi?file=175 -#include "str.h" - -#include -#include - -#include "vfswad.h" -#include "vfs.h" -#include "unwad.h" - -typedef struct -{ - char* name; - WAD3_LUMP wadlump; - wadFile_t *wadfile; - unsigned long filenumber; - unsigned long size; -} VFS_PAKFILE; - -// ============================================================================= -// Global variables - -static GSList* g_wadFiles; -static GSList* g_pakFiles; -static char g_strDirs[VFS_MAXDIRS][PATH_MAX]; -static int g_numDirs; - -// ============================================================================= -// Static functions - -static void vfsAddSlash (char *str) -{ - int n = strlen (str); - if (n > 0) - { - if (str[n-1] != '\\' && str[n-1] != '/') - strcat (str, "/"); - } -} - -static void vfsFixDOSName (char *src) -{ - if (src == NULL) - return; - - while (*src) - { - if (*src == '\\') - *src = '/'; - src++; - } -} - -//FIXME: STUPID short filenames.. get RID of it asap -// copied verbatim from qe3.cpp -int vfsBuildShortPathName(const char* pPath, char* pBuffer, int nBufferLen) -{ -#ifdef _WIN32 - char *pFile = NULL; - int nResult = GetFullPathName(pPath, nBufferLen, pBuffer, &pFile); - nResult = GetShortPathName(pPath, pBuffer, nBufferLen); - if (nResult == 0) - strcpy(pBuffer, pPath); // Use long filename - return nResult; -#endif - -#if defined (__linux__) || defined (__APPLE__) - - // remove /../ from directories - const char *scr = pPath; char *dst = pBuffer; - for (int i = 0; (i < nBufferLen) && (*scr != 0); i++) - { - if (*scr == '/' && *(scr+1) == '.' && *(scr+2) == '.') - { - scr += 3; - while (dst != pBuffer && *(--dst) != '/') - { - i--; - } - } - - *dst = *scr; - - scr++; dst++; - } - *dst = 0; - - return strlen (pBuffer); -#endif -} - -static void vfsInitPakFile (const char *filename) -{ - wadFile_t *wf; - unsigned int i; - int err; - char *wadnameptr; - char wadname[NAME_MAX]; - - wf = wadOpen (filename); - if (wf == NULL) - { - g_FuncTable.m_pfnSysFPrintf(SYS_WRN, " failed to init wad file %s\n", filename); - return; - } - g_FuncTable.m_pfnSysPrintf(" wad file: %s\n", filename); - - for (i = strlen(filename)-1 ; i >= 0 && filename[i] != '\\' && filename[i] != '/' ; i --) - wadnameptr = (char *)filename + i; - - strcpy(wadname,wadnameptr); - wadname[strlen(wadname)-4] = 0; // ditch the .wad so everthing looks nice! - - g_wadFiles = g_slist_append (g_wadFiles, wf); // store the wadfile handle - - wadGoToFirstFile(wf); - - for (i = 0; i < wf->lpHeader->numlumps; i++) - { - char filename_inwad[NAME_MAX]; - char filename_inwadfixed[NAME_MAX]; - unsigned long filesize; - VFS_PAKFILE* file; - - err = wadGetCurrentFileInfo (wf, filename_inwad, sizeof(filename_inwad) - 5, &filesize); // -5 for extension + null terminator - if (err != 1) - break; - - file = (VFS_PAKFILE*)g_malloc (sizeof (VFS_PAKFILE)); - g_pakFiles = g_slist_append (g_pakFiles, file); - - vfsFixDOSName (filename_inwad); - g_strdown (filename_inwad); - - // texturenames in wad files don't have an extensions or paths, so we must add them! - if (wf->lpLump->type == WAD2_TYPE_MIP) - { - sprintf(filename_inwadfixed,"textures/%s/%s.mip",wadname,filename_inwad); - }else { - sprintf(filename_inwadfixed,"textures/%s/%s.hlw",wadname,filename_inwad); - } - - //g_FuncTable.m_pfnSysFPrintf(SYS_WRN, " scanned %s\\%s\n", filename,filename_inwad); - - file->name = g_strdup (filename_inwadfixed); - file->size = filesize; - file->filenumber = wf->currentfile; - file->wadfile = wf; - memcpy(&file->wadlump, wf->lpLump, sizeof(WAD3_LUMP)); - - err = wadGoToNextFile(wf); - if (err != 1) - break; - } -} - -static GSList* vfsGetListInternal (const char *refdir, const char *ext, bool directories) -{ - GSList *lst, *lst_aux, *files = NULL; - char dirname[NAME_MAX], extension[NAME_MAX], filename[NAME_MAX]; - char basedir[NAME_MAX]; - int dirlen; - char *ptr; - struct stat st; - int i; - - if (refdir != NULL) - { - strcpy (dirname, refdir); - g_strdown (dirname); - vfsFixDOSName (dirname); - vfsAddSlash (dirname); - } else - dirname[0] = '\0'; - dirlen = strlen (dirname); - - if (ext != NULL) - strcpy (extension, ext); - else - extension[0] = '\0'; - g_strdown (extension); - - for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) - { - VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; - gboolean found = FALSE; - ptr = file->name; - - // check that the file name begins with dirname - for (i = 0; (*ptr && i < dirlen); i++, ptr++) - if (*ptr != dirname[i]) - break; - - if (i != dirlen) - continue; - - if (directories) - { - char *sep = strchr (ptr, '/'); - if (sep == NULL) - continue; - - i = sep-ptr; - - // check for duplicates - for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) - if (strncmp ((char*)lst_aux->data, ptr, i) == 0) - { - found = TRUE; - break; - } - - if (!found) - { - char *name = g_strndup (ptr, i+1); - name[i] = '\0'; - files = g_slist_append (files, name); - } - } else - { - // check extension - char *ptr_ext = strrchr (ptr, '.'); - if ((ext != NULL) && ((ptr_ext == NULL) || (strcmp (ptr_ext+1, extension) != 0))) - continue; - - // check for duplicates - for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) - if (strcmp ((char*)lst_aux->data, ptr) == 0) - { - found = TRUE; - break; - } - - if (!found) - files = g_slist_append (files, g_strdup (ptr)); - } - } - - for (i = 0; i < g_numDirs; i++) - { - strcpy (basedir, g_strDirs[i]); - strcat (basedir, dirname); - - GDir* dir = g_dir_open (basedir, 0, NULL); - - if (dir != NULL) - { - for(;;) - { - const char* name = g_dir_read_name(dir); - if(name == NULL) - break; - - if (directories && (name[0] == '.')) - continue; - - sprintf (filename, "%s%s", basedir, name); - stat (filename, &st); - - if ((S_ISDIR (st.st_mode) != 0) != directories) - continue; - - gboolean found = FALSE; - - char* direntry = g_strdup(name); - - g_strdown (direntry); - - char *ptr_ext = strrchr (direntry, '.'); - - if(ext == NULL - || (ext != NULL && ptr_ext != NULL && ptr_ext[0] != '\0' && strcmp (ptr_ext+1, extension) == 0)) - { - - // check for duplicates - for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) - if (strcmp ((char*)lst_aux->data, direntry) == 0) - { - found = TRUE; - break; - } - - if (!found) - files = g_slist_append (files, g_strdup (direntry)); - } - - g_free(direntry); - } - g_dir_close(dir); - } - } - - return files; -} - -// ============================================================================= -// Global functions - -// reads all pak files from a dir -void vfsInitDirectory (const char *path) -{ - char filename[PATH_MAX]; - - if (g_numDirs == (VFS_MAXDIRS-1)) - return; - - strcpy (g_strDirs[g_numDirs], path); - vfsFixDOSName (g_strDirs[g_numDirs]); - vfsAddSlash (g_strDirs[g_numDirs]); - g_numDirs++; - -// if (g_PrefsDlg.m_bPAK) - // TODO: can't read prefs from a module, bah.. - if (1) - { - GDir* dir = g_dir_open (path, 0, NULL); - if (dir != NULL) - { - g_FuncTable.m_pfnSysPrintf("vfs directory: %s\n", path); - while (1) - { - const char* name = g_dir_read_name(dir); - if(name == NULL) - break; - - char *ext = strrchr (name, '.'); - if ((ext == NULL) || (strcmp (ext, ".wad") != 0)) - continue; - - sprintf (filename, "%s/%s", path, name); - vfsInitPakFile (filename); - } - g_dir_close (dir); - } else - g_FuncTable.m_pfnSysFPrintf(SYS_WRN, "vfs directory not found: %s\n", path); - } -} - -// frees all memory that we allocated -// FIXME TTimo this should be improved so that we can shutdown and restart the VFS without exiting Radiant? -// (for instance when modifying the project settings) -void vfsShutdown () -{ - wadFile_t *tmpptr; - - while (g_wadFiles) - { - wadCleanup((wadFile_t *)g_wadFiles->data); - g_wadFiles = g_slist_remove (g_wadFiles, g_wadFiles->data); - } - - // avoid dangling pointer operation (makes BC hangry) - GSList *cur = g_pakFiles; - GSList *next = cur; - while (next) - { - cur = next; - VFS_PAKFILE* file = (VFS_PAKFILE*)cur->data; - g_free (file->name); - g_free (file); - next = g_slist_remove (cur, file); - } - g_pakFiles = NULL; -} - -void vfsFreeFile (void *p) -{ - g_free(p); -} - -GSList* vfsGetFileList (const char *dir, const char *ext) -{ - return vfsGetListInternal (dir, ext, false); -} - -GSList* vfsGetDirList (const char *dir) -{ - return vfsGetListInternal (dir, NULL, true); -} - -void vfsClearFileDirList (GSList **lst) -{ - while (*lst) - { - g_free ((*lst)->data); - *lst = g_slist_remove (*lst, (*lst)->data); - } -} - -// return the number of files that match -int vfsGetFileCount (const char *filename, int flag) -{ - int i, count = 0; - char fixed[NAME_MAX], tmp[NAME_MAX]; - GSList *lst; - - strcpy (fixed, filename); - vfsFixDOSName (fixed); - g_strdown (fixed); - - if (!flag || (flag & VFS_SEARCH_PAK)) - { - for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) - { - VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; - - if (strcmp (file->name, fixed) == 0) - count++; - } - } - - if (!flag || (flag & VFS_SEARCH_DIR)) - { - for (i = 0; i < g_numDirs; i++) - { - strcpy (tmp, g_strDirs[i]); - strcat (tmp, fixed); - if (access (tmp, R_OK) == 0) - count++; - } - } - - return count; -} - -// open a full path file -int vfsLoadFullPathFile (const char *filename, void **bufferptr) -{ - FILE *f; - long len; - - f = fopen (filename, "rb"); - if (f == NULL) - return -1; - - fseek (f, 0, SEEK_END); - len = ftell (f); - rewind (f); - - *bufferptr = g_malloc (len+1); - if (*bufferptr == NULL) - return -1; - - fread (*bufferptr, 1, len, f); - fclose (f); - - // we need to end the buffer with a 0 - ((char*) (*bufferptr))[len] = 0; - - return len; -} - -// NOTE: when loading a file, you have to allocate one extra byte and set it to \0 -int vfsLoadFile (const char *filename, void **bufferptr, int index) -{ - int i, count = 0; - char tmp[NAME_MAX], fixed[NAME_MAX]; - GSList *lst; - - *bufferptr = NULL; - strcpy (fixed, filename); - vfsFixDOSName (fixed); - g_strdown (fixed); - - for (i = 0; i < g_numDirs; i++) - { - strcpy (tmp, g_strDirs[i]); - strcat (tmp, filename); - if (access (tmp, R_OK) == 0) - { - if (count == index) - { - return vfsLoadFullPathFile(tmp,bufferptr); - /* - long len; - FILE *f; - - f = fopen (tmp, "rb"); - if (f == NULL) - return -1; - - fseek (f, 0, SEEK_END); - len = ftell (f); - rewind (f); - - *bufferptr = g_malloc (len+1); - if (*bufferptr == NULL) - return -1; - - fread (*bufferptr, 1, len, f); - fclose (f); - - // we need to end the buffer with a 0 - ((char*) (*bufferptr))[len] = 0; - - return len; - */ - } - - count++; - } - } - - - // Textures in HalfLife wads don't have paths, but in the list of files - // we store the actual full paths of the files and what WAD they're in. - // so what we have to do is strip the paths and just compare filenames. - - // Hydra: well, we did do this, but now we don't, as the map loader now - // fills in the correct paths for each texture. - - /* - char *searchname; - char *fixedptr; - - fixedptr = fixed; - - for (i = strlen(fixed)-1 ; i >= 0 && fixed[i] != '\\' && fixed[i] != '/' ; i --) - fixedptr = (char *)fixed + i; - */ - for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) - { - VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; - - - /* - searchname = file->name; - for (i = strlen(file->name)-1 ; i >= 0 && file->name[i] != '\\' && file->name[i] != '/' ; i --) - searchname = (char *)file->name + i; - if (strcmp (searchname, fixedptr) != 0) - continue; - */ - - if (strcmp (file->name, fixed) != 0) - continue; - - if (count == index) - { - // Useful for debugging - //Sys_Printf("VFSWAD: reading from %s\n",file->wadfile->wadfilename); - - if (wadOpenCurrentFileByNum (file->wadfile, file->filenumber) != 1) - return -1; - - *bufferptr = g_malloc (file->size+1); - // we need to end the buffer with a 0 - ((char*) (*bufferptr))[file->size] = 0; - - i = wadReadCurrentFile (file->wadfile , (char *)*bufferptr, file->size); - wadCloseCurrentFile (file->wadfile); - if (i > 0) - return file->size; - else - return -1; - } - - count++; - } - - return -1; -} - -//#ifdef _DEBUG -#if 0 - #define DBG_RLTPATH -#endif - -char* vfsExtractRelativePath(const char *in) -{ - int i; - char l_in[PATH_MAX]; - char check[PATH_MAX]; - static char out[PATH_MAX]; - out[0] = 0; - -#ifdef DBG_RLTPATH - Sys_Printf("vfsExtractRelativePath: %s\n", in); -#endif - - strcpy(l_in,in); - vfsCleanFileName(l_in); - -#ifdef DBG_RLTPATH - Sys_Printf("cleaned path: %s\n", l_in); -#endif - - for (i = 0; i < g_numDirs; i++) - { - strcpy(check,g_strDirs[i]); - vfsCleanFileName(check); -#ifdef DBG_RLTPATH - Sys_Printf("Matching against %s\n", check); -#endif - - // try to find a match - if (strstr(l_in, check)) - { - strcpy(out,l_in+strlen(check)+1); - break; - } - } - if (out[0]!=0) - { -#ifdef DBG_RLTPATH - Sys_Printf("vfsExtractRelativePath: success\n"); -#endif - return out; - } -#ifdef DBG_RLTPATH - Sys_Printf("vfsExtractRelativePath: failed\n"); -#endif - return NULL; -} - -// removed CString usage -void vfsCleanFileName(char *in) -{ - char str[PATH_MAX]; - vfsBuildShortPathName (in, str, PATH_MAX); - strlwr(str); - vfsFixDOSName(str); - int n = strlen(str); - if (str[n-1] == '/') - str[n-1] = '\0'; - strcpy (in, str); -} - -// HYDRA: this now searches VFS/PAK files in addition to the filesystem -// if FLAG is unspecified then ONLY dirs are searched. -// PAK's are searched before DIRs to mimic engine behaviour -// index is ignored when searching PAK files. -// see ifilesystem.h -char* vfsGetFullPath(const char *in, int index, int flag) -{ - int count = 0; - static char out[PATH_MAX]; - char tmp[NAME_MAX]; - int i; - - if (flag & VFS_SEARCH_PAK) - { - char fixed[NAME_MAX]; - GSList *lst; - - strcpy (fixed, in); - vfsFixDOSName (fixed); - g_strdown (fixed); - - for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) - { - VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; - - char *ptr,*lastptr; - lastptr = file->name; - - while (ptr = strchr(lastptr,'/')) - lastptr = ptr+1; - - if (strcmp (lastptr, fixed) == 0) - { - strncpy(out,file->name,PATH_MAX); - return out; - } - } - - } - - if (!flag || (flag & VFS_SEARCH_DIR)) - { - for (i = 0; i < g_numDirs; i++) - { - strcpy (tmp, g_strDirs[i]); - strcat (tmp, in); - if (access (tmp, R_OK) == 0) - { - if (count == index) - { - strcpy (out, tmp); - return out; - } - count++; - } - } - } - return NULL; -} - -// TODO TTimo on linux the base prompt is ~/.q3a/ -// given the file dialog, we could push the strFSBasePath and ~/.q3a into the directory shortcuts -// FIXME TTimo is this really a VFS functionality? -// actually .. this should be the decision of the core isn't it? -// or .. add an API so that the base prompt can be set during VFS init -const char* vfsBasePromptPath() -{ -#ifdef _WIN32 - static char* path = "C:"; -#else - static char* path = "/"; -#endif - return path; -} - +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// +// Rules: +// +// - Directories should be searched in the following order: ~/.q3a/baseq3, +// install dir (/usr/local/games/quake3/baseq3) and cd_path (/mnt/cdrom/baseq3). +// +// - Pak files are searched first inside the directories. +// - Case insensitive. +// - Unix-style slashes (/) (windows is backwards .. everyone knows that) +// +// Leonardo Zide (leo@lokigames.com) +// + +#include +#include + +#if defined (__linux__) || defined (__APPLE__) + #include + #include +#else + #include + #include + #define R_OK 04 + #define S_ISDIR(mode) (mode & _S_IFDIR) +#endif + +// TTimo: String functions +// see http://www.qeradiant.com/faq/index.cgi?file=175 +#include "str.h" + +#include +#include + +#include "vfswad.h" +#include "vfs.h" +#include "unwad.h" + +typedef struct +{ + char* name; + WAD3_LUMP wadlump; + wadFile_t *wadfile; + unsigned long filenumber; + unsigned long size; +} VFS_PAKFILE; + +// ============================================================================= +// Global variables + +static GSList* g_wadFiles; +static GSList* g_pakFiles; +static char g_strDirs[VFS_MAXDIRS][PATH_MAX]; +static int g_numDirs; + +// ============================================================================= +// Static functions + +static void vfsAddSlash (char *str) +{ + int n = strlen (str); + if (n > 0) + { + if (str[n-1] != '\\' && str[n-1] != '/') + strcat (str, "/"); + } +} + +static void vfsFixDOSName (char *src) +{ + if (src == NULL) + return; + + while (*src) + { + if (*src == '\\') + *src = '/'; + src++; + } +} + +//FIXME: STUPID short filenames.. get RID of it asap +// copied verbatim from qe3.cpp +int vfsBuildShortPathName(const char* pPath, char* pBuffer, int nBufferLen) +{ +#ifdef _WIN32 + char *pFile = NULL; + int nResult = GetFullPathName(pPath, nBufferLen, pBuffer, &pFile); + nResult = GetShortPathName(pPath, pBuffer, nBufferLen); + if (nResult == 0) + strcpy(pBuffer, pPath); // Use long filename + return nResult; +#endif + +#if defined (__linux__) || defined (__APPLE__) + + // remove /../ from directories + const char *scr = pPath; char *dst = pBuffer; + for (int i = 0; (i < nBufferLen) && (*scr != 0); i++) + { + if (*scr == '/' && *(scr+1) == '.' && *(scr+2) == '.') + { + scr += 3; + while (dst != pBuffer && *(--dst) != '/') + { + i--; + } + } + + *dst = *scr; + + scr++; dst++; + } + *dst = 0; + + return strlen (pBuffer); +#endif +} + +static void vfsInitPakFile (const char *filename) +{ + wadFile_t *wf; + unsigned int i; + int err; + char *wadnameptr; + char wadname[NAME_MAX]; + + wf = wadOpen (filename); + if (wf == NULL) + { + g_FuncTable.m_pfnSysFPrintf(SYS_WRN, " failed to init wad file %s\n", filename); + return; + } + g_FuncTable.m_pfnSysPrintf(" wad file: %s\n", filename); + + for (i = strlen(filename)-1 ; i >= 0 && filename[i] != '\\' && filename[i] != '/' ; i --) + wadnameptr = (char *)filename + i; + + strcpy(wadname,wadnameptr); + wadname[strlen(wadname)-4] = 0; // ditch the .wad so everthing looks nice! + + g_wadFiles = g_slist_append (g_wadFiles, wf); // store the wadfile handle + + wadGoToFirstFile(wf); + + for (i = 0; i < wf->lpHeader->numlumps; i++) + { + char filename_inwad[NAME_MAX]; + char filename_inwadfixed[NAME_MAX]; + unsigned long filesize; + VFS_PAKFILE* file; + + err = wadGetCurrentFileInfo (wf, filename_inwad, sizeof(filename_inwad) - 5, &filesize); // -5 for extension + null terminator + if (err != 1) + break; + + file = (VFS_PAKFILE*)g_malloc (sizeof (VFS_PAKFILE)); + g_pakFiles = g_slist_append (g_pakFiles, file); + + vfsFixDOSName (filename_inwad); + g_strdown (filename_inwad); + + // texturenames in wad files don't have an extensions or paths, so we must add them! + if (wf->lpLump->type == WAD2_TYPE_MIP) + { + sprintf(filename_inwadfixed,"textures/%s/%s.mip",wadname,filename_inwad); + }else { + sprintf(filename_inwadfixed,"textures/%s/%s.hlw",wadname,filename_inwad); + } + + //g_FuncTable.m_pfnSysFPrintf(SYS_WRN, " scanned %s\\%s\n", filename,filename_inwad); + + file->name = g_strdup (filename_inwadfixed); + file->size = filesize; + file->filenumber = wf->currentfile; + file->wadfile = wf; + memcpy(&file->wadlump, wf->lpLump, sizeof(WAD3_LUMP)); + + err = wadGoToNextFile(wf); + if (err != 1) + break; + } +} + +static GSList* vfsGetListInternal (const char *refdir, const char *ext, bool directories) +{ + GSList *lst, *lst_aux, *files = NULL; + char dirname[NAME_MAX], extension[NAME_MAX], filename[NAME_MAX]; + char basedir[NAME_MAX]; + int dirlen; + char *ptr; + struct stat st; + int i; + + if (refdir != NULL) + { + strcpy (dirname, refdir); + g_strdown (dirname); + vfsFixDOSName (dirname); + vfsAddSlash (dirname); + } else + dirname[0] = '\0'; + dirlen = strlen (dirname); + + if (ext != NULL) + strcpy (extension, ext); + else + extension[0] = '\0'; + g_strdown (extension); + + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + gboolean found = FALSE; + ptr = file->name; + + // check that the file name begins with dirname + for (i = 0; (*ptr && i < dirlen); i++, ptr++) + if (*ptr != dirname[i]) + break; + + if (i != dirlen) + continue; + + if (directories) + { + char *sep = strchr (ptr, '/'); + if (sep == NULL) + continue; + + i = sep-ptr; + + // check for duplicates + for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) + if (strncmp ((char*)lst_aux->data, ptr, i) == 0) + { + found = TRUE; + break; + } + + if (!found) + { + char *name = g_strndup (ptr, i+1); + name[i] = '\0'; + files = g_slist_append (files, name); + } + } else + { + // check extension + char *ptr_ext = strrchr (ptr, '.'); + if ((ext != NULL) && ((ptr_ext == NULL) || (strcmp (ptr_ext+1, extension) != 0))) + continue; + + // check for duplicates + for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) + if (strcmp ((char*)lst_aux->data, ptr) == 0) + { + found = TRUE; + break; + } + + if (!found) + files = g_slist_append (files, g_strdup (ptr)); + } + } + + for (i = 0; i < g_numDirs; i++) + { + strcpy (basedir, g_strDirs[i]); + strcat (basedir, dirname); + + GDir* dir = g_dir_open (basedir, 0, NULL); + + if (dir != NULL) + { + for(;;) + { + const char* name = g_dir_read_name(dir); + if(name == NULL) + break; + + if (directories && (name[0] == '.')) + continue; + + sprintf (filename, "%s%s", basedir, name); + stat (filename, &st); + + if ((S_ISDIR (st.st_mode) != 0) != directories) + continue; + + gboolean found = FALSE; + + char* direntry = g_strdup(name); + + g_strdown (direntry); + + char *ptr_ext = strrchr (direntry, '.'); + + if(ext == NULL + || (ext != NULL && ptr_ext != NULL && ptr_ext[0] != '\0' && strcmp (ptr_ext+1, extension) == 0)) + { + + // check for duplicates + for (lst_aux = files; lst_aux; lst_aux = g_slist_next (lst_aux)) + if (strcmp ((char*)lst_aux->data, direntry) == 0) + { + found = TRUE; + break; + } + + if (!found) + files = g_slist_append (files, g_strdup (direntry)); + } + + g_free(direntry); + } + g_dir_close(dir); + } + } + + return files; +} + +// ============================================================================= +// Global functions + +// reads all pak files from a dir +void vfsInitDirectory (const char *path) +{ + char filename[PATH_MAX]; + + if (g_numDirs == (VFS_MAXDIRS-1)) + return; + + strcpy (g_strDirs[g_numDirs], path); + vfsFixDOSName (g_strDirs[g_numDirs]); + vfsAddSlash (g_strDirs[g_numDirs]); + g_numDirs++; + +// if (g_PrefsDlg.m_bPAK) + // TODO: can't read prefs from a module, bah.. + if (1) + { + GDir* dir = g_dir_open (path, 0, NULL); + if (dir != NULL) + { + g_FuncTable.m_pfnSysPrintf("vfs directory: %s\n", path); + while (1) + { + const char* name = g_dir_read_name(dir); + if(name == NULL) + break; + + char *ext = strrchr (name, '.'); + if ((ext == NULL) || (strcmp (ext, ".wad") != 0)) + continue; + + sprintf (filename, "%s/%s", path, name); + vfsInitPakFile (filename); + } + g_dir_close (dir); + } else + g_FuncTable.m_pfnSysFPrintf(SYS_WRN, "vfs directory not found: %s\n", path); + } +} + +// frees all memory that we allocated +// FIXME TTimo this should be improved so that we can shutdown and restart the VFS without exiting Radiant? +// (for instance when modifying the project settings) +void vfsShutdown () +{ + wadFile_t *tmpptr; + + while (g_wadFiles) + { + wadCleanup((wadFile_t *)g_wadFiles->data); + g_wadFiles = g_slist_remove (g_wadFiles, g_wadFiles->data); + } + + // avoid dangling pointer operation (makes BC hangry) + GSList *cur = g_pakFiles; + GSList *next = cur; + while (next) + { + cur = next; + VFS_PAKFILE* file = (VFS_PAKFILE*)cur->data; + g_free (file->name); + g_free (file); + next = g_slist_remove (cur, file); + } + g_pakFiles = NULL; +} + +void vfsFreeFile (void *p) +{ + g_free(p); +} + +GSList* vfsGetFileList (const char *dir, const char *ext) +{ + return vfsGetListInternal (dir, ext, false); +} + +GSList* vfsGetDirList (const char *dir) +{ + return vfsGetListInternal (dir, NULL, true); +} + +void vfsClearFileDirList (GSList **lst) +{ + while (*lst) + { + g_free ((*lst)->data); + *lst = g_slist_remove (*lst, (*lst)->data); + } +} + +// return the number of files that match +int vfsGetFileCount (const char *filename, int flag) +{ + int i, count = 0; + char fixed[NAME_MAX], tmp[NAME_MAX]; + GSList *lst; + + strcpy (fixed, filename); + vfsFixDOSName (fixed); + g_strdown (fixed); + + if (!flag || (flag & VFS_SEARCH_PAK)) + { + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + + if (strcmp (file->name, fixed) == 0) + count++; + } + } + + if (!flag || (flag & VFS_SEARCH_DIR)) + { + for (i = 0; i < g_numDirs; i++) + { + strcpy (tmp, g_strDirs[i]); + strcat (tmp, fixed); + if (access (tmp, R_OK) == 0) + count++; + } + } + + return count; +} + +// open a full path file +int vfsLoadFullPathFile (const char *filename, void **bufferptr) +{ + FILE *f; + long len; + + f = fopen (filename, "rb"); + if (f == NULL) + return -1; + + fseek (f, 0, SEEK_END); + len = ftell (f); + rewind (f); + + *bufferptr = g_malloc (len+1); + if (*bufferptr == NULL) + return -1; + + fread (*bufferptr, 1, len, f); + fclose (f); + + // we need to end the buffer with a 0 + ((char*) (*bufferptr))[len] = 0; + + return len; +} + +// NOTE: when loading a file, you have to allocate one extra byte and set it to \0 +int vfsLoadFile (const char *filename, void **bufferptr, int index) +{ + int i, count = 0; + char tmp[NAME_MAX], fixed[NAME_MAX]; + GSList *lst; + + *bufferptr = NULL; + strcpy (fixed, filename); + vfsFixDOSName (fixed); + g_strdown (fixed); + + for (i = 0; i < g_numDirs; i++) + { + strcpy (tmp, g_strDirs[i]); + strcat (tmp, filename); + if (access (tmp, R_OK) == 0) + { + if (count == index) + { + return vfsLoadFullPathFile(tmp,bufferptr); + /* + long len; + FILE *f; + + f = fopen (tmp, "rb"); + if (f == NULL) + return -1; + + fseek (f, 0, SEEK_END); + len = ftell (f); + rewind (f); + + *bufferptr = g_malloc (len+1); + if (*bufferptr == NULL) + return -1; + + fread (*bufferptr, 1, len, f); + fclose (f); + + // we need to end the buffer with a 0 + ((char*) (*bufferptr))[len] = 0; + + return len; + */ + } + + count++; + } + } + + + // Textures in HalfLife wads don't have paths, but in the list of files + // we store the actual full paths of the files and what WAD they're in. + // so what we have to do is strip the paths and just compare filenames. + + // Hydra: well, we did do this, but now we don't, as the map loader now + // fills in the correct paths for each texture. + + /* + char *searchname; + char *fixedptr; + + fixedptr = fixed; + + for (i = strlen(fixed)-1 ; i >= 0 && fixed[i] != '\\' && fixed[i] != '/' ; i --) + fixedptr = (char *)fixed + i; + */ + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + + + /* + searchname = file->name; + for (i = strlen(file->name)-1 ; i >= 0 && file->name[i] != '\\' && file->name[i] != '/' ; i --) + searchname = (char *)file->name + i; + if (strcmp (searchname, fixedptr) != 0) + continue; + */ + + if (strcmp (file->name, fixed) != 0) + continue; + + if (count == index) + { + // Useful for debugging + //Sys_Printf("VFSWAD: reading from %s\n",file->wadfile->wadfilename); + + if (wadOpenCurrentFileByNum (file->wadfile, file->filenumber) != 1) + return -1; + + *bufferptr = g_malloc (file->size+1); + // we need to end the buffer with a 0 + ((char*) (*bufferptr))[file->size] = 0; + + i = wadReadCurrentFile (file->wadfile , (char *)*bufferptr, file->size); + wadCloseCurrentFile (file->wadfile); + if (i > 0) + return file->size; + else + return -1; + } + + count++; + } + + return -1; +} + +//#ifdef _DEBUG +#if 0 + #define DBG_RLTPATH +#endif + +char* vfsExtractRelativePath(const char *in) +{ + int i; + char l_in[PATH_MAX]; + char check[PATH_MAX]; + static char out[PATH_MAX]; + out[0] = 0; + +#ifdef DBG_RLTPATH + Sys_Printf("vfsExtractRelativePath: %s\n", in); +#endif + + strcpy(l_in,in); + vfsCleanFileName(l_in); + +#ifdef DBG_RLTPATH + Sys_Printf("cleaned path: %s\n", l_in); +#endif + + for (i = 0; i < g_numDirs; i++) + { + strcpy(check,g_strDirs[i]); + vfsCleanFileName(check); +#ifdef DBG_RLTPATH + Sys_Printf("Matching against %s\n", check); +#endif + + // try to find a match + if (strstr(l_in, check)) + { + strcpy(out,l_in+strlen(check)+1); + break; + } + } + if (out[0]!=0) + { +#ifdef DBG_RLTPATH + Sys_Printf("vfsExtractRelativePath: success\n"); +#endif + return out; + } +#ifdef DBG_RLTPATH + Sys_Printf("vfsExtractRelativePath: failed\n"); +#endif + return NULL; +} + +// removed CString usage +void vfsCleanFileName(char *in) +{ + char str[PATH_MAX]; + vfsBuildShortPathName (in, str, PATH_MAX); + strlwr(str); + vfsFixDOSName(str); + int n = strlen(str); + if (str[n-1] == '/') + str[n-1] = '\0'; + strcpy (in, str); +} + +// HYDRA: this now searches VFS/PAK files in addition to the filesystem +// if FLAG is unspecified then ONLY dirs are searched. +// PAK's are searched before DIRs to mimic engine behaviour +// index is ignored when searching PAK files. +// see ifilesystem.h +char* vfsGetFullPath(const char *in, int index, int flag) +{ + int count = 0; + static char out[PATH_MAX]; + char tmp[NAME_MAX]; + int i; + + if (flag & VFS_SEARCH_PAK) + { + char fixed[NAME_MAX]; + GSList *lst; + + strcpy (fixed, in); + vfsFixDOSName (fixed); + g_strdown (fixed); + + for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst)) + { + VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data; + + char *ptr,*lastptr; + lastptr = file->name; + + while (ptr = strchr(lastptr,'/')) + lastptr = ptr+1; + + if (strcmp (lastptr, fixed) == 0) + { + strncpy(out,file->name,PATH_MAX); + return out; + } + } + + } + + if (!flag || (flag & VFS_SEARCH_DIR)) + { + for (i = 0; i < g_numDirs; i++) + { + strcpy (tmp, g_strDirs[i]); + strcat (tmp, in); + if (access (tmp, R_OK) == 0) + { + if (count == index) + { + strcpy (out, tmp); + return out; + } + count++; + } + } + } + return NULL; +} + +// TODO TTimo on linux the base prompt is ~/.q3a/ +// given the file dialog, we could push the strFSBasePath and ~/.q3a into the directory shortcuts +// FIXME TTimo is this really a VFS functionality? +// actually .. this should be the decision of the core isn't it? +// or .. add an API so that the base prompt can be set during VFS init +const char* vfsBasePromptPath() +{ +#ifdef _WIN32 + static char* path = "C:"; +#else + static char* path = "/"; +#endif + return path; +} + diff --git a/plugins/vfswad/vfswad.cpp b/plugins/vfswad/vfswad.cpp index c54658fa..ee6e8b02 100644 --- a/plugins/vfswad/vfswad.cpp +++ b/plugins/vfswad/vfswad.cpp @@ -1,106 +1,106 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -// -// HalfLife Virtual FileSystem - reads files from different dirs and inside wad files -// -// Coding by Dominic Clifton - Hydra - hydra@hydras-world.com -// -// based on code by Leonardo Zide (leo@lokigames.com) -// - -#ifdef _WIN32 -#include -#endif - -#include -#include "vfswad.h" -#include "vfs.h" - -// ============================================================================= -// SYNAPSE - -_QERFuncTable_1 g_FuncTable; - -CSynapseServer* g_pSynapseServer = NULL; -CSynapseClientVFS 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(VFS_MAJOR, "wad", sizeof(_QERFileSystemTable)); - g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); - - return &g_SynapseClient; -} - -bool CSynapseClientVFS::RequestAPI(APIDescriptor_t *pAPI) -{ - if (!strcmp(pAPI->major_name, VFS_MAJOR)) - { - _QERFileSystemTable* pTable= static_cast<_QERFileSystemTable*>(pAPI->mpTable); - pTable->m_pfnInitDirectory = &vfsInitDirectory; - pTable->m_pfnShutdown = &vfsShutdown; - pTable->m_pfnFreeFile = &vfsFreeFile; - pTable->m_pfnGetDirList = &vfsGetDirList; - pTable->m_pfnGetFileList = &vfsGetFileList; - pTable->m_pfnClearFileDirList = &vfsClearFileDirList; - pTable->m_pfnGetFileCount = &vfsGetFileCount; - pTable->m_pfnLoadFile = &vfsLoadFile; - pTable->m_pfnLoadFullPathFile = &vfsLoadFullPathFile; - pTable->m_pfnExtractRelativePath = &vfsExtractRelativePath; - pTable->m_pfnGetFullPath = &vfsGetFullPath; - pTable->m_pfnBasePromptPath = &vfsBasePromptPath; - return true; - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -#include "version.h" - -const char* CSynapseClientVFS::GetInfo() -{ - return "WAD VFS module built " __DATE__ " " RADIANT_VERSION; -} +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// +// HalfLife Virtual FileSystem - reads files from different dirs and inside wad files +// +// Coding by Dominic Clifton - Hydra - hydra@hydras-world.com +// +// based on code by Leonardo Zide (leo@lokigames.com) +// + +#ifdef _WIN32 +#include +#endif + +#include +#include "vfswad.h" +#include "vfs.h" + +// ============================================================================= +// SYNAPSE + +_QERFuncTable_1 g_FuncTable; + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientVFS 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(VFS_MAJOR, "wad", sizeof(_QERFileSystemTable)); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + + return &g_SynapseClient; +} + +bool CSynapseClientVFS::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, VFS_MAJOR)) + { + _QERFileSystemTable* pTable= static_cast<_QERFileSystemTable*>(pAPI->mpTable); + pTable->m_pfnInitDirectory = &vfsInitDirectory; + pTable->m_pfnShutdown = &vfsShutdown; + pTable->m_pfnFreeFile = &vfsFreeFile; + pTable->m_pfnGetDirList = &vfsGetDirList; + pTable->m_pfnGetFileList = &vfsGetFileList; + pTable->m_pfnClearFileDirList = &vfsClearFileDirList; + pTable->m_pfnGetFileCount = &vfsGetFileCount; + pTable->m_pfnLoadFile = &vfsLoadFile; + pTable->m_pfnLoadFullPathFile = &vfsLoadFullPathFile; + pTable->m_pfnExtractRelativePath = &vfsExtractRelativePath; + pTable->m_pfnGetFullPath = &vfsGetFullPath; + pTable->m_pfnBasePromptPath = &vfsBasePromptPath; + return true; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientVFS::GetInfo() +{ + return "WAD VFS module built " __DATE__ " " RADIANT_VERSION; +} diff --git a/radiant/bp_dlg.cpp b/radiant/bp_dlg.cpp index beb2f050..ac71d3de 100644 --- a/radiant/bp_dlg.cpp +++ b/radiant/bp_dlg.cpp @@ -1,155 +1,155 @@ -/* -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 -*/ - -//----------------------------------------------------------------------------- -// -// DESCRIPTION -// -// custom Gtk dialog for brush primitives load/save - -#include "stdafx.h" - -void BP_dialog_button_callback (GtkWidget *widget, gpointer data) -{ - GtkWidget *parent; - int *loop, *ret; - - parent = gtk_widget_get_toplevel (widget); - loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); - ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); - - *loop = 0; - *ret = (int)data; -} - -gint BP_dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) -{ - int *loop; - - gtk_widget_hide (widget); - loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); - *loop = 0; - - return TRUE; -} - -// ret: 0 = abort, 1 = load and convert, 2 = changed project settings, load and don't convert -// the user might decide to switch the BP mode in project settings -// status: 0 = loading regular, got conflict 1 = loading BP, got conflict -// int WINAPI gtk_MessageBox (GtkWidget *parent, const char* lpText, const char* lpCaption, guint32 uType) -int BP_MessageBox (int status) -{ - GtkWidget *window, *w, *vbox, *hbox; - GtkAccelGroup *accel; - int ret, loop = 1; - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_signal_connect (GTK_OBJECT (window), "delete_event", - GTK_SIGNAL_FUNC (BP_dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (window), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - - gtk_window_set_title (GTK_WINDOW (window), "Current map format is incompatible"); - - gtk_container_border_width (GTK_CONTAINER (window), 10); - g_object_set_data (G_OBJECT (window), "loop", &loop); - g_object_set_data (G_OBJECT (window), "ret", &ret); - gtk_widget_realize (window); - - gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (g_pParentWnd->m_pWidget)); - - accel = gtk_accel_group_new (); - gtk_window_add_accel_group (GTK_WINDOW (window), accel); - - vbox = gtk_vbox_new (FALSE, 10); - gtk_container_add (GTK_CONTAINER (window), vbox); - gtk_widget_show (vbox); - - if (status == 0) - { - w = gtk_label_new ("This map was saved using brush primitives format\n" - "and your project settings use the standard format.\n" - "Do you want to convert the map, change default format or abort?\n" - "NOTE: due to limitations of the standard format, " - "some texture alignments may be lost after conversion."); - } - else - { - w = gtk_label_new ("This map was saved using standard format\n" - "and your project settings use the new \"brush primitives\" format.\n" - "Do you want to convert the map, change default format or abort?\n" - "NOTE: Next versions of Radiant will allow mixing the two formats" - "in the same maps for a smooth transition."); - } - gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); - gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); - gtk_widget_show (w); - - w = gtk_hseparator_new (); - gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); - gtk_widget_show (w); - - hbox = gtk_hbox_new (FALSE, 10); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); - gtk_widget_show (hbox); - - w = gtk_button_new_with_label ("Convert"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (BP_dialog_button_callback), GINT_TO_POINTER (1)); - GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); - gtk_widget_grab_default (w); - gtk_widget_show (w); - - w = gtk_button_new_with_label ("Change default"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (BP_dialog_button_callback), GINT_TO_POINTER (2)); - gtk_widget_show (w); - - w = gtk_button_new_with_label ("Abort load"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (BP_dialog_button_callback), GINT_TO_POINTER (0)); - gtk_widget_show (w); - ret = 0; // abort - - gtk_widget_show (window); - gtk_grab_add (window); - - while (loop) - gtk_main_iteration (); - - if (ret == 2) - { - // change project settings - if (status == 0) - g_qeglobals.m_bBrushPrimitMode = TRUE; - else - g_qeglobals.m_bBrushPrimitMode = FALSE; - SetKeyValue(g_qeglobals.d_project_entity, "brush_primit", (g_qeglobals.m_bBrushPrimitMode ? "1" : "0" )); - } - - gtk_grab_remove (window); - gtk_widget_destroy (window); - - return ret; -} +/* +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 +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION +// +// custom Gtk dialog for brush primitives load/save + +#include "stdafx.h" + +void BP_dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +gint BP_dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} + +// ret: 0 = abort, 1 = load and convert, 2 = changed project settings, load and don't convert +// the user might decide to switch the BP mode in project settings +// status: 0 = loading regular, got conflict 1 = loading BP, got conflict +// int WINAPI gtk_MessageBox (GtkWidget *parent, const char* lpText, const char* lpCaption, guint32 uType) +int BP_MessageBox (int status) +{ + GtkWidget *window, *w, *vbox, *hbox; + GtkAccelGroup *accel; + int ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + GTK_SIGNAL_FUNC (BP_dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title (GTK_WINDOW (window), "Current map format is incompatible"); + + gtk_container_border_width (GTK_CONTAINER (window), 10); + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + gtk_widget_realize (window); + + gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (g_pParentWnd->m_pWidget)); + + accel = gtk_accel_group_new (); + gtk_window_add_accel_group (GTK_WINDOW (window), accel); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + if (status == 0) + { + w = gtk_label_new ("This map was saved using brush primitives format\n" + "and your project settings use the standard format.\n" + "Do you want to convert the map, change default format or abort?\n" + "NOTE: due to limitations of the standard format, " + "some texture alignments may be lost after conversion."); + } + else + { + w = gtk_label_new ("This map was saved using standard format\n" + "and your project settings use the new \"brush primitives\" format.\n" + "Do you want to convert the map, change default format or abort?\n" + "NOTE: Next versions of Radiant will allow mixing the two formats" + "in the same maps for a smooth transition."); + } + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + w = gtk_button_new_with_label ("Convert"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (BP_dialog_button_callback), GINT_TO_POINTER (1)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Change default"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (BP_dialog_button_callback), GINT_TO_POINTER (2)); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Abort load"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (BP_dialog_button_callback), GINT_TO_POINTER (0)); + gtk_widget_show (w); + ret = 0; // abort + + gtk_widget_show (window); + gtk_grab_add (window); + + while (loop) + gtk_main_iteration (); + + if (ret == 2) + { + // change project settings + if (status == 0) + g_qeglobals.m_bBrushPrimitMode = TRUE; + else + g_qeglobals.m_bBrushPrimitMode = FALSE; + SetKeyValue(g_qeglobals.d_project_entity, "brush_primit", (g_qeglobals.m_bBrushPrimitMode ? "1" : "0" )); + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} diff --git a/radiant/brush.cpp b/radiant/brush.cpp index a57913ee..d6d1b95c 100644 --- a/radiant/brush.cpp +++ b/radiant/brush.cpp @@ -1,3644 +1,3644 @@ -/* -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 -*/ - -#include "stdafx.h" -#include -#include "winding.h" -#include -#include "filters.h" - -extern MainFrame* g_pParentWnd; -extern void MemFile_fprintf(MemStream* pMemFile, const char* pText, ...); - -// globals - -int g_nBrushId = 0; - -#ifdef ENABLE_GROUPS -const char* Brush_Name(brush_t *b) -{ - static char cBuff[1024]; - b->numberId = g_nBrushId++; - if (g_qeglobals.m_bBrushPrimitMode) - { - sprintf(cBuff, "Brush %i", b->numberId); - Brush_SetEpair(b, "Name", cBuff); - } - return cBuff; -} -#endif - -brush_t *Brush_Alloc() -{ - brush_t *b = (brush_t*)qmalloc(sizeof(brush_t)); - return b; -} -/* -void Brush_Free(brush_t *b) -{ - free(b); -} -*/ -void PrintWinding (winding_t *w) -{ - int i; - - Sys_Printf ("-------------\n"); - for (i=0 ; inumpoints ; i++) - Sys_Printf ("(%5.2f, %5.2f, %5.2f)\n", w->points[i][0] - , w->points[i][1], w->points[i][2]); -} - -void PrintPlane (plane_t *p) -{ - Sys_Printf ("(%5.2f, %5.2f, %5.2f) : %5.2f\n", p->normal[0], p->normal[1], - p->normal[2], p->dist); -} - -void PrintVector (vec3_t v) -{ - Sys_Printf ("(%5.2f, %5.2f, %5.2f)\n", v[0], v[1], v[2]); -} - - -/* -============================================================================= - - TEXTURE COORDINATES - -============================================================================= -*/ - - -/* -================== -textureAxisFromPlane -================== -*/ -vec3_t baseaxis[18] = -{ -{0,0,1}, {1,0,0}, {0,-1,0}, // floor -{0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling -{1,0,0}, {0,1,0}, {0,0,-1}, // west wall -{-1,0,0}, {0,1,0}, {0,0,-1}, // east wall -{0,1,0}, {1,0,0}, {0,0,-1}, // south wall -{0,-1,0}, {1,0,0}, {0,0,-1} // north wall -}; - -void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv) -{ - int bestaxis; - float dot,best; - int i; - - best = 0; - bestaxis = 0; - - for (i=0 ; i<6 ; i++) - { - dot = DotProduct (pln->normal, baseaxis[i*3]); - if (g_PrefsDlg.m_bQ3Map2Texturing && dot > best + 0.0001f || dot > best) - { - best = dot; - bestaxis = i; - } - } - - VectorCopy (baseaxis[bestaxis*3+1], xv); - VectorCopy (baseaxis[bestaxis*3+2], yv); -} - - - -float lightaxis[3] = {0.6f, 0.8f, 1.0f}; -/* -================ -SetShadeForPlane - -Light different planes differently to -improve recognition -================ -*/ -extern float ShadeForNormal(vec3_t normal); - -float SetShadeForPlane (plane_t *p) -{ - //return ShadeForNormal(p->normal); - - - int i; - float f; - - // axial plane - for (i=0 ; i<3 ; i++) - if (fabs(p->normal[i]) > 0.9) - { - f = lightaxis[i]; - return f; - } - - // between two axial planes - for (i=0 ; i<3 ; i++) - if (fabs(p->normal[i]) < 0.1) - { - f = (lightaxis[(i+1)%3] + lightaxis[(i+2)%3])/2; - return f; - } - - // other - f= (lightaxis[0] + lightaxis[1] + lightaxis[2]) / 3; - return f; - -} - -vec3_t vecs[2]; -float shift[2]; - -/* -================ -Face_Alloc -================ -*/ -face_t *Face_Alloc( void ) -{ - face_t *f = (face_t*)qmalloc( sizeof( *f ) ); - return f; -} - -/* -================ -Face_Free -================ -*/ -void Face_Free( face_t *f ) -{ - assert( f != 0 ); - - if ( f->face_winding ) - { - free( f->face_winding ); - f->face_winding = 0; - } - f->texdef.~texdef_t();; - - free( f ); -} - -/* -================ -Face_Clone -================ -*/ -face_t *Face_Clone (face_t *f) -{ - face_t *n; - - n = Face_Alloc(); - n->texdef = f->texdef; - n->brushprimit_texdef = f->brushprimit_texdef; - - memcpy (n->planepts, f->planepts, sizeof(n->planepts)); - - // all other fields are derived, and will be set by Brush_Build - // FIXME: maybe not, for example n->pData! - return n; -} - -/* -================ -Face_FullClone - -makes an exact copy of the face -================ -*/ -face_t *Face_FullClone (face_t *f) -{ - face_t *n; - - n = Face_Alloc(); - n->texdef = f->texdef; - n->brushprimit_texdef = f->brushprimit_texdef; - memcpy(n->planepts, f->planepts, sizeof(n->planepts)); - memcpy(&n->plane, &f->plane, sizeof(plane_t)); - if (f->face_winding) - n->face_winding = Winding_Clone(f->face_winding); - else - n->face_winding = NULL; - n->pShader = f->pShader; - n->pShader->IncRef(); - n->d_texture = n->pShader->getTexture(); - return n; -} - -void Face_SetShader(face_t *face, const char *name) -{ - if(face->pShader != NULL) - face->pShader->DecRef(); - face->texdef.SetName(name); - face->pShader = QERApp_Shader_ForName(name); - face->pShader->IncRef(); - face->d_texture = face->pShader->getTexture(); - face->texdef.flags = face->pShader->getFlags(); -} - -void Face_SetShader(face_t *face, IShader *shader) -{ - if(face->pShader != NULL) - face->pShader->DecRef(); - face->texdef.SetName(shader->getName()); - face->d_texture = shader->getTexture(); - face->texdef.flags = shader->getFlags(); - face->pShader = shader; - face->pShader->IncRef(); -} - -/* -================ -Clamp -================ -*/ -void Clamp(float& f, int nClamp) -{ - float fFrac = f - static_cast(f); - f = static_cast(f) % nClamp; - f += fFrac; -} - -/* -================ -Face_MoveTexture -================ -*/ -void Face_MoveTexture(face_t *f, vec3_t delta) -{ - vec3_t vX, vY; - - if (g_qeglobals.m_bBrushPrimitMode) - ShiftTextureGeometric_BrushPrimit( f, delta ); - else - { - TextureAxisFromPlane(&f->plane, vX, vY); - - vec3_t vDP, vShift; - vDP[0] = DotProduct(delta, vX); - vDP[1] = DotProduct(delta, vY); - - double fAngle = f->texdef.rotate / 180 * Q_PI; - double c = cos(fAngle); - double s = sin(fAngle); - - vShift[0] = vDP[0] * c - vDP[1] * s; - vShift[1] = vDP[0] * s + vDP[1] * c; - - if (!f->texdef.scale[0]) - f->texdef.scale[0] = g_pGameDescription->mTextureDefaultScale; - if (!f->texdef.scale[1]) - f->texdef.scale[1] = g_pGameDescription->mTextureDefaultScale; - - f->texdef.shift[0] -= vShift[0] / f->texdef.scale[0]; - f->texdef.shift[1] -= vShift[1] / f->texdef.scale[1]; - - // clamp the shifts - Clamp(f->texdef.shift[0], f->d_texture->width); - Clamp(f->texdef.shift[1], f->d_texture->height); - } -} - -/* -================ -Face_SetColor -================ -*/ -/*!\todo Replace all face_t::d_texture access with face_t::pShader::GetTexture.*/ -void Face_SetColor (brush_t *b, face_t *f, float fCurveColor) -{ - // set shading for face - f->d_shade = SetShadeForPlane (&f->plane); - f->d_color[0] = f->pShader->getTexture()->color[0] * f->d_shade; - f->d_color[1] = f->pShader->getTexture()->color[1] * f->d_shade; - f->d_color[2] = f->pShader->getTexture()->color[2] * f->d_shade; -} - -/* -================ -Face_TextureVectors -================ -*/ -void Face_TextureVectors (face_t *f, float STfromXYZ[2][4]) -{ - vec3_t pvecs[2]; - int sv, tv; - float ang, sinv, cosv; - float ns, nt; - int i,j; - qtexture_t *q; - texdef_t *td; - -#ifdef _DEBUG - // this code is not supposed to be used while in BP mode, warning here can help spot the problem - if (g_qeglobals.m_bBrushPrimitMode && !g_qeglobals.bNeedConvert) - Sys_Printf("Warning : illegal call of Face_TextureVectors in brush primitive mode\n"); -#endif - - td = &f->texdef; - q = f->d_texture; - - memset (STfromXYZ, 0, 8*sizeof(float)); - - if (!td->scale[0]) - td->scale[0] = g_pGameDescription->mTextureDefaultScale; - if (!td->scale[1]) - td->scale[1] = g_pGameDescription->mTextureDefaultScale; - - // get natural texture axis - TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]); - - // rotate axis - if (td->rotate == 0) - { sinv = 0 ; cosv = 1; } - else if (td->rotate == 90) - { sinv = 1 ; cosv = 0; } - else if (td->rotate == 180) - { sinv = 0 ; cosv = -1; } - else if (td->rotate == 270) - { sinv = -1 ; cosv = 0; } - else - { - ang = td->rotate / 180 * Q_PI; - sinv = sin(ang); - cosv = cos(ang); - } - - if (pvecs[0][0]) - sv = 0; - else if (pvecs[0][1]) - sv = 1; - else - sv = 2; - - if (pvecs[1][0]) - tv = 0; - else if (pvecs[1][1]) - tv = 1; - else - tv = 2; - - for (i=0 ; i<2 ; i++) { - ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv]; - nt = sinv * pvecs[i][sv] + cosv * pvecs[i][tv]; - STfromXYZ[i][sv] = ns; - STfromXYZ[i][tv] = nt; - } - - // scale - for (i=0 ; i<2 ; i++) - for (j=0 ; j<3 ; j++) - STfromXYZ[i][j] = STfromXYZ[i][j] / td->scale[i]; - - // shift - STfromXYZ[0][3] = td->shift[0]; - STfromXYZ[1][3] = td->shift[1]; - - for (j=0 ; j<4 ; j++) { - STfromXYZ[0][j] /= q->width; - STfromXYZ[1][j] /= q->height; - } -} - -/* -================ -Face_MakePlane -================ -*/ -void Face_MakePlane (face_t *f) -{ - int j; - vec3_t t1, t2, t3; - - // convert to a vector / dist plane - for (j=0 ; j<3 ; j++) - { - t1[j] = f->planepts[0][j] - f->planepts[1][j]; - t2[j] = f->planepts[2][j] - f->planepts[1][j]; - t3[j] = f->planepts[1][j]; - } - - CrossProduct(t1,t2, f->plane.normal); - if (VectorCompare (f->plane.normal, vec3_origin)) - Sys_FPrintf (SYS_WRN, "WARNING: brush plane with no normal\n"); - VectorNormalize (f->plane.normal, f->plane.normal); - f->plane.dist = DotProduct (t3, f->plane.normal); -} - -/* -================ -EmitTextureCoordinates -================ -*/ -void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f) -{ - float STfromXYZ[2][4]; - - Face_TextureVectors (f, STfromXYZ); - xyzst[3] = DotProduct (xyzst, STfromXYZ[0]) + STfromXYZ[0][3]; - xyzst[4] = DotProduct (xyzst, STfromXYZ[1]) + STfromXYZ[1][3]; -} - -//========================================================================== - -/* -================ -Brush_MakeFacePlanes -================ -*/ -void Brush_MakeFacePlanes (brush_t *b) -{ - face_t *f; - - for (f=b->brush_faces ; f ; f=f->next) - { - Face_MakePlane (f); - } -} - -/* -================ -DrawBrushEntityName -================ -*/ -void DrawBrushEntityName (brush_t *b) -{ - const char *name; - float a, s, c; - vec3_t mid; - int i; - - if (!b->owner) - return; // during contruction - - if (b->owner == world_entity) - return; - - if (b != b->owner->brushes.onext) - return; // not key brush - - // TTimo: Brush_DrawFacingAngle is for camera view rendering, this function is called for 2D views - // FIXME - spog - not sure who put this here.. Brush_DrawFacingAngle() does this job? - // Brush_DrawFacingAngle() works when called, but is not being called. - if (g_qeglobals.d_savedinfo.show_angles && (b->owner->eclass->nShowFlags & ECLASS_ANGLE)) - { - // draw the angle pointer - a = FloatForKey (b->owner, "angle"); - s = sin (a/180*Q_PI); - c = cos (a/180*Q_PI); - for (i=0 ; i<3 ; i++) - mid[i] = (b->mins[i] + b->maxs[i])*0.5; - - qglBegin (GL_LINE_STRIP); - qglVertex3fv (mid); - mid[0] += c*8; - mid[1] += s*8; - mid[2] += s*8; - qglVertex3fv (mid); - mid[0] -= c*4; - mid[1] -= s*4; - mid[2] -= s*4; - mid[0] -= s*4; - mid[1] += c*4; - mid[2] += c*4; - qglVertex3fv (mid); - mid[0] += c*4; - mid[1] += s*4; - mid[2] += s*4; - mid[0] += s*4; - mid[1] -= c*4; - mid[2] -= c*4; - qglVertex3fv (mid); - mid[0] -= c*4; - mid[1] -= s*4; - mid[2] -= s*4; - mid[0] += s*4; - mid[1] -= c*4; - mid[2] -= c*4; - qglVertex3fv (mid); - qglEnd (); - } - - if (g_qeglobals.d_savedinfo.show_names) - { - name = ValueForKey (b->owner, "classname"); - qglRasterPos3f (b->mins[0]+4, b->mins[1]+4, b->mins[2]+4); - gtk_glwidget_print_string(name); - } -} - -/* -================= -Brush_MakeFaceWinding - -returns the visible polygon on a face -================= -*/ -winding_t *Brush_MakeFaceWinding (brush_t *b, face_t *face) -{ - winding_t *w; - face_t *clip; - plane_t plane; - qboolean past; - - // get a poly that covers an effectively infinite area - w = Winding_BaseForPlane (&face->plane); - - // chop the poly by all of the other faces - past = false; - for (clip = b->brush_faces ; clip && w ; clip=clip->next) - { - if (clip == face) - { - past = true; - continue; - } - if (DotProduct (face->plane.normal, clip->plane.normal) > 0.999 - && fabs(face->plane.dist - clip->plane.dist) < 0.01 ) - { // identical plane, use the later one - if (past) - { - free (w); - return NULL; - } - continue; - } - - // flip the plane, because we want to keep the back side - VectorSubtract (vec3_origin,clip->plane.normal, plane.normal); - plane.dist = -clip->plane.dist; - - w = Winding_Clip (w, &plane, false); - if (!w) - return w; - } - - if (w->numpoints < 3) - { - free(w); - w = NULL; - } - - if (!w) - Sys_FPrintf (SYS_WRN, "unused plane\n"); - - return w; -} - -/* -================= -Brush_SnapPlanepts -================= -*/ -void Brush_SnapPlanepts (brush_t *b) -{ - int i, j; - face_t *f; - - if (g_PrefsDlg.m_bNoClamp) - return; - - if (g_qeglobals.d_bSmallGrid) - { - for (f=b->brush_faces ; f; f=f->next) - for (i=0 ; i<3 ; i++) - for (j=0 ; j<3 ; j++) - f->planepts[i][j] = floor (f->planepts[i][j]/g_qeglobals.d_gridsize + 0.5)*g_qeglobals.d_gridsize; - } - else - { - for (f=b->brush_faces ; f; f=f->next) - for (i=0 ; i<3 ; i++) - for (j=0 ; j<3 ; j++) - f->planepts[i][j] = floor (f->planepts[i][j] + 0.5); - } -} - -/* -** Brush_Build -** -** Builds a brush rendering data and also sets the min/max bounds -*/ -// TTimo -// added a bConvert flag to convert between old and new brush texture formats -// TTimo -// brush grouping: update the group treeview if necessary -void Brush_Build( brush_t *b, bool bSnap, bool bMarkMap, bool bConvert, bool bFilterTest) -{ - bool bLocalConvert; - - -#ifdef _DEBUG - if (!g_qeglobals.m_bBrushPrimitMode && bConvert) - Sys_Printf("Warning : conversion from brush primitive to old brush format not implemented\n"); -#endif - - // if bConvert is set and g_qeglobals.bNeedConvert is not, that just means we need convert for this brush only - if (bConvert && !g_qeglobals.bNeedConvert) - { -#ifdef _DEBUG - //++timo FIXME: it's not very clear when this can happen, I guess while dealing with plugins that send brushes - // back and forth in one format or the other .. more when mixing BP / noBP in the same maps. -#endif - bLocalConvert = true; - g_qeglobals.bNeedConvert = true; - } - else - bLocalConvert = false; - - /* - ** build the windings and generate the bounding box - */ - Brush_BuildWindings(b, bSnap); - - if(b->owner->model.pRender) - { - const aabb_t *aabb = b->owner->model.pRender->GetAABB(); - VectorAdd(aabb->origin, aabb->extents, b->maxs); - VectorSubtract(aabb->origin, aabb->extents, b->mins); - } - - //Patch_BuildPoints (b); // does nothing but set b->patchBrush true if the texdef contains SURF_PATCH ! - - /* - ** move the points and edges if in select mode - */ - if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge) - SetupVertexSelection (); - - if (b->itemOwner == 0) //NULL) - Group_AddToProperGroup(b); - - if (bMarkMap) - { - Sys_MarkMapModified(); - } - - if (bLocalConvert) - g_qeglobals.bNeedConvert = false; - - // spog - applying filters to brush during brush_build instead of during redraw - if (bFilterTest) - b->bFiltered = FilterBrush( b ); -} - -/* -============== -Brush_SplitBrushByFace - -The incoming brush is NOT freed. -The incoming face is NOT left referenced. -============== -*/ -void Brush_SplitBrushByFace (brush_t *in, face_t *f, brush_t **front, brush_t **back, boolean bCaulk) -{ - brush_t *b; - face_t *nf; - vec3_t temp; - - b = Brush_Clone (in); - nf = Face_Clone (f); - - nf->texdef = b->brush_faces->texdef; - if (bCaulk) - { - nf->texdef.SetName(g_pGameDescription->mCaulkShader.GetBuffer()); - } - nf->next = b->brush_faces; - b->brush_faces = nf; - - Brush_Build( b ); - Brush_RemoveEmptyFaces ( b ); - if ( !b->brush_faces ) - { // completely clipped away - Brush_Free (b); - *back = NULL; - } - else - { - Entity_LinkBrush (in->owner, b); - *back = b; - } - - b = Brush_Clone (in); - nf = Face_Clone (f); - // swap the plane winding - VectorCopy (nf->planepts[0], temp); - VectorCopy (nf->planepts[1], nf->planepts[0]); - VectorCopy (temp, nf->planepts[1]); - - nf->texdef = b->brush_faces->texdef; - if (bCaulk) - { - nf->texdef.SetName(g_pGameDescription->mCaulkShader.GetBuffer()); - } - nf->next = b->brush_faces; - b->brush_faces = nf; - - Brush_Build( b ); - Brush_RemoveEmptyFaces ( b ); - if ( !b->brush_faces ) - { // completely clipped away - Brush_Free (b); - *front = NULL; - } - else - { - Entity_LinkBrush (in->owner, b); - *front = b; - } -} - -/* -================= -Brush_BestSplitFace - -returns the best face to split the brush with. -return NULL if the brush is convex -================= -*/ -face_t *Brush_BestSplitFace(brush_t *b) -{ - face_t *face, *f, *bestface; - winding_t *front, *back; - int splits, tinywindings, value, bestvalue; - - bestvalue = 999999; - bestface = NULL; - for (face = b->brush_faces; face; face = face->next) - { - splits = 0; - tinywindings = 0; - for (f = b->brush_faces; f; f = f->next) - { - if (f == face) continue; - // - Winding_SplitEpsilon(f->face_winding, face->plane.normal, face->plane.dist, 0.1f, &front, &back); - - if (!front) - { - Winding_Free(back); - } - else if (!back) - { - Winding_Free(front); - } - else - { - splits++; - if (Winding_IsTiny(front)) tinywindings++; - if (Winding_IsTiny(back)) tinywindings++; - } - } - if (splits) - { - value = splits + 50 * tinywindings; - if (value < bestvalue) - { - bestvalue = value; - bestface = face; - } - } - } - return bestface; -} - -/* -================= -Brush_MakeConvexBrushes - -MrE FIXME: this doesn't work because the old - Brush_SplitBrushByFace is used -Turns the brush into a minimal number of convex brushes. -If the input brush is convex then it will be returned. -Otherwise the input brush will be freed. -NOTE: the input brush should have windings for the faces. -================= -*/ -brush_t *Brush_MakeConvexBrushes(brush_t *b) -{ - brush_t *front, *back, *end; - face_t *face; - - b->next = NULL; - face = Brush_BestSplitFace(b); - if (!face) return b; - Brush_SplitBrushByFace(b, face, &front, &back); - //this should never happen - if (!front && !back) return b; - Brush_Free(b); - if (!front) - return Brush_MakeConvexBrushes(back); - b = Brush_MakeConvexBrushes(front); - if (back) - { - for (end = b; end->next; end = end->next); - end->next = Brush_MakeConvexBrushes(back); - } - return b; -} - -/* -================= -Brush_Convex -================= -*/ -int Brush_Convex(brush_t *b) -{ - face_t *face1, *face2; - - for (face1 = b->brush_faces; face1; face1 = face1->next) - { - if (!face1->face_winding) continue; - for (face2 = b->brush_faces; face2; face2 = face2->next) - { - if (face1 == face2) continue; - if (!face2->face_winding) continue; - if (Winding_PlanesConcave(face1->face_winding, face2->face_winding, - face1->plane.normal, face2->plane.normal, - face1->plane.dist, face2->plane.dist)) - { - return false; - } - } - } - return true; -} - -/* -================= -Brush_MoveVertexes - -- The input brush must be convex -- The input brush must have face windings. -- The output brush will be convex. -- Returns true if the WHOLE vertex movement is performed. -================= -*/ - -// define this to debug the vertex editing mode -#ifdef _DEBUG -//#define DBG_VERT -#endif - -#define MAX_MOVE_FACES 64 - -int Brush_MoveVertex(brush_t *b, vec3_t vertex, vec3_t delta, vec3_t end, bool bSnap) -{ - face_t *f, *face, *newface, *lastface, *nextface; - face_t *movefaces[MAX_MOVE_FACES]; - int movefacepoints[MAX_MOVE_FACES]; - winding_t *w, tmpw; - vec3_t start, mid; - plane_t plane; - int i, j, k, nummovefaces, result, done; - float dot, front, back, frac, smallestfrac; - -#ifdef DBG_VERT - Sys_Printf("Bursh_MoveVertex: %p vertex: %g %g %g delta: %g %g %g end: %g %g %g snap: %s\n", b, vertex[0], vertex[1], vertex[2], delta[0], delta[1], delta[2], end[0], end[1], end[2], bSnap ? "true" : "false" ); -#endif - - result = true; - // - tmpw.numpoints = 3; - tmpw.maxpoints = 3; - VectorCopy(vertex, start); - VectorAdd(vertex, delta, end); - //snap or not? - if (bSnap) - for (i = 0; i < 3; i++) - end[i] = floor(end[i] / g_qeglobals.d_gridsize + 0.1) * g_qeglobals.d_gridsize; - // - VectorCopy(end, mid); - //if the start and end are the same - if (Point_Equal(start, end, 0.3f)) return false; - //the end point may not be the same as another vertex - for (face = b->brush_faces; face; face = face->next) - { - w = face->face_winding; - if (!w) continue; - for (i = 0; i < w->numpoints; i++) - { - if (Point_Equal(w->points[i], end, 0.3f)) - { - VectorCopy(vertex, end); - return false; - } - } - } - // - done = false; - while(!done) - { - //chop off triangles from all brush faces that use the to be moved vertex - //store pointers to these chopped off triangles in movefaces[] - nummovefaces = 0; - for (face = b->brush_faces; face; face = face->next) - { - w = face->face_winding; - if (!w) continue; - for (i = 0; i < w->numpoints; i++) - { - if (Point_Equal(w->points[i], start, 0.2f)) - { - if (face->face_winding->numpoints <= 3) - { - movefacepoints[nummovefaces] = i; - movefaces[nummovefaces++] = face; - break; - } - dot = DotProduct(end, face->plane.normal) - face->plane.dist; - //if the end point is in front of the face plane - if (dot > 0.1) - { - //fanout triangle subdivision - for (k = i; k < i + w->numpoints-3; k++) - { - VectorCopy(w->points[i], tmpw.points[0]); - VectorCopy(w->points[(k+1) % w->numpoints], tmpw.points[1]); - VectorCopy(w->points[(k+2) % w->numpoints], tmpw.points[2]); - // - newface = Face_Clone(face); - //get the original - for (f = face; f->original; f = f->original) ; - newface->original = f; - //store the new winding - if (newface->face_winding) Winding_Free(newface->face_winding); - newface->face_winding = Winding_Clone(&tmpw); - //get the texture information - newface->pShader = face->pShader; - newface->d_texture = face->d_texture; - - //add the face to the brush - newface->next = b->brush_faces; - b->brush_faces = newface; - //add this new triangle to the move faces - movefacepoints[nummovefaces] = 0; - movefaces[nummovefaces++] = newface; - } - //give the original face a new winding - VectorCopy(w->points[(i-2+w->numpoints) % w->numpoints], tmpw.points[0]); - VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[1]); - VectorCopy(w->points[i], tmpw.points[2]); - Winding_Free(face->face_winding); - face->face_winding = Winding_Clone(&tmpw); - //add the original face to the move faces - movefacepoints[nummovefaces] = 2; - movefaces[nummovefaces++] = face; - } - else - { - //chop a triangle off the face - VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[0]); - VectorCopy(w->points[i], tmpw.points[1]); - VectorCopy(w->points[(i+1) % w->numpoints], tmpw.points[2]); - //remove the point from the face winding - Winding_RemovePoint(w, i); - //get texture crap right - Face_SetColor(b, face, 1.0); - for (j = 0; j < w->numpoints; j++) - EmitTextureCoordinates(w->points[j], face->d_texture, face); - //make a triangle face - newface = Face_Clone(face); - //get the original - for (f = face; f->original; f = f->original) ; - newface->original = f; - //store the new winding - if (newface->face_winding) Winding_Free(newface->face_winding); - newface->face_winding = Winding_Clone(&tmpw); - //get the texture - newface->pShader = face->pShader; - newface->d_texture = newface->pShader->getTexture(); -// newface->d_texture = QERApp_Texture_ForName2( newface->texdef.name ); - //add the face to the brush - newface->next = b->brush_faces; - b->brush_faces = newface; - // - movefacepoints[nummovefaces] = 1; - movefaces[nummovefaces++] = newface; - } - break; - } - } - } - //now movefaces contains pointers to triangle faces that - //contain the to be moved vertex - // - done = true; - VectorCopy(end, mid); - smallestfrac = 1; - for (face = b->brush_faces; face; face = face->next) - { - //check if there is a move face that has this face as the original - for (i = 0; i < nummovefaces; i++) - { - if (movefaces[i]->original == face) break; - } - if (i >= nummovefaces) continue; - //check if the original is not a move face itself - for (j = 0; j < nummovefaces; j++) - { - if (face == movefaces[j]) break; - } - //if the original is not a move face itself - if (j >= nummovefaces) - { - memcpy(&plane, &movefaces[i]->original->plane, sizeof(plane_t)); - } - else - { - k = movefacepoints[j]; - w = movefaces[j]->face_winding; - VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[0]); - VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[1]); - // - k = movefacepoints[i]; - w = movefaces[i]->face_winding; - VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[2]); - if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane)) - { - VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[2]); - if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane)) - //this should never happen otherwise the face merge did a crappy job a previous pass - continue; - } - } - //now we've got the plane to check agains - front = DotProduct(start, plane.normal) - plane.dist; - back = DotProduct(end, plane.normal) - plane.dist; - //if the whole move is at one side of the plane - if (front < 0.01 && back < 0.01) continue; - if (front > -0.01 && back > -0.01) continue; - //if there's no movement orthogonal to this plane at all - if (fabs(front-back) < 0.001) continue; - //ok first only move till the plane is hit - frac = front/(front-back); - if (frac < smallestfrac) - { - mid[0] = start[0] + (end[0] - start[0]) * frac; - mid[1] = start[1] + (end[1] - start[1]) * frac; - mid[2] = start[2] + (end[2] - start[2]) * frac; - smallestfrac = frac; - } - // - done = false; - } - - //move the vertex - for (i = 0; i < nummovefaces; i++) - { - //move vertex to end position - VectorCopy(mid, movefaces[i]->face_winding->points[movefacepoints[i]]); - //create new face plane - for (j = 0; j < 3; j++) - { - VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]); - } - Face_MakePlane(movefaces[i]); - if (VectorLength(movefaces[i]->plane.normal) < 0.1) - result = false; - } - //if the brush is no longer convex - if (!result || !Brush_Convex(b)) - { - for (i = 0; i < nummovefaces; i++) - { - //move the vertex back to the initial position - VectorCopy(start, movefaces[i]->face_winding->points[movefacepoints[i]]); - //create new face plane - for (j = 0; j < 3; j++) - { - VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]); - } - Face_MakePlane(movefaces[i]); - } - result = false; - VectorCopy(start, end); - done = true; - } - else - { - VectorCopy(mid, start); - } - //get texture crap right - for (i = 0; i < nummovefaces; i++) - { - Face_SetColor(b, movefaces[i], 1.0); - for (j = 0; j < movefaces[i]->face_winding->numpoints; j++) - EmitTextureCoordinates(movefaces[i]->face_winding->points[j], movefaces[i]->d_texture, movefaces[i]); - } - - //now try to merge faces with their original faces - lastface = NULL; - for (face = b->brush_faces; face; face = nextface) - { - nextface = face->next; - if (!face->original) - { - lastface = face; - continue; - } - if (!Plane_Equal(&face->plane, &face->original->plane, false)) - { - lastface = face; - continue; - } - w = Winding_TryMerge(face->face_winding, face->original->face_winding, face->plane.normal, true); - if (!w) - { - lastface = face; - continue; - } - Winding_Free(face->original->face_winding); - face->original->face_winding = w; - //get texture crap right - Face_SetColor(b, face->original, 1.0); - for (j = 0; j < face->original->face_winding->numpoints; j++) - EmitTextureCoordinates(face->original->face_winding->points[j], face->original->d_texture, face->original); - //remove the face that was merged with the original - if (lastface) lastface->next = face->next; - else b->brush_faces = face->next; - Face_Free(face); - } - } - return result; -} - -/* -================= -Brush_InsertVertexBetween -================= -*/ -int Brush_InsertVertexBetween(brush_t *b, vec3_t p1, vec3_t p2) -{ - face_t *face; - winding_t *w, *neww; - vec3_t point; - int i, insert; - - if (Point_Equal(p1, p2, 0.4f)) - return false; - VectorAdd(p1, p2, point); - VectorScale(point, 0.5f, point); - insert = false; - //the end point may not be the same as another vertex - for (face = b->brush_faces; face; face = face->next) - { - w = face->face_winding; - if (!w) continue; - neww = NULL; - for (i = 0; i < w->numpoints; i++) - { - if (!Point_Equal(w->points[i], p1, 0.1f)) - continue; - if (Point_Equal(w->points[(i+1) % w->numpoints], p2, 0.1f)) - { - neww = Winding_InsertPoint(w, point, (i+1) % w->numpoints); - break; - } - else if (Point_Equal(w->points[(i-1+w->numpoints) % w->numpoints], p2, 0.3f)) - { - neww = Winding_InsertPoint(w, point, i); - break; - } - } - if (neww) - { - Winding_Free(face->face_winding); - face->face_winding = neww; - insert = true; - } - } - return insert; -} - - -/* -================= -Brush_ResetFaceOriginals -================= -*/ -void Brush_ResetFaceOriginals(brush_t *b) -{ - face_t *face; - - for (face = b->brush_faces; face; face = face->next) - { - face->original = NULL; - } -} - -#ifdef ENABLE_GROUPS -/* -============== -Brush_SetEpair -sets an epair for the given brush -============== -*/ -void Brush_SetEpair(brush_t *b, const char *pKey, const char *pValue) -{ - if (g_qeglobals.m_bBrushPrimitMode) - { - if (b->patchBrush) - { - Patch_SetEpair(b->pPatch, pKey, pValue); - } - else - { - SetKeyValue(b->epairs, pKey, pValue); - } - } - else - { - Sys_Printf("Can only set key/values in Brush primitive mode\n"); - } -} - -/* -================= -Brush_GetKeyValue -================= -*/ -const char* Brush_GetKeyValue(brush_t *b, const char *pKey) -{ - if (g_qeglobals.m_bBrushPrimitMode) - { - if (b->patchBrush) - { - return Patch_GetKeyValue(b->pPatch, pKey); - } - else - { - return ValueForKey(b->epairs, pKey); - } - } - else - { - Sys_Printf("Can only set brush/patch key/values in Brush primitive mode\n"); - } - return ""; -} -#endif -/* -================= -CheckName -temporary stuff, detect potential problems when saving the texture name -================= -*/ -void CheckName( face_t *fa, char *pname ) -{ - if (!strlen(fa->texdef.GetName())) - { -#ifdef _DEBUG - Sys_Printf("WARNING: unexpected texdef.name is empty in Brush.cpp CheckName\n"); -#endif - fa->texdef.SetName(SHADER_NOT_FOUND); - strcpy(pname, SHADER_NOT_FOUND); - return; - } - - // some people manage to get long filename textures (with spaces) in their maps - if (strchr( fa->texdef.GetName(), ' ' )) - { - char Msg1[1024]; - - sprintf( Msg1, "Can't save texture with spaces in name. Rename %s\nNOTE: This message may popup several times .. once for each buggy face detected.", fa->texdef.GetName() ); - - Sys_Printf("%s\n", Msg1 ); - gtk_MessageBox(g_pParentWnd->m_pWidget, Msg1, "Error saving map", MB_OK ); - strcpy( pname, SHADER_NOT_FOUND ); - return; - } - - //++timo FIXME: bug #103494 detection attempt - // TODO: clean this detection part when bug will have disappeared - if (fa->texdef.GetName()[0] == '(') - { - char *text = "Bug #103494 detected, dropping texture. Please report to timo@qeradiant.com if you have a way to reproduce!\nNOTE: this message may popup several times .. once for each buggy face detected."; - Sys_Printf("%s\n", text); - gtk_MessageBox(g_pParentWnd->m_pWidget, text, "Error saving map", MB_OK ); - // need to cleanup this dead face name or we may loop endlessly - fa->texdef.SetName(SHADER_NOT_FOUND); - strcpy( pname, SHADER_NOT_FOUND ); - return; - } - strcpy( pname, fa->texdef.GetName()+9 ); // remove "textures/" -} - -/* -============= -Brush_Create - -Create non-textured blocks for entities -The brush is NOT linked to any list -============= -*/ -brush_t *Brush_Create (vec3_t mins, vec3_t maxs, texdef_t *texdef) -{ - int i, j; - vec3_t pts[4][2]; - face_t *f; - brush_t *b; - -#if DBG_BP - // brush primitive mode : convert texdef to brushprimit_texdef ? - // most of the time texdef is empty - if (g_qeglobals.m_bBrushPrimitMode) - { - // check texdef is empty .. if there are cases it's not we need to write some conversion code - if (texdef->shift[0]!=0 || texdef->shift[1]!=0 || texdef->scale[0]!=0 || texdef->scale[1]!=0 || texdef->rotate!=0) - Sys_Printf("Warning : non-zero texdef detected in Brush_Create .. need brush primitive conversion\n"); - } -#endif - - for (i=0 ; i<3 ; i++) - { - if (maxs[i] < mins[i]) - Error ("Brush_InitSolid: backwards"); - } - - b = Brush_Alloc(); - - pts[0][0][0] = mins[0]; - pts[0][0][1] = mins[1]; - - pts[1][0][0] = mins[0]; - pts[1][0][1] = maxs[1]; - - pts[2][0][0] = maxs[0]; - pts[2][0][1] = maxs[1]; - - pts[3][0][0] = maxs[0]; - pts[3][0][1] = mins[1]; - - for (i=0 ; i<4 ; i++) - { - pts[i][0][2] = mins[2]; - pts[i][1][0] = pts[i][0][0]; - pts[i][1][1] = pts[i][0][1]; - pts[i][1][2] = maxs[2]; - } - - for (i=0 ; i<4 ; i++) - { - f = Face_Alloc(); - f->texdef = *texdef; - f->texdef.flags &= ~SURF_KEEP; - f->texdef.contents &= ~CONTENTS_KEEP; - f->next = b->brush_faces; - b->brush_faces = f; - j = (i+1)%4; - - VectorCopy (pts[j][1], f->planepts[0]); - VectorCopy (pts[i][1], f->planepts[1]); - VectorCopy (pts[i][0], f->planepts[2]); - } - - f = Face_Alloc(); - f->texdef = *texdef; - f->texdef.flags &= ~SURF_KEEP; - f->texdef.contents &= ~CONTENTS_KEEP; - f->next = b->brush_faces; - b->brush_faces = f; - - VectorCopy (pts[0][1], f->planepts[0]); - VectorCopy (pts[1][1], f->planepts[1]); - VectorCopy (pts[2][1], f->planepts[2]); - - f = Face_Alloc(); - f->texdef = *texdef; - f->texdef.flags &= ~SURF_KEEP; - f->texdef.contents &= ~CONTENTS_KEEP; - f->next = b->brush_faces; - b->brush_faces = f; - - VectorCopy (pts[2][0], f->planepts[0]); - VectorCopy (pts[1][0], f->planepts[1]); - VectorCopy (pts[0][0], f->planepts[2]); - - return b; -} - -/* -============= -Brush_CreatePyramid - -Create non-textured pyramid for light entities -The brush is NOT linked to any list -============= -*/ -brush_t *Brush_CreatePyramid (vec3_t mins, vec3_t maxs, texdef_t *texdef) -{ - int i; - - //++timo handle new brush primitive ? return here ?? - return Brush_Create(mins, maxs, texdef); - - for (i=0 ; i<3 ; i++) - if (maxs[i] < mins[i]) - Error ("Brush_InitSolid: backwards"); - - brush_t* b = Brush_Alloc(); - - vec3_t corners[4]; - - float fMid = Rad_rint(mins[2] + (Rad_rint((maxs[2] - mins[2]) / 2))); - - corners[0][0] = mins[0]; - corners[0][1] = mins[1]; - corners[0][2] = fMid; - - corners[1][0] = mins[0]; - corners[1][1] = maxs[1]; - corners[1][2] = fMid; - - corners[2][0] = maxs[0]; - corners[2][1] = maxs[1]; - corners[2][2] = fMid; - - corners[3][0] = maxs[0]; - corners[3][1] = mins[1]; - corners[3][2] = fMid; - - vec3_t top, bottom; - - top[0] = Rad_rint(mins[0] + ((maxs[0] - mins[0]) / 2)); - top[1] = Rad_rint(mins[1] + ((maxs[1] - mins[1]) / 2)); - top[2] = Rad_rint(maxs[2]); - - VectorCopy(top, bottom); - bottom[2] = mins[2]; - - // sides - for (i = 0; i < 4; i++) - { - face_t* f = Face_Alloc(); - f->texdef = *texdef; - f->texdef.flags &= ~SURF_KEEP; - f->texdef.contents &= ~CONTENTS_KEEP; - f->next = b->brush_faces; - b->brush_faces = f; - int j = (i+1)%4; - - VectorCopy (top, f->planepts[0]); - VectorCopy (corners[i], f->planepts[1]); - VectorCopy(corners[j], f->planepts[2]); - - f = Face_Alloc(); - f->texdef = *texdef; - f->texdef.flags &= ~SURF_KEEP; - f->texdef.contents &= ~CONTENTS_KEEP; - f->next = b->brush_faces; - b->brush_faces = f; - - VectorCopy (bottom, f->planepts[2]); - VectorCopy (corners[i], f->planepts[1]); - VectorCopy(corners[j], f->planepts[0]); - } - - return b; -} - - - - -/* -============= -Brush_MakeSided - -Makes the current brush have the given number of 2d sides -============= -*/ -void Brush_MakeSided (int sides) -{ - int i, axis; - vec3_t mins, maxs; - brush_t *b; - texdef_t *texdef; - face_t *f; - vec3_t mid; - float width; - float sv, cv; - - if (sides < 3) - { - Sys_Status ("Bad sides number", 0); - return; - } - - if (sides >= MAX_POINTS_ON_WINDING-4) - { - Sys_Printf("too many sides.\n"); - return; - } - - if (!QE_SingleBrush ()) - { - Sys_Status ("Must have a single brush selected", 0 ); - return; - } - - b = selected_brushes.next; - VectorCopy (b->mins, mins); - VectorCopy (b->maxs, maxs); - texdef = &g_qeglobals.d_texturewin.texdef; - - Brush_Free (b); - - if (g_pParentWnd->ActiveXY()) - { - switch(g_pParentWnd->ActiveXY()->GetViewType()) - { - case XY: axis = 2; break; - case XZ: axis = 1; break; - case YZ: axis = 0; break; - } - } - else - { - axis = 2; - } - - // find center of brush - width = 8; - for (i = 0; i < 3; i++) - { - mid[i] = (maxs[i] + mins[i]) * 0.5; - if (i == axis) continue; - if ((maxs[i] - mins[i]) * 0.5 > width) - width = (maxs[i] - mins[i]) * 0.5; - } - - b = Brush_Alloc(); - - // create top face - f = Face_Alloc(); - f->texdef = *texdef; - f->next = b->brush_faces; - b->brush_faces = f; - - f->planepts[2][(axis+1)%3] = mins[(axis+1)%3]; f->planepts[2][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[2][axis] = maxs[axis]; - f->planepts[1][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[1][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[1][axis] = maxs[axis]; - f->planepts[0][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[0][(axis+2)%3] = maxs[(axis+2)%3]; f->planepts[0][axis] = maxs[axis]; - - // create bottom face - f = Face_Alloc(); - f->texdef = *texdef; - f->next = b->brush_faces; - b->brush_faces = f; - - f->planepts[0][(axis+1)%3] = mins[(axis+1)%3]; f->planepts[0][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[0][axis] = mins[axis]; - f->planepts[1][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[1][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[1][axis] = mins[axis]; - f->planepts[2][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[2][(axis+2)%3] = maxs[(axis+2)%3]; f->planepts[2][axis] = mins[axis]; - - for (i=0 ; itexdef = *texdef; - f->next = b->brush_faces; - b->brush_faces = f; - - sv = sin (i*3.14159265*2/sides); - cv = cos (i*3.14159265*2/sides); - - f->planepts[0][(axis+1)%3] = floor(mid[(axis+1)%3]+width*cv+0.5); - f->planepts[0][(axis+2)%3] = floor(mid[(axis+2)%3]+width*sv+0.5); - f->planepts[0][axis] = mins[axis]; - - f->planepts[1][(axis+1)%3] = f->planepts[0][(axis+1)%3]; - f->planepts[1][(axis+2)%3] = f->planepts[0][(axis+2)%3]; - f->planepts[1][axis] = maxs[axis]; - - f->planepts[2][(axis+1)%3] = floor(f->planepts[0][(axis+1)%3] - width*sv + 0.5); - f->planepts[2][(axis+2)%3] = floor(f->planepts[0][(axis+2)%3] + width*cv + 0.5); - f->planepts[2][axis] = maxs[axis]; - } - - Brush_AddToList (b, &selected_brushes); - - Entity_LinkBrush (world_entity, b); - - Brush_Build( b ); - - Sys_UpdateWindows (W_ALL); -} - - - -/* -============= -Brush_Free - -Frees the brush with all of its faces and display list. -Unlinks the brush from whichever chain it is in. -Decrements the owner entity's brushcount. -Removes owner entity if this was the last brush -unless owner is the world. -Removes from groups -============= -*/ -void Brush_Free (brush_t *b, bool bRemoveNode) -{ - face_t *f, *next; - epair_t *ep, *enext; - - // remove from group - if (bRemoveNode) - Group_RemoveBrush(b); - - // free the patch if it's there - if (b->patchBrush) - { - Patch_Delete(b->pPatch); - } - - // free faces - for (f=b->brush_faces ; f ; f=next) - { - next = f->next; - Face_Free( f ); - } - - // TTimo : free brush epairs - for (ep = b->epairs ; ep ; ep=enext ) - { - enext = ep->next; - free (ep->key); - free (ep->value); - free (ep); - } - - // unlink from active/selected list - if (b->next) - Brush_RemoveFromList (b); - - // unlink from entity list - if (b->onext) - Entity_UnlinkBrush (b); - - free (b); -} - -/* -============= -Face_MemorySize -============= -*/ -int Face_MemorySize(face_t *f ) -{ - int size = 0; - - if (f->face_winding) - { -// size += _msize(f->face_winding); - size += sizeof(vec3_t)*f->face_winding->numpoints+2*sizeof(int); - } -// size += _msize(f); - size += sizeof(face_t); - return size; -} - -/* -============= -Brush_MemorySize -============= -*/ -int Brush_MemorySize(brush_t *b) -{ - face_t *f; - epair_t *ep; - int size = 0; - - // - if (b->patchBrush) - { - size += Patch_MemorySize(b->pPatch); - } - // - for (f = b->brush_faces; f; f = f->next) - { - size += Face_MemorySize(f); - } - // - for (ep = b->epairs; ep; ep = ep->next ) - { -// size += _msize(ep->key); - size += strlen(ep->key); -// size += _msize(ep->value); - size += strlen(ep->value); -// size += _msize(ep); - size += sizeof(epair_t); - } -// size += _msize(b); - size += sizeof(brush_t); - return size; -} - - -/* -============ -Brush_Clone - -Does NOT add the new brush to any lists -============ -*/ -brush_t *Brush_Clone (brush_t *b) -{ - brush_t *n = NULL; - face_t *f, *nf; - - if (b->patchBrush) - { - patchMesh_t *p = Patch_Duplicate(b->pPatch); - Brush_RemoveFromList(p->pSymbiot); - Entity_UnlinkBrush(p->pSymbiot); - n = p->pSymbiot; - } - else - { - n = Brush_Alloc(); - n->numberId = g_nBrushId++; - n->owner = b->owner; - for (f=b->brush_faces ; f ; f=f->next) - { - nf = Face_Clone( f ); - nf->next = n->brush_faces; - n->brush_faces = nf; - } - } - - return n; -} - -/* -============ -Brush_Clone - -Does NOT add the new brush to any lists -============ -*/ -brush_t *Brush_FullClone(brush_t *b) -{ - brush_t *n = NULL; - face_t *f, *nf, *f2, *nf2; - int j; - - if (b->patchBrush) - { - patchMesh_t *p = Patch_Duplicate(b->pPatch); - Brush_RemoveFromList(p->pSymbiot); - Entity_UnlinkBrush(p->pSymbiot); - n = p->pSymbiot; - n->owner = b->owner; - Brush_Build(n); - } - else - { - n = Brush_Alloc(); - n->numberId = g_nBrushId++; - n->owner = b->owner; - VectorCopy(b->mins, n->mins); - VectorCopy(b->maxs, n->maxs); - // - for (f = b->brush_faces; f; f = f->next) - { - if (f->original) continue; - nf = Face_FullClone(f); - nf->next = n->brush_faces; - n->brush_faces = nf; - //copy all faces that have the original set to this face - for (f2 = b->brush_faces; f2; f2 = f2->next) - { - if (f2->original == f) - { - nf2 = Face_FullClone(f2); - nf2->next = n->brush_faces; - n->brush_faces = nf2; - //set original - nf2->original = nf; - } - } - } - for (nf = n->brush_faces; nf; nf = nf->next) - { - Face_SetColor(n, nf, 1.0); - if (nf->face_winding) - { - if (g_qeglobals.m_bBrushPrimitMode) - EmitBrushPrimitTextureCoordinates(nf,nf->face_winding); - else - { - for (j = 0; j < nf->face_winding->numpoints; j++) - EmitTextureCoordinates(nf->face_winding->points[j], nf->d_texture, nf); - } - } - } - } - return n; -} - - // FIXME - spog - finish this later.. - /* -bool Triangle_Ray(vec3_t origin, vec3_t dir, vec3_t p1, vec3_t p2, vec3_t p3) -{ - int i; - vec3_t v1, v2, normal[3]; - float d; - - //Sys_Printf("p1: %f %f %f\n",p1[0],p1[1],p1[2]); - //Sys_Printf("p2: %f %f %f\n",p2[0],p2[1],p2[2]); - //Sys_Printf("p3: %f %f %f\n",p3[0],p3[1],p3[2]); - //Sys_Printf("origin: %f %f %f\n",origin[0],origin[1],origin[2]); - - // test ray against triangle - // get triangle plane normal - //VectorSubtract(p1, p2, v1); - //VectorSubtract(p1, p3, v2); - //CrossProduct(v1, v2, v1); - // check normal against direction - //if (DotProduct(dir, v1) >= 0) - //{ - // generate cone normals - VectorSubtract(origin, p1, v1); - VectorSubtract(origin, p2, v2); - CrossProduct(v1, v2, normal[0]); - VectorSubtract(origin, p2, v1); - VectorSubtract(origin, p3, v2); - CrossProduct(v1, v2, normal[1]); - VectorSubtract(origin, p3, v1); - VectorSubtract(origin, p1, v2); - CrossProduct(v1, v2, normal[2]); - //} - //else - //{ - // flip normals if triangle faces away - // Sys_Printf("flipped\n"); - // VectorSubtract(origin, p1, v1); - // VectorSubtract(origin, p3, v2); - // CrossProduct(v1, v2, normal[0]); - // VectorSubtract(origin, p3, v1); - // VectorSubtract(origin, p2, v2); - // CrossProduct(v1, v2, normal[1]); - // VectorSubtract(origin, p2, v1); - // VectorSubtract(origin, p1, v2); - // CrossProduct(v1, v2, normal[2]); - //} - - for (i=0; i<3; i++) - { - VectorNormalize(normal[i]); - //Sys_Printf("direction: %f %f %f\n",dir[0],dir[1],dir[2]); - //Sys_Printf("normal: %f %f %f\n",normal[i][0],normal[i][1],normal[i][2]); - d = DotProduct(dir, normal[i]); - //Sys_Printf("dotproduct: %f\n",d); - if (d < 0) - return false; - } - return true; -} -*/ - -/* -extern int Triangle_Ray(float orig[3], float dir[3], bool bCullBack, - float vert0[3], float vert1[3], float vert2[3], - double *t, double *u, double *v); - -bool Model_Ray(brush_t *b, vec3_t origin, vec3_t dir, double *t, double *u, double *v) -{ - bool bIntersect = false; - float tBest = FLT_MAX; - int i, j; - vec3_t xyz[3]; - vec3_t vRay[2]; - - float angle = FloatForKey (b->owner, "angle"); // FIXME: should be set when this entity key is set - - VectorSubtract (origin, b->owner->origin, vRay[0]); - VectorCopy (dir, vRay[1]); - - if (angle > 0) - { - int i; - float s, c; - float x, y; - - s = sin (-angle/180*Q_PI); - c = cos (-angle/180*Q_PI); - - for (i=0; i<2; i++) - { - x = vRay[i][0]; - y = vRay[i][1]; - vRay[i][0] = (x * c) - (y * s); - vRay[i][1] = (x * s) + (y * c); - } - } - - entitymodel *model = b->owner->md3Class->model; - - while (model != NULL) - { - for (i = 0; i < model->nTriCount; i++) - { - for (j = 0; j < 3; j++) - VectorCopy(model->pVertList[model->pTriList[i].indexes[j]].v, xyz[j]); - - if (Triangle_Ray(vRay[0], vRay[1], true, xyz[0], xyz[2], xyz[1], t, u, v)) - { - bIntersect = true; - if (*t < tBest) - tBest = *t; - } - } - model = model->pNext; - } - if (bIntersect) - { - *t = tBest; - return true; - } - else - { - *t = 0; - return false; - } -} -*/ - -/* -============== -Brush_Ray - -Itersects a ray with a brush -Returns the face hit and the distance along the ray the intersection occured at -Returns NULL and 0 if not hit at all - -http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=556 -============== -*/ -extern bool Patch_Ray(patchMesh_t *patch, vec3_t origin, vec3_t dir, double *t, double *u, double *v); -face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist, int nFlags) -{ - face_t *f, *firstface = NULL; - vec3_t p1, p2; - float frac, d1, d2; - int i; - - if (b->owner->eclass->fixedsize - && b->owner->model.pSelect - && !(!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY)) - && g_PrefsDlg.m_nEntityShowState != ENTITY_BOX) - { - ray_t ray_local; - vec_t dist_local = FLT_MAX; - ray_construct_for_vec3(&ray_local, origin, dir); - if (b->owner->model.pSelect->TestRay(&ray_local, &dist_local)) - { - *dist = dist_local; - return b->brush_faces; - } - else - { - *dist = 0.0f; - return NULL; - } - } - - VectorCopy (origin, p1); - for (i=0 ; i<3 ; i++) - p2[i] = p1[i] + dir[i]*2*g_MaxWorldCoord; - - for (f=b->brush_faces ; f ; f=f->next) - { - d1 = DotProduct (p1, f->plane.normal) - f->plane.dist; - d2 = DotProduct (p2, f->plane.normal) - f->plane.dist; - if (d1 >= 0 && d2 >= 0) - { - *dist = 0; - return NULL; // ray is on front side of face - } - if (d1 <=0 && d2 <= 0) - continue; - // clip the ray to the plane - frac = d1 / (d1 - d2); - if (d1 > 0) - { - firstface = f; - for (i=0 ; i<3 ; i++) - p1[i] = p1[i] + frac *(p2[i] - p1[i]); - } - else - { - for (i=0 ; i<3 ; i++) - p2[i] = p1[i] + frac *(p2[i] - p1[i]); - } - } - - // find distance p1 is along dir - VectorSubtract (p1, origin, p1); - d1 = DotProduct (p1, dir); - - *dist = d1; - - // new test stuff for patches - if (!g_PrefsDlg.m_bPatchBBoxSelect && b->patchBrush) - { - double t, u, v; // t is the distance from origin to point-of-intersection.. er.. i don't know what u and v are - if (!Patch_Ray(b->pPatch, origin, dir, &t, &u, &v)) - { - *dist = 0; - return NULL; - } - else - { - *dist = (float)t; - //Sys_Printf("t: %f, u: %f, v: %f\n", t, u, v); - } - } - - // IMPORTANT NOTE: - // modifications to the discarding code here should be matched in the selection code - // see Brush_Draw - - // do some last minute filtering - if (firstface && nFlags & SF_CAMERA) - { - if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK) - { - if (strstr(firstface->texdef.GetName(), "caulk")) - { - *dist = 0; - return NULL; - } - } - if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP) - { - if (strstr(firstface->texdef.GetName(), "botclip") || strstr(firstface->texdef.GetName(), "clipmonster")) - { - *dist = 0; - return NULL; - } - } - if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP) - { - if (strstr(firstface->texdef.GetName(), "clip")) - { - *dist = 0; - return NULL; - } - } - } - - return firstface; -} - -//PGM -face_t *Brush_Point (vec3_t origin, brush_t *b) -{ - face_t *f; - float d1; - - for (f=b->brush_faces ; f ; f=f->next) - { - d1 = DotProduct (origin, f->plane.normal) - f->plane.dist; - if (d1 > 0) - { - return NULL; // point is on front side of face - } - } - - return b->brush_faces; -} -//PGM - - -void Brush_AddToList (brush_t *b, brush_t *blist) -{ - if (b->next || b->prev) - Error ("Brush_AddToList: already linked"); - - if (blist == &selected_brushes || blist == &active_brushes) - { - if (b->patchBrush && blist == &selected_brushes) - { - Patch_Select(b->pPatch); - } - } - b->next = blist->next; - blist->next->prev = b; - blist->next = b; - b->prev = blist; - - // TTimo messaging - DispatchRadiantMsg( RADIANT_SELECTION ); -} - -void Brush_RemoveFromList (brush_t *b) -{ - if (!b->next || !b->prev) - Error ("Brush_RemoveFromList: not linked"); - - if (b->patchBrush) - { - Patch_Deselect(b->pPatch); - } - b->next->prev = b->prev; - b->prev->next = b->next; - b->next = b->prev = NULL; -} - -/* -=============== -SetFaceTexdef - -Doesn't set the curve flags - -NOTE : ( TTimo ) - never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture - use Texture_ForName() to find the right shader - FIXME : send the right shader ( qtexture_t * ) in the parameters ? - -TTimo: surface plugin, added an IPluginTexdef* parameter - if not NULL, get ->Copy() of it into the face ( and remember to hook ) - if NULL, ask for a default - - TTimo - shader code cleanup - added IShader* parameter - =============== -*/ -void SetFaceTexdef2 (brush_t *b, face_t *f, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) { - int oldFlags; - int oldContents; - face_t *tf; - - oldFlags = f->texdef.flags; - oldContents = f->texdef.contents; - if (g_qeglobals.m_bBrushPrimitMode) - { - f->texdef = *texdef; - ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() ); - } - else - if (bFitScale) - { - f->texdef = *texdef; - // fit the scaling of the texture on the actual plane - vec3_t p1,p2,p3; // absolute coordinates - // compute absolute coordinates - ComputeAbsolute(f,p1,p2,p3); - // compute the scale - vec3_t vx,vy; - VectorSubtract(p2,p1,vx); - VectorNormalize(vx, vx); - VectorSubtract(p3,p1,vy); - VectorNormalize(vy, vy); - // assign scale - VectorScale(vx,texdef->scale[0],vx); - VectorScale(vy,texdef->scale[1],vy); - VectorAdd(p1,vx,p2); - VectorAdd(p1,vy,p3); - // compute back shift scale rot - AbsoluteToLocal(f->plane,f,p1,p2,p3); - } - else - f->texdef = *texdef; - f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP); - f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP); - - // if this is a curve face, set all other curve faces to the same texdef - if (f->texdef.flags & SURF_CURVE) - { - for (tf = b->brush_faces ; tf ; tf = tf->next) - { - if (tf->texdef.flags & SURF_CURVE) - tf->texdef = f->texdef; - } - } -} - -/* -=============== -SetFaceTexdef - -Doesn't set the curve flags - -NOTE : ( TTimo ) - never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture - use Texture_ForName() to find the right shader - FIXME : send the right shader ( qtexture_t * ) in the parameters ? - - TTimo: surface plugin, added an IPluginTexdef* parameter - if not NULL, get ->Copy() of it into the face ( and remember to hook ) - if NULL, ask for a default -=============== -*/ -void SetFaceTexdef (face_t *f, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) { - int oldFlags; - int oldContents; - - oldFlags = f->texdef.flags; - oldContents = f->texdef.contents; - - if(strcmp(f->texdef.GetName(), texdef->GetName()) != 0) // set shader here instead of Brush_Build - Face_SetShader(f, texdef->GetName()); - - if (g_qeglobals.m_bBrushPrimitMode) - { - f->texdef = *texdef; - ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() ); - } - else - { - if (bFitScale) - { - f->texdef = *texdef; - // fit the scaling of the texture on the actual plane - vec3_t p1,p2,p3; // absolute coordinates - // compute absolute coordinates - ComputeAbsolute(f,p1,p2,p3); - // compute the scale - vec3_t vx,vy; - VectorSubtract(p2,p1,vx); - VectorNormalize(vx, vx); - VectorSubtract(p3,p1,vy); - VectorNormalize(vy, vy); - // assign scale - VectorScale(vx,texdef->scale[0],vx); - VectorScale(vy,texdef->scale[1],vy); - VectorAdd(p1,vx,p2); - VectorAdd(p1,vy,p3); - // compute back shift scale rot - AbsoluteToLocal(f->plane,f,p1,p2,p3); - } - else - { - f->texdef = *texdef; - } - } - f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP); - f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP); -} - -#ifdef _DEBUG -void Brush_SetTexture2 (brush_t *b, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef) -{ - for (face_t* f = b->brush_faces ; f ; f = f->next) - SetFaceTexdef2 (b, f, pShader, texdef, brushprimit_texdef, bFitScale, pTexdef); - Brush_Build( b ); - if (b->patchBrush) - { - Patch_SetTexture(b->pPatch, texdef, pTexdef ); - b->bFiltered = FilterBrush( b ); - } -} -#endif - -void Brush_SetTexture (brush_t *b, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef) -{ - for (face_t* f = b->brush_faces ; f ; f = f->next) - SetFaceTexdef (f, texdef, brushprimit_texdef, bFitScale, pTexdef); - Brush_Build( b ); - if (b->patchBrush) - { - Patch_SetTexture(b->pPatch, texdef, pTexdef ); - b->bFiltered = FilterBrush( b ); - } -} - - -qboolean ClipLineToFace (vec3_t p1, vec3_t p2, face_t *f) -{ - float d1, d2, fr; - int i; - float *v; - - d1 = DotProduct (p1, f->plane.normal) - f->plane.dist; - d2 = DotProduct (p2, f->plane.normal) - f->plane.dist; - - if (d1 >= 0 && d2 >= 0) - return false; // totally outside - if (d1 <= 0 && d2 <= 0) - return true; // totally inside - - fr = d1 / (d1 - d2); - - if (d1 > 0) - v = p1; - else - v = p2; - - for (i=0 ; i<3 ; i++) - v[i] = p1[i] + fr*(p2[i] - p1[i]); - - return true; -} - - -int AddPlanept (float *f) -{ - int i; - - for (i=0 ; iowner->eclass->fixedsize) - return; - - c = 0; - for (i=0 ; i<3 ; i++) - c += AddPlanept (f->planepts[i]); - if (c == 0) - return; // already completely added - - // select all points on this plane in all brushes the selection - for (b2=selected_brushes.next ; b2 != &selected_brushes ; b2 = b2->next) - { - if (b2 == b) - continue; - for (f2=b2->brush_faces ; f2 ; f2=f2->next) - { - for (i=0 ; i<3 ; i++) - if (fabs(DotProduct(f2->planepts[i], f->plane.normal) - -f->plane.dist) > ON_EPSILON) - break; - if (i==3) - { // move this face as well - Brush_SelectFaceForDragging (b2, f2, shear); - break; - } - } - } - - - // if shearing, take all the planes adjacent to - // selected faces and rotate their points so the - // edge clipped by a selcted face has two of the points - if (!shear) - return; - - for (f2=b->brush_faces ; f2 ; f2=f2->next) - { - if (f2 == f) - continue; - w = Brush_MakeFaceWinding (b, f2); - if (!w) - continue; - - // any points on f will become new control points - for (i=0 ; inumpoints ; i++) - { - d = DotProduct (w->points[i], f->plane.normal) - - f->plane.dist; - if (d > -ON_EPSILON && d < ON_EPSILON) - break; - } - - // - // if none of the points were on the plane, - // leave it alone - // - if (i != w->numpoints) - { - if (i == 0) - { // see if the first clockwise point was the - // last point on the winding - d = DotProduct (w->points[w->numpoints-1] - , f->plane.normal) - f->plane.dist; - if (d > -ON_EPSILON && d < ON_EPSILON) - i = w->numpoints - 1; - } - - AddPlanept (f2->planepts[0]); - - VectorCopy (w->points[i], f2->planepts[0]); - if (++i == w->numpoints) - i = 0; - - // see if the next point is also on the plane - d = DotProduct (w->points[i] - , f->plane.normal) - f->plane.dist; - if (d > -ON_EPSILON && d < ON_EPSILON) - AddPlanept (f2->planepts[1]); - - VectorCopy (w->points[i], f2->planepts[1]); - if (++i == w->numpoints) - i = 0; - - // the third point is never on the plane - - VectorCopy (w->points[i], f2->planepts[2]); - } - - free(w); - } -} - -/* -============== -Brush_SideSelect - -The mouse click did not hit the brush, so grab one or more side -planes for dragging -============== -*/ -void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir - , qboolean shear) -{ - face_t *f, *f2; - vec3_t p1, p2; - - for (f=b->brush_faces ; f ; f=f->next) - { - VectorCopy (origin, p1); - VectorMA (origin, 2*g_MaxWorldCoord, dir, p2); - - for (f2=b->brush_faces ; f2 ; f2=f2->next) - { - if (f2 == f) - continue; - ClipLineToFace (p1, p2, f2); - } - - if (f2) - continue; - - if (VectorCompare (p1, origin)) - continue; - if (ClipLineToFace (p1, p2, f)) - continue; - - Brush_SelectFaceForDragging (b, f, shear); - } -} - -bool g_bBuildWindingsNoTexBuild = false; - -void Brush_SetBuildWindingsNoTexBuild(bool bBuild) -{ - g_bBuildWindingsNoTexBuild = bBuild; -} - -// TTimo: don't rebuild pShader and d_texture if it doesn't seem necessary -// saves quite a lot of time, but on the other hand we've gotta make sure we clean the d_texture in some cases -// ie when we want to update a shader -// default will make Radiant rebuild the texture, but it can be turned off by setting the flag g_bBuildWindingsNoTexBuild -void Brush_BuildWindings( brush_t *b, bool bSnap ) -{ - winding_t *w; - face_t *face; - vec_t v; - - if (bSnap) - Brush_SnapPlanepts( b ); - - // clear the mins/maxs bounds - b->mins[0] = b->mins[1] = b->mins[2] = 99999; - b->maxs[0] = b->maxs[1] = b->maxs[2] = -99999; - - Brush_MakeFacePlanes (b); - - face = b->brush_faces; - - float fCurveColor = 1.0; - - for ( ; face ; face=face->next) - { - int i, j; - free(face->face_winding); - w = face->face_winding = Brush_MakeFaceWinding (b, face); - - if (!g_bBuildWindingsNoTexBuild || !face->d_texture) - { -#ifdef _DEBUG - // if there's no d_texture, then we expect pShader to be empty - if (!face->d_texture && face->pShader) - Sys_FPrintf(SYS_ERR, "ERROR: unexpected face->pShader != NULL with face->d_texture == NULL in Brush_BuildWindings\n"); -#endif - if ((!face->d_texture && !face->pShader) || !face->pShader) - { - // NOTE TTimo - // patch 84 for bug 253 doesn't dec ref the potential face->pShader - // add a debug check to make sure this is actually not necessary -#ifdef _DEBUG - if (face->pShader) - { - Sys_FPrintf(SYS_ERR, "ERROR: face->pShader != NULL in Brush_BuildWindings\n"); - } -#endif - face->pShader = QERApp_Shader_ForName( face->texdef.GetName() ); - face->pShader->IncRef(); - face->d_texture = face->pShader->getTexture(); - } - } - - if (!w) - continue; - - for (i=0 ; inumpoints ; i++) - { - // add to bounding box - for (j=0 ; j<3 ; j++) - { - v = w->points[i][j]; - if (v > b->maxs[j]) - b->maxs[j] = v; - if (v < b->mins[j]) - b->mins[j] = v; - } - } - Face_SetColor (b, face, fCurveColor); - - fCurveColor -= .10f; - if (fCurveColor <= 0) - fCurveColor = 1.0f; - - // computing ST coordinates for the windings - if (g_qeglobals.m_bBrushPrimitMode) - { - if (g_qeglobals.bNeedConvert) - { - // we have parsed old brushes format and need conversion - // convert old brush texture representation to new format - FaceToBrushPrimitFace(face); -#ifdef _DEBUG - // use old texture coordinates code to check against - for (i=0 ; inumpoints ; i++) - EmitTextureCoordinates( w->points[i], face->d_texture, face); -#endif - } - // use new texture representation to compute texture coordinates - // in debug mode we will check against old code and warn if there are differences - EmitBrushPrimitTextureCoordinates(face,w); - } - else - { - if (g_qeglobals.bNeedConvert) - { - BrushPrimitFaceToFace(face); -/* - // we have parsed brush primitives and need conversion back to standard format - // NOTE: converting back is a quick hack, there's some information lost and we can't do anything about it - // FIXME: if we normalize the texture matrix to a standard 2x2 size, we end up with wrong scaling - // I tried various tweaks, no luck .. seems shifting is lost - brushprimit_texdef_t aux; - ConvertTexMatWithQTexture( &face->brushprimit_texdef, face->d_texture, &aux, NULL ); - TexMatToFakeTexCoords( aux.coords, face->texdef.shift, &face->texdef.rotate, face->texdef.scale ); - face->texdef.scale[0]/=2.0; - face->texdef.scale[1]/=2.0; -*/ - } - for (i=0 ; inumpoints ; i++) - EmitTextureCoordinates( w->points[i], face->d_texture, face); - } - } -} - -/* -================== -Brush_RemoveEmptyFaces - -Frees any overconstraining faces -================== -*/ -void Brush_RemoveEmptyFaces ( brush_t *b ) -{ - face_t *f, *next; - - f = b->brush_faces; - b->brush_faces = NULL; - - for ( ; f ; f=next) - { - next = f->next; - if (!f->face_winding) - Face_Free (f); - else - { - f->next = b->brush_faces; - b->brush_faces = f; - } - - } -} - -void Brush_SnapToGrid(brush_t *pb) -{ - face_t *f; - vec3_t temp; - vec3_t diff[2]; - int mult[3]; - int i, j, n; - // TTimo: some brushes are "special" and should not be snapped - // specially fixed-size entity ones - if (pb->owner->eclass->fixedsize) - { - // save current origin - VectorCopy (pb->owner->origin, temp); - // snap the origin - VectorFSnap(pb->owner->origin, g_qeglobals.d_gridsize); - // return if amount is zero - if (VectorCompare (pb->owner->origin, temp)) - return; - // transform brush faces same amount - VectorSubtract (pb->owner->origin, temp, temp); - for (f = pb->brush_faces; f; f = f->next) - { - for (i=0 ; i<3 ; i++) - VectorAdd (f->planepts[i], temp, f->planepts[i]); - } - } - else - { - for (f = pb->brush_faces ; f; f = f->next) - { - for (j=0; j<2; j++) - { - // spog - move planepts apart just far enough to avoid snapping two together - VectorSubtract (f->planepts[j+1], f->planepts[j], diff[j]); - for (i=0; i<3; i++) - { - if (diff[j][i] == 0.0f) - mult[i] = 2; // next value up from 1 - else // multiplier = gridsize / component difference, rounded up - mult[i] = (int)ceil(fabs(g_qeglobals.d_gridsize / diff[j][i])); - } - - if (mult[0] > 1 && mult[1] > 1 && mult[2] > 1) // if all multipliers are greater than 1 - { - n = (mult[0] >= mult[1] && mult[0] >= mult[2]) ? 0 : (mult[1] >= mult[0] && mult[1] >= mult[2]) ? 1 : 2; - for (i=0; i<3; i++) - diff[j][i] *= mult[n]; // multiply difference by multiplier of smallest component - } - VectorAdd (f->planepts[j], diff[j], f->planepts[j+1]); - } - - for (i=0; i<3; i++) - VectorFSnap(f->planepts[i], g_qeglobals.d_gridsize); - - } - } - Brush_Build(pb,true,true,false,false); // don't filter -} - -void Brush_Rotate(brush_t *b, vec3_t vAngle, vec3_t vOrigin, bool bBuild) -{ - for (face_t* f=b->brush_faces ; f ; f=f->next) - { - for (int i=0 ; i<3 ; i++) - { - VectorRotateOrigin (f->planepts[i], vAngle, vOrigin, f->planepts[i]); - } - } - if (bBuild) - { - Brush_Build(b,false,false,false,false); // don't filter - } -} - -void Brush_Center(brush_t *b, vec3_t vNewCenter) -{ - vec3_t vMid; - // get center of the brush - for (int j = 0; j < 3; j++) - { - vMid[j] = b->mins[j] + fabs((b->maxs[j] - b->mins[j]) * 0.5); - } - // calc distance between centers - VectorSubtract(vNewCenter, vMid, vMid); - Brush_Move(b, vMid, true); - -} - -void Brush_Resize(brush_t *b, vec3_t vMin, vec3_t vMax) -{ - face_t *f; - texdef_t texdef; - int i; - short box[3][2] = { { 0, 1 }, { 2, 0 }, { 1, 2 } }; - - for (i=0 ; i<3 ; i++) - if (vMax[i] < vMin[i]) - Error ("Brush_Resize: invalid input"); - - if(b->brush_faces != NULL) - texdef = b->brush_faces->texdef; - else - texdef = g_qeglobals.d_texturewin.texdef; - - while (b->brush_faces != NULL) - { - f = b->brush_faces->next; - Face_Free(b->brush_faces); - b->brush_faces = f; - } - - for(i=0; i<3; i++) - { - f = b->brush_faces; - b->brush_faces = Face_Alloc(); - b->brush_faces->next = f; - f = b->brush_faces; - f->texdef = texdef; - VectorCopy(vMax, f->planepts[0]); - VectorCopy(vMax, f->planepts[1]); - VectorCopy(vMax, f->planepts[2]); - f->planepts[2][box[i][0]] = vMin[box[i][0]]; - f->planepts[1][box[i][1]] = vMin[box[i][1]]; - } - for(i=0; i<3; i++) - { - f = b->brush_faces; - b->brush_faces = Face_Alloc(); - b->brush_faces->next = f; - f = b->brush_faces; - f->texdef = texdef; - VectorCopy(vMin, f->planepts[0]); - VectorCopy(vMin, f->planepts[1]); - VectorCopy(vMin, f->planepts[2]); - f->planepts[1][box[i][0]] = vMax[box[i][0]]; - f->planepts[2][box[i][1]] = vMax[box[i][1]]; - } -} - -void FacingVectors (entity_t *e, vec3_t forward, vec3_t right, vec3_t up) -{ - int angleVal; - vec3_t angles; - - angleVal = IntForKey(e, "angle"); - if (angleVal == -1) // up - { - VectorSet(angles, 270, 0, 0); - } - else if(angleVal == -2) // down - { - VectorSet(angles, 90, 0, 0); - } - else - { - VectorSet(angles, 0, angleVal, 0); - } - - AngleVectors(angles, forward, right, up); -} - -void Brush_DrawFacingAngle (brush_t *b, entity_t *e) -{ - vec3_t forward, right, up; - vec3_t endpoint, tip1, tip2; - vec3_t start; - float dist; - - VectorAdd(e->brushes.onext->mins, e->brushes.onext->maxs, start); - VectorScale(start, 0.5, start); - dist = (b->maxs[0] - start[0]) * 2.5; - - FacingVectors (e, forward, right, up); - VectorMA (start, dist, forward, endpoint); - - dist = (b->maxs[0] - start[0]) * 0.5; - VectorMA (endpoint, -dist, forward, tip1); - VectorMA (tip1, -dist, up, tip1); - VectorMA (tip1, 2*dist, up, tip2); - - qglColor4f (1, 1, 1, 1); - qglLineWidth (4); - qglBegin (GL_LINES); - qglVertex3fv (start); - qglVertex3fv (endpoint); - qglVertex3fv (endpoint); - qglVertex3fv (tip1); - qglVertex3fv (endpoint); - qglVertex3fv (tip2); - qglEnd (); - qglLineWidth (1); -} - -void Brush_FaceDraw(face_t *face, int nGLState) -{ - const winding_t *w = face->face_winding; - if (w == NULL) return; - if (nGLState & DRAW_GL_LIGHTING && g_PrefsDlg.m_bGLLighting) - qglNormal3fv(face->plane.normal); - /* - if (mode & DRAW_GL_TEXTURE_2D) - qglTexCoordPointer(2, GL_FLOAT, 5, &w->points[3]); - qglVertexPointer(3, GL_FLOAT, 5, w->points); - - if (mode & DRAW_GL_FILL) - qglDrawArrays(GL_TRIANGLE_FAN, 0, w->numpoints); - else - qglDrawArrays(GL_POLYGON, 0, w->numpoints); - */ - - if (nGLState & DRAW_GL_FILL) - qglBegin(GL_TRIANGLE_FAN); - else - qglBegin(GL_POLYGON); - - for (int i=0 ; inumpoints ; i++) - { - if (nGLState & DRAW_GL_TEXTURE_2D) - qglTexCoord2fv( &w->points[i][3] ); - qglVertex3fv(w->points[i]); - } - qglEnd(); -} - -void Brush_Draw(brush_t *b) -{ - face_t *face; - int order; - qtexture_t *prev = 0; - winding_t *w; - - int nDrawMode = g_pParentWnd->GetCamWnd()->Camera()->draw_mode; - int nGLState = g_pParentWnd->GetCamWnd()->Camera()->draw_glstate; - - GLfloat material[4], identity[4]; - VectorSet(identity, 0.8f, 0.8f, 0.8f); - IShader *pShader; - qglPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); - qglDisableClientState(GL_NORMAL_ARRAY); - - // guarantee the texture will be set first - bool bTrans; - prev = NULL; - for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++) - { - w = face->face_winding; - if (!w) - { - continue; // freed face - } - - bTrans = (face->pShader->getFlags() & QER_TRANS); - - if (bTrans && !(nGLState & DRAW_GL_BLEND)) - continue; - if (!bTrans && nGLState & DRAW_GL_BLEND) - continue; - - // IMPORTANT NOTE: - // modifications to the discarding code here should be matched in the selection code - // see Brush_Ray - - if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK) - { - if (strstr(face->texdef.GetName(), "caulk")) - continue; - } - - if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP) - { - if (strstr(face->texdef.GetName(), "botclip") || strstr(face->texdef.GetName(), "clipmonster")) - continue; - } - - if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP) - { - if (strstr(face->texdef.GetName(), "clip")) - continue; - } - - if (nGLState & DRAW_GL_TEXTURE_2D && face->d_texture->name[0] == '(') - { - prev = NULL; - qglDisable(GL_TEXTURE_2D); - } - else if (nGLState & DRAW_GL_TEXTURE_2D && (nDrawMode == cd_texture || nDrawMode == cd_light) && face->d_texture != prev) - { - // set the texture for this face - prev = face->d_texture; - qglBindTexture( GL_TEXTURE_2D, face->d_texture->texture_number ); - } - - if (nGLState & DRAW_GL_LIGHTING && !g_PrefsDlg.m_bGLLighting) - { - if (!b->owner->eclass->fixedsize) - material[3] = face->pShader->getTrans(); - else - material[3] = 1; - VectorCopy(face->d_color, material); - - if (nGLState & DRAW_GL_TEXTURE_2D) - qglColor4f(face->d_shade, face->d_shade, face->d_shade, material[3]); - else - qglColor4fv(material); - } - else if (!b->owner->eclass->fixedsize) - { - pShader = face->pShader; - VectorCopy(pShader->getTexture()->color, material); - material[3] = identity[3] = pShader->getTrans(); - - if (nGLState & DRAW_GL_TEXTURE_2D) - qglColor4fv(identity); - else - qglColor4fv(material); - } - - // draw the polygon - - Brush_FaceDraw(face, nGLState); - } - qglPopClientAttrib(); -} - -void Face_Draw( face_t *f ) -{ - int i; - - if ( f->face_winding == 0 ) - return; - qglBegin(GL_POLYGON); - for ( i = 0 ; i < f->face_winding->numpoints; i++) - qglVertex3fv( f->face_winding->points[i] ); - qglEnd(); -} - -entity_t *FindEntity(const char *pszKey, const char *pszValue) -{ - entity_t *pe; - - pe = entities.next; - - for (; pe != NULL && pe != &entities ; pe = pe->next) - { - if (!strcmp(ValueForKey(pe, pszKey), pszValue)) - return pe; - } - - return NULL; -} - -void Brush_DrawXY(brush_t *b, int nViewType) -{ - face_t *face; - int order; - winding_t *w; - int i; - - if (b->patchBrush) - { - Patch_DrawXY(b->pPatch); - if (!g_bPatchShowBounds) - return; - } - - if (b->owner->eclass->fixedsize) - { - if (g_PrefsDlg.m_bNewLightDraw && (b->owner->eclass->nShowFlags & ECLASS_LIGHT)) - { -#if 1 // requires vertex arrays enabled - DrawLight(b->owner, DRAW_GL_WIRE, (IsBrushSelected(b)) ? g_PrefsDlg.m_nLightRadiuses : 0, nViewType); -#else - vec3_t vCorners[4]; - float fMid = b->mins[2] + (b->maxs[2] - b->mins[2]) / 2; - - vCorners[0][0] = b->mins[0]; - vCorners[0][1] = b->mins[1]; - vCorners[0][2] = fMid; - - vCorners[1][0] = b->mins[0]; - vCorners[1][1] = b->maxs[1]; - vCorners[1][2] = fMid; - - vCorners[2][0] = b->maxs[0]; - vCorners[2][1] = b->maxs[1]; - vCorners[2][2] = fMid; - - vCorners[3][0] = b->maxs[0]; - vCorners[3][1] = b->mins[1]; - vCorners[3][2] = fMid; - - vec3_t vTop, vBottom; - - vTop[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) / 2); - vTop[1] = b->mins[1] + ((b->maxs[1] - b->mins[1]) / 2); - vTop[2] = b->maxs[2]; - - VectorCopy(vTop, vBottom); - vBottom[2] = b->mins[2]; - - qglBegin(GL_LINES); - qglVertex3fv(vTop); - qglVertex3fv(vCorners[0]); - qglVertex3fv(vTop); - qglVertex3fv(vCorners[1]); - qglVertex3fv(vTop); - qglVertex3fv(vCorners[2]); - qglVertex3fv(vTop); - qglVertex3fv(vCorners[3]); - qglEnd(); - - qglBegin(GL_LINES); - qglVertex3fv(vBottom); - qglVertex3fv(vCorners[0]); - qglVertex3fv(vBottom); - qglVertex3fv(vCorners[1]); - qglVertex3fv(vBottom); - qglVertex3fv(vCorners[2]); - qglVertex3fv(vBottom); - qglVertex3fv(vCorners[3]); - qglEnd(); - - qglBegin(GL_LINE_LOOP); - qglVertex3fv(vCorners[0]); - qglVertex3fv(vCorners[1]); - qglVertex3fv(vCorners[2]); - qglVertex3fv(vCorners[3]); - qglEnd(); -#endif - DrawBrushEntityName (b); - return; - } - else if (b->owner->model.pRender && !(!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY))) - { - qglPushAttrib(GL_CURRENT_BIT); // save brush colour - qglColor3fv(b->owner->eclass->color); - if( g_PrefsDlg.m_nEntityShowState != ENTITY_BOX ) - b->owner->model.pRender->Draw(DRAW_GL_WIRE, DRAW_RF_XY); - aabb_draw(b->owner->model.pRender->GetAABB(), DRAW_GL_WIRE); - qglPopAttrib(); - return; - } - //} - } - - for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++) - { - // moved so check occurs earlier - w = face->face_winding; - if (!w) - continue; - // only draw polygons facing in a direction we care about - if (nViewType == XY) - { - if (face->plane.normal[2] <= 0) - continue; - } - else - { - if (nViewType == XZ) - { - if (face->plane.normal[1] >= 0) // stop axes being mirrored - continue; - } - else - { - if (face->plane.normal[0] <= 0) - continue; - } - } - - // draw the polygon - qglBegin(GL_LINE_LOOP); - for (i=0 ; inumpoints ; i++) - qglVertex3fv(w->points[i]); - qglEnd(); - } - - DrawBrushEntityName (b); - -} - -/* -============ -Brush_Move -============ -*/ -void Brush_Move (brush_t *b, const vec3_t move, bool bSnap) -{ - int i; - face_t *f; - - for (f=b->brush_faces ; f ; f=f->next) - for (i=0 ; i<3 ; i++) - VectorAdd (f->planepts[i], move, f->planepts[i]); - - if (g_PrefsDlg.m_bTextureLock && !b->owner->eclass->fixedsize) - { - for (f=b->brush_faces ; f ; f=f->next) - { - vec3_t vTemp; - VectorCopy(move, vTemp); - Face_MoveTexture(f, vTemp); - } - } - - Brush_Build( b, bSnap,true,false,false); // don't filter - - - if (b->patchBrush) - { - //Patch_Move(b->nPatchID, move); - Patch_Move(b->pPatch, move); - } - - - // PGM - keep the origin vector up to date on fixed size entities. - if(b->owner->eclass->fixedsize) - { - char text[64]; - VectorAdd(b->owner->origin, move, b->owner->origin); - sprintf (text, "%i %i %i", - (int)b->owner->origin[0], (int)b->owner->origin[1], (int)b->owner->origin[2]); - SetKeyValue(b->owner, "origin", text); - //VectorAdd(b->maxs, b->mins, b->owner->origin); - //VectorScale(b->owner->origin, 0.5, b->owner->origin); - } -} - - - -void Brush_Print(brush_t* b) -{ - int nFace = 0; - for (face_t* f = b->brush_faces ; f ; f=f->next) - { - Sys_Printf("Face %i\n", nFace++); - Sys_Printf("%f %f %f\n", f->planepts[0][0], f->planepts[0][1], f->planepts[0][2]); - Sys_Printf("%f %f %f\n", f->planepts[1][0], f->planepts[1][1], f->planepts[1][2]); - Sys_Printf("%f %f %f\n", f->planepts[2][0], f->planepts[2][1], f->planepts[2][2]); - } - } - - - -/* -============= -Brush_MakeSided - -Makes the current brushhave the given number of 2d sides and turns it into a cone -============= -*/ -void Brush_MakeSidedCone(int sides) -{ - int i; - vec3_t mins, maxs; - brush_t *b; - texdef_t *texdef; - face_t *f; - vec3_t mid; - float width; - float sv, cv; - - if (sides < 3 || sides > 32) - { - Sys_Status ("Bad sides number", 0); - return; - } - - if (!QE_SingleBrush ()) - { - Sys_Status ("Must have a single brush selected", 0 ); - return; - } - - b = selected_brushes.next; - VectorCopy (b->mins, mins); - VectorCopy (b->maxs, maxs); - texdef = &g_qeglobals.d_texturewin.texdef; - - Brush_Free (b); - - // find center of brush - width = 8; - for (i=0 ; i<2 ; i++) - { - mid[i] = (maxs[i] + mins[i])*0.5; - if (maxs[i] - mins[i] > width) - width = maxs[i] - mins[i]; - } - width /= 2; - - b = Brush_Alloc(); - - // create bottom face - f = Face_Alloc(); - f->texdef = *texdef; - f->next = b->brush_faces; - b->brush_faces = f; - - f->planepts[0][0] = mins[0];f->planepts[0][1] = mins[1];f->planepts[0][2] = mins[2]; - f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = mins[2]; - f->planepts[2][0] = maxs[0];f->planepts[2][1] = maxs[1];f->planepts[2][2] = mins[2]; - - for (i=0 ; itexdef = *texdef; - f->next = b->brush_faces; - b->brush_faces = f; - - sv = sin (i*3.14159265*2/sides); - cv = cos (i*3.14159265*2/sides); - - - f->planepts[0][0] = floor(mid[0]+width*cv+0.5); - f->planepts[0][1] = floor(mid[1]+width*sv+0.5); - f->planepts[0][2] = mins[2]; - - f->planepts[1][0] = mid[0]; - f->planepts[1][1] = mid[1]; - f->planepts[1][2] = maxs[2]; - - f->planepts[2][0] = floor(f->planepts[0][0] - width * sv + 0.5); - f->planepts[2][1] = floor(f->planepts[0][1] + width * cv + 0.5); - f->planepts[2][2] = maxs[2]; - - } - - Brush_AddToList (b, &selected_brushes); - - Entity_LinkBrush (world_entity, b); - - Brush_Build( b ); - - Sys_UpdateWindows (W_ALL); -} - -/* -============= -Brush_MakeSided - -Makes the current brushhave the given number of 2d sides and turns it into a sphere -============= - -*/ -void Brush_MakeSidedSphere(int sides) -{ - int i,j; - vec3_t mins, maxs; - brush_t *b; - texdef_t *texdef; - face_t *f; - vec3_t mid; - - if (sides < 4 || sides > 32) - { - Sys_Status ("Bad sides number", 0); - return; - } - - if (!QE_SingleBrush ()) - { - Sys_Status ("Must have a single brush selected", 0 ); - return; - } - - b = selected_brushes.next; - VectorCopy (b->mins, mins); - VectorCopy (b->maxs, maxs); - texdef = &g_qeglobals.d_texturewin.texdef; - - Brush_Free (b); - - // find center of brush - float radius = 8; - for (i=0 ; i<2 ; i++) - { - mid[i] = (maxs[i] + mins[i])*0.5; - if (maxs[i] - mins[i] > radius) - radius = maxs[i] - mins[i]; - } - radius /= 2; - - b = Brush_Alloc(); - - float dt = float(2 * Q_PI / sides); - float dp = float(Q_PI / sides); - float t,p; - for(i=0; i <= sides-1; i++) - { - for(j=0;j <= sides-2; j++) - { - t = i * dt; - p = float(j * dp - Q_PI / 2); - - f = Face_Alloc(); - f->texdef = *texdef; - f->next = b->brush_faces; - b->brush_faces = f; - - VectorPolar(f->planepts[0], radius, t, p); - VectorPolar(f->planepts[1], radius, t, p + dp); - VectorPolar(f->planepts[2], radius, t + dt, p + dp); - - for (int k = 0; k < 3; k++) - VectorAdd(f->planepts[k], mid, f->planepts[k]); - } - } - - p = float((sides - 1) * dp - Q_PI / 2); - for(i = 0; i <= sides-1; i++) - { - t = i * dt; - - f = Face_Alloc(); - f->texdef = *texdef; - f->next = b->brush_faces; - b->brush_faces = f; - - VectorPolar(f->planepts[0], radius, t, p); - VectorPolar(f->planepts[1], radius, t + dt, p + dp); - VectorPolar(f->planepts[2], radius, t + dt, p); - - for (int k = 0; k < 3; k++) - VectorAdd(f->planepts[k], mid, f->planepts[k]); - } - - Brush_AddToList (b, &selected_brushes); - - Entity_LinkBrush (world_entity, b); - - Brush_Build( b ); - - Sys_UpdateWindows (W_ALL); -} - -void Face_FitTexture( face_t * face, int nHeight, int nWidth ) -{ - winding_t *w; - vec3_t mins,maxs; - int i; - float width, height, temp; - float rot_width, rot_height; - float cosv,sinv,ang; - float min_t, min_s, max_t, max_s; - float s,t; - vec3_t vecs[2]; - vec3_t coords[4]; - texdef_t *td; - - if (nHeight < 1) - nHeight = 1; - if (nWidth < 1) - nWidth = 1; - - ClearBounds (mins, maxs); - - w = face->face_winding; - if (!w) - { - return; - } - for (i=0 ; inumpoints ; i++) - { - AddPointToBounds( w->points[i], mins, maxs ); - } - - if (g_qeglobals.m_bBrushPrimitMode) - Face_FitTexture_BrushPrimit( face, mins, maxs, nHeight, nWidth ); - else - { - - td = &face->texdef; - // - // get the current angle - // - ang = td->rotate / 180 * Q_PI; - sinv = sin(ang); - cosv = cos(ang); - - // get natural texture axis - TextureAxisFromPlane(&face->plane, vecs[0], vecs[1]); - - min_s = DotProduct( mins, vecs[0] ); - min_t = DotProduct( mins, vecs[1] ); - max_s = DotProduct( maxs, vecs[0] ); - max_t = DotProduct( maxs, vecs[1] ); - width = max_s - min_s; - height = max_t - min_t; - coords[0][0] = min_s; - coords[0][1] = min_t; - coords[1][0] = max_s; - coords[1][1] = min_t; - coords[2][0] = min_s; - coords[2][1] = max_t; - coords[3][0] = max_s; - coords[3][1] = max_t; - min_s = min_t = 99999; - max_s = max_t = -99999; - for (i=0; i<4; i++) - { - s = cosv * coords[i][0] - sinv * coords[i][1]; - t = sinv * coords[i][0] + cosv * coords[i][1]; - if (i&1) - { - if (s > max_s) - { - max_s = s; - } - } - else - { - if (s < min_s) - { - min_s = s; - } - if (i<2) - { - if (t < min_t) - { - min_t = t; - } - } - else - { - if (t > max_t) - { - max_t = t; - } - } - } - } - rot_width = (max_s - min_s); - rot_height = (max_t - min_t); - td->scale[0] = -(rot_width/((float)(face->d_texture->width*nWidth))); - td->scale[1] = -(rot_height/((float)(face->d_texture->height*nHeight))); - - td->shift[0] = min_s/td->scale[0]; - temp = (int)(td->shift[0] / (face->d_texture->width*nWidth)); - temp = (temp+1)*face->d_texture->width*nWidth; - td->shift[0] = (int)(temp - td->shift[0])%(face->d_texture->width*nWidth); - - td->shift[1] = min_t/td->scale[1]; - temp = (int)(td->shift[1] / (face->d_texture->height*nHeight)); - temp = (temp+1)*(face->d_texture->height*nHeight); - td->shift[1] = (int)(temp - td->shift[1])%(face->d_texture->height*nHeight); - - td->shift[1] = min_t/td->scale[1]; - temp = (int)(td->shift[1] / (face->d_texture->height*nHeight)); - temp = (temp+1)*(face->d_texture->height*nHeight); - td->shift[1] = (int)(temp - td->shift[1])%(face->d_texture->height*nHeight); - - } -} - -void Brush_FitTexture( brush_t *b, int nHeight, int nWidth ) -{ - face_t *face; - - for (face = b->brush_faces ; face ; face=face->next) - { - Face_FitTexture( face, nHeight, nWidth ); - } -} - -void aabb_draw(const aabb_t *aabb, int mode) -{ - vec3_t normals[6] = { { 1, 0, 0}, { 0, 1, 0 }, { 0, 0, 1 }, {-1, 0, 0}, { 0,-1, 0 }, { 0, 0,-1 } }; - vec3_t points[8]; - vec3_t vMin, vMax; - VectorSubtract(aabb->origin, aabb->extents, vMin); - VectorAdd(aabb->origin, aabb->extents, vMax); - VectorSet(points[0], vMin[0], vMax[1], vMax[2]); - VectorSet(points[1], vMax[0], vMax[1], vMax[2]); - VectorSet(points[2], vMax[0], vMin[1], vMax[2]); - VectorSet(points[3], vMin[0], vMin[1], vMax[2]); - VectorSet(points[4], vMin[0], vMax[1], vMin[2]); - VectorSet(points[5], vMax[0], vMax[1], vMin[2]); - VectorSet(points[6], vMax[0], vMin[1], vMin[2]); - VectorSet(points[7], vMin[0], vMin[1], vMin[2]); - - qglBegin(GL_QUADS); - - qglNormal3fv(normals[0]); - qglVertex3fv(points[2]); - qglVertex3fv(points[1]); - qglVertex3fv(points[5]); - qglVertex3fv(points[6]); - - qglNormal3fv(normals[1]); - qglVertex3fv(points[1]); - qglVertex3fv(points[0]); - qglVertex3fv(points[4]); - qglVertex3fv(points[5]); - - qglNormal3fv(normals[2]); - qglVertex3fv(points[0]); - qglVertex3fv(points[1]); - qglVertex3fv(points[2]); - qglVertex3fv(points[3]); - - qglNormal3fv(normals[3]); - qglVertex3fv(points[3]); - qglVertex3fv(points[7]); - qglVertex3fv(points[4]); - qglVertex3fv(points[0]); - - qglNormal3fv(normals[4]); - qglVertex3fv(points[3]); - qglVertex3fv(points[2]); - qglVertex3fv(points[6]); - qglVertex3fv(points[7]); - - qglNormal3fv(normals[5]); - qglVertex3fv(points[7]); - qglVertex3fv(points[6]); - qglVertex3fv(points[5]); - qglVertex3fv(points[4]); - - qglEnd(); - -/* - - - vec3_t Coords[8]; - - vec3_t vMin, vMax; - VectorSubtract(aabb->origin, aabb->extents, vMin); - VectorAdd(aabb->origin, aabb->extents, vMax); - VectorSet(Coords[0], vMin[0], vMax[1], vMax[2]); - VectorSet(Coords[1], vMax[0], vMax[1], vMax[2]); - VectorSet(Coords[2], vMax[0], vMin[1], vMax[2]); - VectorSet(Coords[3], vMin[0], vMin[1], vMax[2]); - VectorSet(Coords[4], vMin[0], vMax[1], vMin[2]); - VectorSet(Coords[5], vMax[0], vMax[1], vMin[2]); - VectorSet(Coords[6], vMax[0], vMin[1], vMin[2]); - VectorSet(Coords[7], vMin[0], vMin[1], vMin[2]); - - vec3_t Normals[8] = { {-1, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 1 }, - { 0, 0,-1 }, - { 0, 1, 0 }, - { 1, 0, 0 }, - { 0,-1, 0 } }; - - unsigned short Indices[24] = { 2, 1, 5, 6, - 1, 0, 4, 5, - 0, 1, 2, 3, - 3, 7, 4, 0, - 3, 2, 6, 7, - 7, 6, 5, 4 }; - - qglVertexPointer(3, GL_FLOAT, 0, Coords); // filling the arrays - qglNormalPointer(GL_FLOAT, 0, Normals); - - //glLockArraysEXT(0, count); // extension GL_EXT_compiled_vertex_array - - qglDrawElements(GL_QUADS, 24, GL_UNSIGNED_SHORT, Indices); - - //glUnlockArraysEXT; // extension GL_EXT_compiled_vertex_array -*/ -} - -qboolean IsBrushSelected(brush_t* bSel) -{ - for (brush_t* b = selected_brushes.next ;b != NULL && b != &selected_brushes; b = b->next) - { - if (b == bSel) - return true; - } - return false; -} - - +/* +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 +*/ + +#include "stdafx.h" +#include +#include "winding.h" +#include +#include "filters.h" + +extern MainFrame* g_pParentWnd; +extern void MemFile_fprintf(MemStream* pMemFile, const char* pText, ...); + +// globals + +int g_nBrushId = 0; + +#ifdef ENABLE_GROUPS +const char* Brush_Name(brush_t *b) +{ + static char cBuff[1024]; + b->numberId = g_nBrushId++; + if (g_qeglobals.m_bBrushPrimitMode) + { + sprintf(cBuff, "Brush %i", b->numberId); + Brush_SetEpair(b, "Name", cBuff); + } + return cBuff; +} +#endif + +brush_t *Brush_Alloc() +{ + brush_t *b = (brush_t*)qmalloc(sizeof(brush_t)); + return b; +} +/* +void Brush_Free(brush_t *b) +{ + free(b); +} +*/ +void PrintWinding (winding_t *w) +{ + int i; + + Sys_Printf ("-------------\n"); + for (i=0 ; inumpoints ; i++) + Sys_Printf ("(%5.2f, %5.2f, %5.2f)\n", w->points[i][0] + , w->points[i][1], w->points[i][2]); +} + +void PrintPlane (plane_t *p) +{ + Sys_Printf ("(%5.2f, %5.2f, %5.2f) : %5.2f\n", p->normal[0], p->normal[1], + p->normal[2], p->dist); +} + +void PrintVector (vec3_t v) +{ + Sys_Printf ("(%5.2f, %5.2f, %5.2f)\n", v[0], v[1], v[2]); +} + + +/* +============================================================================= + + TEXTURE COORDINATES + +============================================================================= +*/ + + +/* +================== +textureAxisFromPlane +================== +*/ +vec3_t baseaxis[18] = +{ +{0,0,1}, {1,0,0}, {0,-1,0}, // floor +{0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling +{1,0,0}, {0,1,0}, {0,0,-1}, // west wall +{-1,0,0}, {0,1,0}, {0,0,-1}, // east wall +{0,1,0}, {1,0,0}, {0,0,-1}, // south wall +{0,-1,0}, {1,0,0}, {0,0,-1} // north wall +}; + +void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv) +{ + int bestaxis; + float dot,best; + int i; + + best = 0; + bestaxis = 0; + + for (i=0 ; i<6 ; i++) + { + dot = DotProduct (pln->normal, baseaxis[i*3]); + if (g_PrefsDlg.m_bQ3Map2Texturing && dot > best + 0.0001f || dot > best) + { + best = dot; + bestaxis = i; + } + } + + VectorCopy (baseaxis[bestaxis*3+1], xv); + VectorCopy (baseaxis[bestaxis*3+2], yv); +} + + + +float lightaxis[3] = {0.6f, 0.8f, 1.0f}; +/* +================ +SetShadeForPlane + +Light different planes differently to +improve recognition +================ +*/ +extern float ShadeForNormal(vec3_t normal); + +float SetShadeForPlane (plane_t *p) +{ + //return ShadeForNormal(p->normal); + + + int i; + float f; + + // axial plane + for (i=0 ; i<3 ; i++) + if (fabs(p->normal[i]) > 0.9) + { + f = lightaxis[i]; + return f; + } + + // between two axial planes + for (i=0 ; i<3 ; i++) + if (fabs(p->normal[i]) < 0.1) + { + f = (lightaxis[(i+1)%3] + lightaxis[(i+2)%3])/2; + return f; + } + + // other + f= (lightaxis[0] + lightaxis[1] + lightaxis[2]) / 3; + return f; + +} + +vec3_t vecs[2]; +float shift[2]; + +/* +================ +Face_Alloc +================ +*/ +face_t *Face_Alloc( void ) +{ + face_t *f = (face_t*)qmalloc( sizeof( *f ) ); + return f; +} + +/* +================ +Face_Free +================ +*/ +void Face_Free( face_t *f ) +{ + assert( f != 0 ); + + if ( f->face_winding ) + { + free( f->face_winding ); + f->face_winding = 0; + } + f->texdef.~texdef_t();; + + free( f ); +} + +/* +================ +Face_Clone +================ +*/ +face_t *Face_Clone (face_t *f) +{ + face_t *n; + + n = Face_Alloc(); + n->texdef = f->texdef; + n->brushprimit_texdef = f->brushprimit_texdef; + + memcpy (n->planepts, f->planepts, sizeof(n->planepts)); + + // all other fields are derived, and will be set by Brush_Build + // FIXME: maybe not, for example n->pData! + return n; +} + +/* +================ +Face_FullClone + +makes an exact copy of the face +================ +*/ +face_t *Face_FullClone (face_t *f) +{ + face_t *n; + + n = Face_Alloc(); + n->texdef = f->texdef; + n->brushprimit_texdef = f->brushprimit_texdef; + memcpy(n->planepts, f->planepts, sizeof(n->planepts)); + memcpy(&n->plane, &f->plane, sizeof(plane_t)); + if (f->face_winding) + n->face_winding = Winding_Clone(f->face_winding); + else + n->face_winding = NULL; + n->pShader = f->pShader; + n->pShader->IncRef(); + n->d_texture = n->pShader->getTexture(); + return n; +} + +void Face_SetShader(face_t *face, const char *name) +{ + if(face->pShader != NULL) + face->pShader->DecRef(); + face->texdef.SetName(name); + face->pShader = QERApp_Shader_ForName(name); + face->pShader->IncRef(); + face->d_texture = face->pShader->getTexture(); + face->texdef.flags = face->pShader->getFlags(); +} + +void Face_SetShader(face_t *face, IShader *shader) +{ + if(face->pShader != NULL) + face->pShader->DecRef(); + face->texdef.SetName(shader->getName()); + face->d_texture = shader->getTexture(); + face->texdef.flags = shader->getFlags(); + face->pShader = shader; + face->pShader->IncRef(); +} + +/* +================ +Clamp +================ +*/ +void Clamp(float& f, int nClamp) +{ + float fFrac = f - static_cast(f); + f = static_cast(f) % nClamp; + f += fFrac; +} + +/* +================ +Face_MoveTexture +================ +*/ +void Face_MoveTexture(face_t *f, vec3_t delta) +{ + vec3_t vX, vY; + + if (g_qeglobals.m_bBrushPrimitMode) + ShiftTextureGeometric_BrushPrimit( f, delta ); + else + { + TextureAxisFromPlane(&f->plane, vX, vY); + + vec3_t vDP, vShift; + vDP[0] = DotProduct(delta, vX); + vDP[1] = DotProduct(delta, vY); + + double fAngle = f->texdef.rotate / 180 * Q_PI; + double c = cos(fAngle); + double s = sin(fAngle); + + vShift[0] = vDP[0] * c - vDP[1] * s; + vShift[1] = vDP[0] * s + vDP[1] * c; + + if (!f->texdef.scale[0]) + f->texdef.scale[0] = g_pGameDescription->mTextureDefaultScale; + if (!f->texdef.scale[1]) + f->texdef.scale[1] = g_pGameDescription->mTextureDefaultScale; + + f->texdef.shift[0] -= vShift[0] / f->texdef.scale[0]; + f->texdef.shift[1] -= vShift[1] / f->texdef.scale[1]; + + // clamp the shifts + Clamp(f->texdef.shift[0], f->d_texture->width); + Clamp(f->texdef.shift[1], f->d_texture->height); + } +} + +/* +================ +Face_SetColor +================ +*/ +/*!\todo Replace all face_t::d_texture access with face_t::pShader::GetTexture.*/ +void Face_SetColor (brush_t *b, face_t *f, float fCurveColor) +{ + // set shading for face + f->d_shade = SetShadeForPlane (&f->plane); + f->d_color[0] = f->pShader->getTexture()->color[0] * f->d_shade; + f->d_color[1] = f->pShader->getTexture()->color[1] * f->d_shade; + f->d_color[2] = f->pShader->getTexture()->color[2] * f->d_shade; +} + +/* +================ +Face_TextureVectors +================ +*/ +void Face_TextureVectors (face_t *f, float STfromXYZ[2][4]) +{ + vec3_t pvecs[2]; + int sv, tv; + float ang, sinv, cosv; + float ns, nt; + int i,j; + qtexture_t *q; + texdef_t *td; + +#ifdef _DEBUG + // this code is not supposed to be used while in BP mode, warning here can help spot the problem + if (g_qeglobals.m_bBrushPrimitMode && !g_qeglobals.bNeedConvert) + Sys_Printf("Warning : illegal call of Face_TextureVectors in brush primitive mode\n"); +#endif + + td = &f->texdef; + q = f->d_texture; + + memset (STfromXYZ, 0, 8*sizeof(float)); + + if (!td->scale[0]) + td->scale[0] = g_pGameDescription->mTextureDefaultScale; + if (!td->scale[1]) + td->scale[1] = g_pGameDescription->mTextureDefaultScale; + + // get natural texture axis + TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]); + + // rotate axis + if (td->rotate == 0) + { sinv = 0 ; cosv = 1; } + else if (td->rotate == 90) + { sinv = 1 ; cosv = 0; } + else if (td->rotate == 180) + { sinv = 0 ; cosv = -1; } + else if (td->rotate == 270) + { sinv = -1 ; cosv = 0; } + else + { + ang = td->rotate / 180 * Q_PI; + sinv = sin(ang); + cosv = cos(ang); + } + + if (pvecs[0][0]) + sv = 0; + else if (pvecs[0][1]) + sv = 1; + else + sv = 2; + + if (pvecs[1][0]) + tv = 0; + else if (pvecs[1][1]) + tv = 1; + else + tv = 2; + + for (i=0 ; i<2 ; i++) { + ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv]; + nt = sinv * pvecs[i][sv] + cosv * pvecs[i][tv]; + STfromXYZ[i][sv] = ns; + STfromXYZ[i][tv] = nt; + } + + // scale + for (i=0 ; i<2 ; i++) + for (j=0 ; j<3 ; j++) + STfromXYZ[i][j] = STfromXYZ[i][j] / td->scale[i]; + + // shift + STfromXYZ[0][3] = td->shift[0]; + STfromXYZ[1][3] = td->shift[1]; + + for (j=0 ; j<4 ; j++) { + STfromXYZ[0][j] /= q->width; + STfromXYZ[1][j] /= q->height; + } +} + +/* +================ +Face_MakePlane +================ +*/ +void Face_MakePlane (face_t *f) +{ + int j; + vec3_t t1, t2, t3; + + // convert to a vector / dist plane + for (j=0 ; j<3 ; j++) + { + t1[j] = f->planepts[0][j] - f->planepts[1][j]; + t2[j] = f->planepts[2][j] - f->planepts[1][j]; + t3[j] = f->planepts[1][j]; + } + + CrossProduct(t1,t2, f->plane.normal); + if (VectorCompare (f->plane.normal, vec3_origin)) + Sys_FPrintf (SYS_WRN, "WARNING: brush plane with no normal\n"); + VectorNormalize (f->plane.normal, f->plane.normal); + f->plane.dist = DotProduct (t3, f->plane.normal); +} + +/* +================ +EmitTextureCoordinates +================ +*/ +void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f) +{ + float STfromXYZ[2][4]; + + Face_TextureVectors (f, STfromXYZ); + xyzst[3] = DotProduct (xyzst, STfromXYZ[0]) + STfromXYZ[0][3]; + xyzst[4] = DotProduct (xyzst, STfromXYZ[1]) + STfromXYZ[1][3]; +} + +//========================================================================== + +/* +================ +Brush_MakeFacePlanes +================ +*/ +void Brush_MakeFacePlanes (brush_t *b) +{ + face_t *f; + + for (f=b->brush_faces ; f ; f=f->next) + { + Face_MakePlane (f); + } +} + +/* +================ +DrawBrushEntityName +================ +*/ +void DrawBrushEntityName (brush_t *b) +{ + const char *name; + float a, s, c; + vec3_t mid; + int i; + + if (!b->owner) + return; // during contruction + + if (b->owner == world_entity) + return; + + if (b != b->owner->brushes.onext) + return; // not key brush + + // TTimo: Brush_DrawFacingAngle is for camera view rendering, this function is called for 2D views + // FIXME - spog - not sure who put this here.. Brush_DrawFacingAngle() does this job? + // Brush_DrawFacingAngle() works when called, but is not being called. + if (g_qeglobals.d_savedinfo.show_angles && (b->owner->eclass->nShowFlags & ECLASS_ANGLE)) + { + // draw the angle pointer + a = FloatForKey (b->owner, "angle"); + s = sin (a/180*Q_PI); + c = cos (a/180*Q_PI); + for (i=0 ; i<3 ; i++) + mid[i] = (b->mins[i] + b->maxs[i])*0.5; + + qglBegin (GL_LINE_STRIP); + qglVertex3fv (mid); + mid[0] += c*8; + mid[1] += s*8; + mid[2] += s*8; + qglVertex3fv (mid); + mid[0] -= c*4; + mid[1] -= s*4; + mid[2] -= s*4; + mid[0] -= s*4; + mid[1] += c*4; + mid[2] += c*4; + qglVertex3fv (mid); + mid[0] += c*4; + mid[1] += s*4; + mid[2] += s*4; + mid[0] += s*4; + mid[1] -= c*4; + mid[2] -= c*4; + qglVertex3fv (mid); + mid[0] -= c*4; + mid[1] -= s*4; + mid[2] -= s*4; + mid[0] += s*4; + mid[1] -= c*4; + mid[2] -= c*4; + qglVertex3fv (mid); + qglEnd (); + } + + if (g_qeglobals.d_savedinfo.show_names) + { + name = ValueForKey (b->owner, "classname"); + qglRasterPos3f (b->mins[0]+4, b->mins[1]+4, b->mins[2]+4); + gtk_glwidget_print_string(name); + } +} + +/* +================= +Brush_MakeFaceWinding + +returns the visible polygon on a face +================= +*/ +winding_t *Brush_MakeFaceWinding (brush_t *b, face_t *face) +{ + winding_t *w; + face_t *clip; + plane_t plane; + qboolean past; + + // get a poly that covers an effectively infinite area + w = Winding_BaseForPlane (&face->plane); + + // chop the poly by all of the other faces + past = false; + for (clip = b->brush_faces ; clip && w ; clip=clip->next) + { + if (clip == face) + { + past = true; + continue; + } + if (DotProduct (face->plane.normal, clip->plane.normal) > 0.999 + && fabs(face->plane.dist - clip->plane.dist) < 0.01 ) + { // identical plane, use the later one + if (past) + { + free (w); + return NULL; + } + continue; + } + + // flip the plane, because we want to keep the back side + VectorSubtract (vec3_origin,clip->plane.normal, plane.normal); + plane.dist = -clip->plane.dist; + + w = Winding_Clip (w, &plane, false); + if (!w) + return w; + } + + if (w->numpoints < 3) + { + free(w); + w = NULL; + } + + if (!w) + Sys_FPrintf (SYS_WRN, "unused plane\n"); + + return w; +} + +/* +================= +Brush_SnapPlanepts +================= +*/ +void Brush_SnapPlanepts (brush_t *b) +{ + int i, j; + face_t *f; + + if (g_PrefsDlg.m_bNoClamp) + return; + + if (g_qeglobals.d_bSmallGrid) + { + for (f=b->brush_faces ; f; f=f->next) + for (i=0 ; i<3 ; i++) + for (j=0 ; j<3 ; j++) + f->planepts[i][j] = floor (f->planepts[i][j]/g_qeglobals.d_gridsize + 0.5)*g_qeglobals.d_gridsize; + } + else + { + for (f=b->brush_faces ; f; f=f->next) + for (i=0 ; i<3 ; i++) + for (j=0 ; j<3 ; j++) + f->planepts[i][j] = floor (f->planepts[i][j] + 0.5); + } +} + +/* +** Brush_Build +** +** Builds a brush rendering data and also sets the min/max bounds +*/ +// TTimo +// added a bConvert flag to convert between old and new brush texture formats +// TTimo +// brush grouping: update the group treeview if necessary +void Brush_Build( brush_t *b, bool bSnap, bool bMarkMap, bool bConvert, bool bFilterTest) +{ + bool bLocalConvert; + + +#ifdef _DEBUG + if (!g_qeglobals.m_bBrushPrimitMode && bConvert) + Sys_Printf("Warning : conversion from brush primitive to old brush format not implemented\n"); +#endif + + // if bConvert is set and g_qeglobals.bNeedConvert is not, that just means we need convert for this brush only + if (bConvert && !g_qeglobals.bNeedConvert) + { +#ifdef _DEBUG + //++timo FIXME: it's not very clear when this can happen, I guess while dealing with plugins that send brushes + // back and forth in one format or the other .. more when mixing BP / noBP in the same maps. +#endif + bLocalConvert = true; + g_qeglobals.bNeedConvert = true; + } + else + bLocalConvert = false; + + /* + ** build the windings and generate the bounding box + */ + Brush_BuildWindings(b, bSnap); + + if(b->owner->model.pRender) + { + const aabb_t *aabb = b->owner->model.pRender->GetAABB(); + VectorAdd(aabb->origin, aabb->extents, b->maxs); + VectorSubtract(aabb->origin, aabb->extents, b->mins); + } + + //Patch_BuildPoints (b); // does nothing but set b->patchBrush true if the texdef contains SURF_PATCH ! + + /* + ** move the points and edges if in select mode + */ + if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge) + SetupVertexSelection (); + + if (b->itemOwner == 0) //NULL) + Group_AddToProperGroup(b); + + if (bMarkMap) + { + Sys_MarkMapModified(); + } + + if (bLocalConvert) + g_qeglobals.bNeedConvert = false; + + // spog - applying filters to brush during brush_build instead of during redraw + if (bFilterTest) + b->bFiltered = FilterBrush( b ); +} + +/* +============== +Brush_SplitBrushByFace + +The incoming brush is NOT freed. +The incoming face is NOT left referenced. +============== +*/ +void Brush_SplitBrushByFace (brush_t *in, face_t *f, brush_t **front, brush_t **back, boolean bCaulk) +{ + brush_t *b; + face_t *nf; + vec3_t temp; + + b = Brush_Clone (in); + nf = Face_Clone (f); + + nf->texdef = b->brush_faces->texdef; + if (bCaulk) + { + nf->texdef.SetName(g_pGameDescription->mCaulkShader.GetBuffer()); + } + nf->next = b->brush_faces; + b->brush_faces = nf; + + Brush_Build( b ); + Brush_RemoveEmptyFaces ( b ); + if ( !b->brush_faces ) + { // completely clipped away + Brush_Free (b); + *back = NULL; + } + else + { + Entity_LinkBrush (in->owner, b); + *back = b; + } + + b = Brush_Clone (in); + nf = Face_Clone (f); + // swap the plane winding + VectorCopy (nf->planepts[0], temp); + VectorCopy (nf->planepts[1], nf->planepts[0]); + VectorCopy (temp, nf->planepts[1]); + + nf->texdef = b->brush_faces->texdef; + if (bCaulk) + { + nf->texdef.SetName(g_pGameDescription->mCaulkShader.GetBuffer()); + } + nf->next = b->brush_faces; + b->brush_faces = nf; + + Brush_Build( b ); + Brush_RemoveEmptyFaces ( b ); + if ( !b->brush_faces ) + { // completely clipped away + Brush_Free (b); + *front = NULL; + } + else + { + Entity_LinkBrush (in->owner, b); + *front = b; + } +} + +/* +================= +Brush_BestSplitFace + +returns the best face to split the brush with. +return NULL if the brush is convex +================= +*/ +face_t *Brush_BestSplitFace(brush_t *b) +{ + face_t *face, *f, *bestface; + winding_t *front, *back; + int splits, tinywindings, value, bestvalue; + + bestvalue = 999999; + bestface = NULL; + for (face = b->brush_faces; face; face = face->next) + { + splits = 0; + tinywindings = 0; + for (f = b->brush_faces; f; f = f->next) + { + if (f == face) continue; + // + Winding_SplitEpsilon(f->face_winding, face->plane.normal, face->plane.dist, 0.1f, &front, &back); + + if (!front) + { + Winding_Free(back); + } + else if (!back) + { + Winding_Free(front); + } + else + { + splits++; + if (Winding_IsTiny(front)) tinywindings++; + if (Winding_IsTiny(back)) tinywindings++; + } + } + if (splits) + { + value = splits + 50 * tinywindings; + if (value < bestvalue) + { + bestvalue = value; + bestface = face; + } + } + } + return bestface; +} + +/* +================= +Brush_MakeConvexBrushes + +MrE FIXME: this doesn't work because the old + Brush_SplitBrushByFace is used +Turns the brush into a minimal number of convex brushes. +If the input brush is convex then it will be returned. +Otherwise the input brush will be freed. +NOTE: the input brush should have windings for the faces. +================= +*/ +brush_t *Brush_MakeConvexBrushes(brush_t *b) +{ + brush_t *front, *back, *end; + face_t *face; + + b->next = NULL; + face = Brush_BestSplitFace(b); + if (!face) return b; + Brush_SplitBrushByFace(b, face, &front, &back); + //this should never happen + if (!front && !back) return b; + Brush_Free(b); + if (!front) + return Brush_MakeConvexBrushes(back); + b = Brush_MakeConvexBrushes(front); + if (back) + { + for (end = b; end->next; end = end->next); + end->next = Brush_MakeConvexBrushes(back); + } + return b; +} + +/* +================= +Brush_Convex +================= +*/ +int Brush_Convex(brush_t *b) +{ + face_t *face1, *face2; + + for (face1 = b->brush_faces; face1; face1 = face1->next) + { + if (!face1->face_winding) continue; + for (face2 = b->brush_faces; face2; face2 = face2->next) + { + if (face1 == face2) continue; + if (!face2->face_winding) continue; + if (Winding_PlanesConcave(face1->face_winding, face2->face_winding, + face1->plane.normal, face2->plane.normal, + face1->plane.dist, face2->plane.dist)) + { + return false; + } + } + } + return true; +} + +/* +================= +Brush_MoveVertexes + +- The input brush must be convex +- The input brush must have face windings. +- The output brush will be convex. +- Returns true if the WHOLE vertex movement is performed. +================= +*/ + +// define this to debug the vertex editing mode +#ifdef _DEBUG +//#define DBG_VERT +#endif + +#define MAX_MOVE_FACES 64 + +int Brush_MoveVertex(brush_t *b, vec3_t vertex, vec3_t delta, vec3_t end, bool bSnap) +{ + face_t *f, *face, *newface, *lastface, *nextface; + face_t *movefaces[MAX_MOVE_FACES]; + int movefacepoints[MAX_MOVE_FACES]; + winding_t *w, tmpw; + vec3_t start, mid; + plane_t plane; + int i, j, k, nummovefaces, result, done; + float dot, front, back, frac, smallestfrac; + +#ifdef DBG_VERT + Sys_Printf("Bursh_MoveVertex: %p vertex: %g %g %g delta: %g %g %g end: %g %g %g snap: %s\n", b, vertex[0], vertex[1], vertex[2], delta[0], delta[1], delta[2], end[0], end[1], end[2], bSnap ? "true" : "false" ); +#endif + + result = true; + // + tmpw.numpoints = 3; + tmpw.maxpoints = 3; + VectorCopy(vertex, start); + VectorAdd(vertex, delta, end); + //snap or not? + if (bSnap) + for (i = 0; i < 3; i++) + end[i] = floor(end[i] / g_qeglobals.d_gridsize + 0.1) * g_qeglobals.d_gridsize; + // + VectorCopy(end, mid); + //if the start and end are the same + if (Point_Equal(start, end, 0.3f)) return false; + //the end point may not be the same as another vertex + for (face = b->brush_faces; face; face = face->next) + { + w = face->face_winding; + if (!w) continue; + for (i = 0; i < w->numpoints; i++) + { + if (Point_Equal(w->points[i], end, 0.3f)) + { + VectorCopy(vertex, end); + return false; + } + } + } + // + done = false; + while(!done) + { + //chop off triangles from all brush faces that use the to be moved vertex + //store pointers to these chopped off triangles in movefaces[] + nummovefaces = 0; + for (face = b->brush_faces; face; face = face->next) + { + w = face->face_winding; + if (!w) continue; + for (i = 0; i < w->numpoints; i++) + { + if (Point_Equal(w->points[i], start, 0.2f)) + { + if (face->face_winding->numpoints <= 3) + { + movefacepoints[nummovefaces] = i; + movefaces[nummovefaces++] = face; + break; + } + dot = DotProduct(end, face->plane.normal) - face->plane.dist; + //if the end point is in front of the face plane + if (dot > 0.1) + { + //fanout triangle subdivision + for (k = i; k < i + w->numpoints-3; k++) + { + VectorCopy(w->points[i], tmpw.points[0]); + VectorCopy(w->points[(k+1) % w->numpoints], tmpw.points[1]); + VectorCopy(w->points[(k+2) % w->numpoints], tmpw.points[2]); + // + newface = Face_Clone(face); + //get the original + for (f = face; f->original; f = f->original) ; + newface->original = f; + //store the new winding + if (newface->face_winding) Winding_Free(newface->face_winding); + newface->face_winding = Winding_Clone(&tmpw); + //get the texture information + newface->pShader = face->pShader; + newface->d_texture = face->d_texture; + + //add the face to the brush + newface->next = b->brush_faces; + b->brush_faces = newface; + //add this new triangle to the move faces + movefacepoints[nummovefaces] = 0; + movefaces[nummovefaces++] = newface; + } + //give the original face a new winding + VectorCopy(w->points[(i-2+w->numpoints) % w->numpoints], tmpw.points[0]); + VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[1]); + VectorCopy(w->points[i], tmpw.points[2]); + Winding_Free(face->face_winding); + face->face_winding = Winding_Clone(&tmpw); + //add the original face to the move faces + movefacepoints[nummovefaces] = 2; + movefaces[nummovefaces++] = face; + } + else + { + //chop a triangle off the face + VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[0]); + VectorCopy(w->points[i], tmpw.points[1]); + VectorCopy(w->points[(i+1) % w->numpoints], tmpw.points[2]); + //remove the point from the face winding + Winding_RemovePoint(w, i); + //get texture crap right + Face_SetColor(b, face, 1.0); + for (j = 0; j < w->numpoints; j++) + EmitTextureCoordinates(w->points[j], face->d_texture, face); + //make a triangle face + newface = Face_Clone(face); + //get the original + for (f = face; f->original; f = f->original) ; + newface->original = f; + //store the new winding + if (newface->face_winding) Winding_Free(newface->face_winding); + newface->face_winding = Winding_Clone(&tmpw); + //get the texture + newface->pShader = face->pShader; + newface->d_texture = newface->pShader->getTexture(); +// newface->d_texture = QERApp_Texture_ForName2( newface->texdef.name ); + //add the face to the brush + newface->next = b->brush_faces; + b->brush_faces = newface; + // + movefacepoints[nummovefaces] = 1; + movefaces[nummovefaces++] = newface; + } + break; + } + } + } + //now movefaces contains pointers to triangle faces that + //contain the to be moved vertex + // + done = true; + VectorCopy(end, mid); + smallestfrac = 1; + for (face = b->brush_faces; face; face = face->next) + { + //check if there is a move face that has this face as the original + for (i = 0; i < nummovefaces; i++) + { + if (movefaces[i]->original == face) break; + } + if (i >= nummovefaces) continue; + //check if the original is not a move face itself + for (j = 0; j < nummovefaces; j++) + { + if (face == movefaces[j]) break; + } + //if the original is not a move face itself + if (j >= nummovefaces) + { + memcpy(&plane, &movefaces[i]->original->plane, sizeof(plane_t)); + } + else + { + k = movefacepoints[j]; + w = movefaces[j]->face_winding; + VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[0]); + VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[1]); + // + k = movefacepoints[i]; + w = movefaces[i]->face_winding; + VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[2]); + if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane)) + { + VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[2]); + if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane)) + //this should never happen otherwise the face merge did a crappy job a previous pass + continue; + } + } + //now we've got the plane to check agains + front = DotProduct(start, plane.normal) - plane.dist; + back = DotProduct(end, plane.normal) - plane.dist; + //if the whole move is at one side of the plane + if (front < 0.01 && back < 0.01) continue; + if (front > -0.01 && back > -0.01) continue; + //if there's no movement orthogonal to this plane at all + if (fabs(front-back) < 0.001) continue; + //ok first only move till the plane is hit + frac = front/(front-back); + if (frac < smallestfrac) + { + mid[0] = start[0] + (end[0] - start[0]) * frac; + mid[1] = start[1] + (end[1] - start[1]) * frac; + mid[2] = start[2] + (end[2] - start[2]) * frac; + smallestfrac = frac; + } + // + done = false; + } + + //move the vertex + for (i = 0; i < nummovefaces; i++) + { + //move vertex to end position + VectorCopy(mid, movefaces[i]->face_winding->points[movefacepoints[i]]); + //create new face plane + for (j = 0; j < 3; j++) + { + VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]); + } + Face_MakePlane(movefaces[i]); + if (VectorLength(movefaces[i]->plane.normal) < 0.1) + result = false; + } + //if the brush is no longer convex + if (!result || !Brush_Convex(b)) + { + for (i = 0; i < nummovefaces; i++) + { + //move the vertex back to the initial position + VectorCopy(start, movefaces[i]->face_winding->points[movefacepoints[i]]); + //create new face plane + for (j = 0; j < 3; j++) + { + VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]); + } + Face_MakePlane(movefaces[i]); + } + result = false; + VectorCopy(start, end); + done = true; + } + else + { + VectorCopy(mid, start); + } + //get texture crap right + for (i = 0; i < nummovefaces; i++) + { + Face_SetColor(b, movefaces[i], 1.0); + for (j = 0; j < movefaces[i]->face_winding->numpoints; j++) + EmitTextureCoordinates(movefaces[i]->face_winding->points[j], movefaces[i]->d_texture, movefaces[i]); + } + + //now try to merge faces with their original faces + lastface = NULL; + for (face = b->brush_faces; face; face = nextface) + { + nextface = face->next; + if (!face->original) + { + lastface = face; + continue; + } + if (!Plane_Equal(&face->plane, &face->original->plane, false)) + { + lastface = face; + continue; + } + w = Winding_TryMerge(face->face_winding, face->original->face_winding, face->plane.normal, true); + if (!w) + { + lastface = face; + continue; + } + Winding_Free(face->original->face_winding); + face->original->face_winding = w; + //get texture crap right + Face_SetColor(b, face->original, 1.0); + for (j = 0; j < face->original->face_winding->numpoints; j++) + EmitTextureCoordinates(face->original->face_winding->points[j], face->original->d_texture, face->original); + //remove the face that was merged with the original + if (lastface) lastface->next = face->next; + else b->brush_faces = face->next; + Face_Free(face); + } + } + return result; +} + +/* +================= +Brush_InsertVertexBetween +================= +*/ +int Brush_InsertVertexBetween(brush_t *b, vec3_t p1, vec3_t p2) +{ + face_t *face; + winding_t *w, *neww; + vec3_t point; + int i, insert; + + if (Point_Equal(p1, p2, 0.4f)) + return false; + VectorAdd(p1, p2, point); + VectorScale(point, 0.5f, point); + insert = false; + //the end point may not be the same as another vertex + for (face = b->brush_faces; face; face = face->next) + { + w = face->face_winding; + if (!w) continue; + neww = NULL; + for (i = 0; i < w->numpoints; i++) + { + if (!Point_Equal(w->points[i], p1, 0.1f)) + continue; + if (Point_Equal(w->points[(i+1) % w->numpoints], p2, 0.1f)) + { + neww = Winding_InsertPoint(w, point, (i+1) % w->numpoints); + break; + } + else if (Point_Equal(w->points[(i-1+w->numpoints) % w->numpoints], p2, 0.3f)) + { + neww = Winding_InsertPoint(w, point, i); + break; + } + } + if (neww) + { + Winding_Free(face->face_winding); + face->face_winding = neww; + insert = true; + } + } + return insert; +} + + +/* +================= +Brush_ResetFaceOriginals +================= +*/ +void Brush_ResetFaceOriginals(brush_t *b) +{ + face_t *face; + + for (face = b->brush_faces; face; face = face->next) + { + face->original = NULL; + } +} + +#ifdef ENABLE_GROUPS +/* +============== +Brush_SetEpair +sets an epair for the given brush +============== +*/ +void Brush_SetEpair(brush_t *b, const char *pKey, const char *pValue) +{ + if (g_qeglobals.m_bBrushPrimitMode) + { + if (b->patchBrush) + { + Patch_SetEpair(b->pPatch, pKey, pValue); + } + else + { + SetKeyValue(b->epairs, pKey, pValue); + } + } + else + { + Sys_Printf("Can only set key/values in Brush primitive mode\n"); + } +} + +/* +================= +Brush_GetKeyValue +================= +*/ +const char* Brush_GetKeyValue(brush_t *b, const char *pKey) +{ + if (g_qeglobals.m_bBrushPrimitMode) + { + if (b->patchBrush) + { + return Patch_GetKeyValue(b->pPatch, pKey); + } + else + { + return ValueForKey(b->epairs, pKey); + } + } + else + { + Sys_Printf("Can only set brush/patch key/values in Brush primitive mode\n"); + } + return ""; +} +#endif +/* +================= +CheckName +temporary stuff, detect potential problems when saving the texture name +================= +*/ +void CheckName( face_t *fa, char *pname ) +{ + if (!strlen(fa->texdef.GetName())) + { +#ifdef _DEBUG + Sys_Printf("WARNING: unexpected texdef.name is empty in Brush.cpp CheckName\n"); +#endif + fa->texdef.SetName(SHADER_NOT_FOUND); + strcpy(pname, SHADER_NOT_FOUND); + return; + } + + // some people manage to get long filename textures (with spaces) in their maps + if (strchr( fa->texdef.GetName(), ' ' )) + { + char Msg1[1024]; + + sprintf( Msg1, "Can't save texture with spaces in name. Rename %s\nNOTE: This message may popup several times .. once for each buggy face detected.", fa->texdef.GetName() ); + + Sys_Printf("%s\n", Msg1 ); + gtk_MessageBox(g_pParentWnd->m_pWidget, Msg1, "Error saving map", MB_OK ); + strcpy( pname, SHADER_NOT_FOUND ); + return; + } + + //++timo FIXME: bug #103494 detection attempt + // TODO: clean this detection part when bug will have disappeared + if (fa->texdef.GetName()[0] == '(') + { + char *text = "Bug #103494 detected, dropping texture. Please report to timo@qeradiant.com if you have a way to reproduce!\nNOTE: this message may popup several times .. once for each buggy face detected."; + Sys_Printf("%s\n", text); + gtk_MessageBox(g_pParentWnd->m_pWidget, text, "Error saving map", MB_OK ); + // need to cleanup this dead face name or we may loop endlessly + fa->texdef.SetName(SHADER_NOT_FOUND); + strcpy( pname, SHADER_NOT_FOUND ); + return; + } + strcpy( pname, fa->texdef.GetName()+9 ); // remove "textures/" +} + +/* +============= +Brush_Create + +Create non-textured blocks for entities +The brush is NOT linked to any list +============= +*/ +brush_t *Brush_Create (vec3_t mins, vec3_t maxs, texdef_t *texdef) +{ + int i, j; + vec3_t pts[4][2]; + face_t *f; + brush_t *b; + +#if DBG_BP + // brush primitive mode : convert texdef to brushprimit_texdef ? + // most of the time texdef is empty + if (g_qeglobals.m_bBrushPrimitMode) + { + // check texdef is empty .. if there are cases it's not we need to write some conversion code + if (texdef->shift[0]!=0 || texdef->shift[1]!=0 || texdef->scale[0]!=0 || texdef->scale[1]!=0 || texdef->rotate!=0) + Sys_Printf("Warning : non-zero texdef detected in Brush_Create .. need brush primitive conversion\n"); + } +#endif + + for (i=0 ; i<3 ; i++) + { + if (maxs[i] < mins[i]) + Error ("Brush_InitSolid: backwards"); + } + + b = Brush_Alloc(); + + pts[0][0][0] = mins[0]; + pts[0][0][1] = mins[1]; + + pts[1][0][0] = mins[0]; + pts[1][0][1] = maxs[1]; + + pts[2][0][0] = maxs[0]; + pts[2][0][1] = maxs[1]; + + pts[3][0][0] = maxs[0]; + pts[3][0][1] = mins[1]; + + for (i=0 ; i<4 ; i++) + { + pts[i][0][2] = mins[2]; + pts[i][1][0] = pts[i][0][0]; + pts[i][1][1] = pts[i][0][1]; + pts[i][1][2] = maxs[2]; + } + + for (i=0 ; i<4 ; i++) + { + f = Face_Alloc(); + f->texdef = *texdef; + f->texdef.flags &= ~SURF_KEEP; + f->texdef.contents &= ~CONTENTS_KEEP; + f->next = b->brush_faces; + b->brush_faces = f; + j = (i+1)%4; + + VectorCopy (pts[j][1], f->planepts[0]); + VectorCopy (pts[i][1], f->planepts[1]); + VectorCopy (pts[i][0], f->planepts[2]); + } + + f = Face_Alloc(); + f->texdef = *texdef; + f->texdef.flags &= ~SURF_KEEP; + f->texdef.contents &= ~CONTENTS_KEEP; + f->next = b->brush_faces; + b->brush_faces = f; + + VectorCopy (pts[0][1], f->planepts[0]); + VectorCopy (pts[1][1], f->planepts[1]); + VectorCopy (pts[2][1], f->planepts[2]); + + f = Face_Alloc(); + f->texdef = *texdef; + f->texdef.flags &= ~SURF_KEEP; + f->texdef.contents &= ~CONTENTS_KEEP; + f->next = b->brush_faces; + b->brush_faces = f; + + VectorCopy (pts[2][0], f->planepts[0]); + VectorCopy (pts[1][0], f->planepts[1]); + VectorCopy (pts[0][0], f->planepts[2]); + + return b; +} + +/* +============= +Brush_CreatePyramid + +Create non-textured pyramid for light entities +The brush is NOT linked to any list +============= +*/ +brush_t *Brush_CreatePyramid (vec3_t mins, vec3_t maxs, texdef_t *texdef) +{ + int i; + + //++timo handle new brush primitive ? return here ?? + return Brush_Create(mins, maxs, texdef); + + for (i=0 ; i<3 ; i++) + if (maxs[i] < mins[i]) + Error ("Brush_InitSolid: backwards"); + + brush_t* b = Brush_Alloc(); + + vec3_t corners[4]; + + float fMid = Rad_rint(mins[2] + (Rad_rint((maxs[2] - mins[2]) / 2))); + + corners[0][0] = mins[0]; + corners[0][1] = mins[1]; + corners[0][2] = fMid; + + corners[1][0] = mins[0]; + corners[1][1] = maxs[1]; + corners[1][2] = fMid; + + corners[2][0] = maxs[0]; + corners[2][1] = maxs[1]; + corners[2][2] = fMid; + + corners[3][0] = maxs[0]; + corners[3][1] = mins[1]; + corners[3][2] = fMid; + + vec3_t top, bottom; + + top[0] = Rad_rint(mins[0] + ((maxs[0] - mins[0]) / 2)); + top[1] = Rad_rint(mins[1] + ((maxs[1] - mins[1]) / 2)); + top[2] = Rad_rint(maxs[2]); + + VectorCopy(top, bottom); + bottom[2] = mins[2]; + + // sides + for (i = 0; i < 4; i++) + { + face_t* f = Face_Alloc(); + f->texdef = *texdef; + f->texdef.flags &= ~SURF_KEEP; + f->texdef.contents &= ~CONTENTS_KEEP; + f->next = b->brush_faces; + b->brush_faces = f; + int j = (i+1)%4; + + VectorCopy (top, f->planepts[0]); + VectorCopy (corners[i], f->planepts[1]); + VectorCopy(corners[j], f->planepts[2]); + + f = Face_Alloc(); + f->texdef = *texdef; + f->texdef.flags &= ~SURF_KEEP; + f->texdef.contents &= ~CONTENTS_KEEP; + f->next = b->brush_faces; + b->brush_faces = f; + + VectorCopy (bottom, f->planepts[2]); + VectorCopy (corners[i], f->planepts[1]); + VectorCopy(corners[j], f->planepts[0]); + } + + return b; +} + + + + +/* +============= +Brush_MakeSided + +Makes the current brush have the given number of 2d sides +============= +*/ +void Brush_MakeSided (int sides) +{ + int i, axis; + vec3_t mins, maxs; + brush_t *b; + texdef_t *texdef; + face_t *f; + vec3_t mid; + float width; + float sv, cv; + + if (sides < 3) + { + Sys_Status ("Bad sides number", 0); + return; + } + + if (sides >= MAX_POINTS_ON_WINDING-4) + { + Sys_Printf("too many sides.\n"); + return; + } + + if (!QE_SingleBrush ()) + { + Sys_Status ("Must have a single brush selected", 0 ); + return; + } + + b = selected_brushes.next; + VectorCopy (b->mins, mins); + VectorCopy (b->maxs, maxs); + texdef = &g_qeglobals.d_texturewin.texdef; + + Brush_Free (b); + + if (g_pParentWnd->ActiveXY()) + { + switch(g_pParentWnd->ActiveXY()->GetViewType()) + { + case XY: axis = 2; break; + case XZ: axis = 1; break; + case YZ: axis = 0; break; + } + } + else + { + axis = 2; + } + + // find center of brush + width = 8; + for (i = 0; i < 3; i++) + { + mid[i] = (maxs[i] + mins[i]) * 0.5; + if (i == axis) continue; + if ((maxs[i] - mins[i]) * 0.5 > width) + width = (maxs[i] - mins[i]) * 0.5; + } + + b = Brush_Alloc(); + + // create top face + f = Face_Alloc(); + f->texdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + + f->planepts[2][(axis+1)%3] = mins[(axis+1)%3]; f->planepts[2][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[2][axis] = maxs[axis]; + f->planepts[1][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[1][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[1][axis] = maxs[axis]; + f->planepts[0][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[0][(axis+2)%3] = maxs[(axis+2)%3]; f->planepts[0][axis] = maxs[axis]; + + // create bottom face + f = Face_Alloc(); + f->texdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + + f->planepts[0][(axis+1)%3] = mins[(axis+1)%3]; f->planepts[0][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[0][axis] = mins[axis]; + f->planepts[1][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[1][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[1][axis] = mins[axis]; + f->planepts[2][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[2][(axis+2)%3] = maxs[(axis+2)%3]; f->planepts[2][axis] = mins[axis]; + + for (i=0 ; itexdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + + sv = sin (i*3.14159265*2/sides); + cv = cos (i*3.14159265*2/sides); + + f->planepts[0][(axis+1)%3] = floor(mid[(axis+1)%3]+width*cv+0.5); + f->planepts[0][(axis+2)%3] = floor(mid[(axis+2)%3]+width*sv+0.5); + f->planepts[0][axis] = mins[axis]; + + f->planepts[1][(axis+1)%3] = f->planepts[0][(axis+1)%3]; + f->planepts[1][(axis+2)%3] = f->planepts[0][(axis+2)%3]; + f->planepts[1][axis] = maxs[axis]; + + f->planepts[2][(axis+1)%3] = floor(f->planepts[0][(axis+1)%3] - width*sv + 0.5); + f->planepts[2][(axis+2)%3] = floor(f->planepts[0][(axis+2)%3] + width*cv + 0.5); + f->planepts[2][axis] = maxs[axis]; + } + + Brush_AddToList (b, &selected_brushes); + + Entity_LinkBrush (world_entity, b); + + Brush_Build( b ); + + Sys_UpdateWindows (W_ALL); +} + + + +/* +============= +Brush_Free + +Frees the brush with all of its faces and display list. +Unlinks the brush from whichever chain it is in. +Decrements the owner entity's brushcount. +Removes owner entity if this was the last brush +unless owner is the world. +Removes from groups +============= +*/ +void Brush_Free (brush_t *b, bool bRemoveNode) +{ + face_t *f, *next; + epair_t *ep, *enext; + + // remove from group + if (bRemoveNode) + Group_RemoveBrush(b); + + // free the patch if it's there + if (b->patchBrush) + { + Patch_Delete(b->pPatch); + } + + // free faces + for (f=b->brush_faces ; f ; f=next) + { + next = f->next; + Face_Free( f ); + } + + // TTimo : free brush epairs + for (ep = b->epairs ; ep ; ep=enext ) + { + enext = ep->next; + free (ep->key); + free (ep->value); + free (ep); + } + + // unlink from active/selected list + if (b->next) + Brush_RemoveFromList (b); + + // unlink from entity list + if (b->onext) + Entity_UnlinkBrush (b); + + free (b); +} + +/* +============= +Face_MemorySize +============= +*/ +int Face_MemorySize(face_t *f ) +{ + int size = 0; + + if (f->face_winding) + { +// size += _msize(f->face_winding); + size += sizeof(vec3_t)*f->face_winding->numpoints+2*sizeof(int); + } +// size += _msize(f); + size += sizeof(face_t); + return size; +} + +/* +============= +Brush_MemorySize +============= +*/ +int Brush_MemorySize(brush_t *b) +{ + face_t *f; + epair_t *ep; + int size = 0; + + // + if (b->patchBrush) + { + size += Patch_MemorySize(b->pPatch); + } + // + for (f = b->brush_faces; f; f = f->next) + { + size += Face_MemorySize(f); + } + // + for (ep = b->epairs; ep; ep = ep->next ) + { +// size += _msize(ep->key); + size += strlen(ep->key); +// size += _msize(ep->value); + size += strlen(ep->value); +// size += _msize(ep); + size += sizeof(epair_t); + } +// size += _msize(b); + size += sizeof(brush_t); + return size; +} + + +/* +============ +Brush_Clone + +Does NOT add the new brush to any lists +============ +*/ +brush_t *Brush_Clone (brush_t *b) +{ + brush_t *n = NULL; + face_t *f, *nf; + + if (b->patchBrush) + { + patchMesh_t *p = Patch_Duplicate(b->pPatch); + Brush_RemoveFromList(p->pSymbiot); + Entity_UnlinkBrush(p->pSymbiot); + n = p->pSymbiot; + } + else + { + n = Brush_Alloc(); + n->numberId = g_nBrushId++; + n->owner = b->owner; + for (f=b->brush_faces ; f ; f=f->next) + { + nf = Face_Clone( f ); + nf->next = n->brush_faces; + n->brush_faces = nf; + } + } + + return n; +} + +/* +============ +Brush_Clone + +Does NOT add the new brush to any lists +============ +*/ +brush_t *Brush_FullClone(brush_t *b) +{ + brush_t *n = NULL; + face_t *f, *nf, *f2, *nf2; + int j; + + if (b->patchBrush) + { + patchMesh_t *p = Patch_Duplicate(b->pPatch); + Brush_RemoveFromList(p->pSymbiot); + Entity_UnlinkBrush(p->pSymbiot); + n = p->pSymbiot; + n->owner = b->owner; + Brush_Build(n); + } + else + { + n = Brush_Alloc(); + n->numberId = g_nBrushId++; + n->owner = b->owner; + VectorCopy(b->mins, n->mins); + VectorCopy(b->maxs, n->maxs); + // + for (f = b->brush_faces; f; f = f->next) + { + if (f->original) continue; + nf = Face_FullClone(f); + nf->next = n->brush_faces; + n->brush_faces = nf; + //copy all faces that have the original set to this face + for (f2 = b->brush_faces; f2; f2 = f2->next) + { + if (f2->original == f) + { + nf2 = Face_FullClone(f2); + nf2->next = n->brush_faces; + n->brush_faces = nf2; + //set original + nf2->original = nf; + } + } + } + for (nf = n->brush_faces; nf; nf = nf->next) + { + Face_SetColor(n, nf, 1.0); + if (nf->face_winding) + { + if (g_qeglobals.m_bBrushPrimitMode) + EmitBrushPrimitTextureCoordinates(nf,nf->face_winding); + else + { + for (j = 0; j < nf->face_winding->numpoints; j++) + EmitTextureCoordinates(nf->face_winding->points[j], nf->d_texture, nf); + } + } + } + } + return n; +} + + // FIXME - spog - finish this later.. + /* +bool Triangle_Ray(vec3_t origin, vec3_t dir, vec3_t p1, vec3_t p2, vec3_t p3) +{ + int i; + vec3_t v1, v2, normal[3]; + float d; + + //Sys_Printf("p1: %f %f %f\n",p1[0],p1[1],p1[2]); + //Sys_Printf("p2: %f %f %f\n",p2[0],p2[1],p2[2]); + //Sys_Printf("p3: %f %f %f\n",p3[0],p3[1],p3[2]); + //Sys_Printf("origin: %f %f %f\n",origin[0],origin[1],origin[2]); + + // test ray against triangle + // get triangle plane normal + //VectorSubtract(p1, p2, v1); + //VectorSubtract(p1, p3, v2); + //CrossProduct(v1, v2, v1); + // check normal against direction + //if (DotProduct(dir, v1) >= 0) + //{ + // generate cone normals + VectorSubtract(origin, p1, v1); + VectorSubtract(origin, p2, v2); + CrossProduct(v1, v2, normal[0]); + VectorSubtract(origin, p2, v1); + VectorSubtract(origin, p3, v2); + CrossProduct(v1, v2, normal[1]); + VectorSubtract(origin, p3, v1); + VectorSubtract(origin, p1, v2); + CrossProduct(v1, v2, normal[2]); + //} + //else + //{ + // flip normals if triangle faces away + // Sys_Printf("flipped\n"); + // VectorSubtract(origin, p1, v1); + // VectorSubtract(origin, p3, v2); + // CrossProduct(v1, v2, normal[0]); + // VectorSubtract(origin, p3, v1); + // VectorSubtract(origin, p2, v2); + // CrossProduct(v1, v2, normal[1]); + // VectorSubtract(origin, p2, v1); + // VectorSubtract(origin, p1, v2); + // CrossProduct(v1, v2, normal[2]); + //} + + for (i=0; i<3; i++) + { + VectorNormalize(normal[i]); + //Sys_Printf("direction: %f %f %f\n",dir[0],dir[1],dir[2]); + //Sys_Printf("normal: %f %f %f\n",normal[i][0],normal[i][1],normal[i][2]); + d = DotProduct(dir, normal[i]); + //Sys_Printf("dotproduct: %f\n",d); + if (d < 0) + return false; + } + return true; +} +*/ + +/* +extern int Triangle_Ray(float orig[3], float dir[3], bool bCullBack, + float vert0[3], float vert1[3], float vert2[3], + double *t, double *u, double *v); + +bool Model_Ray(brush_t *b, vec3_t origin, vec3_t dir, double *t, double *u, double *v) +{ + bool bIntersect = false; + float tBest = FLT_MAX; + int i, j; + vec3_t xyz[3]; + vec3_t vRay[2]; + + float angle = FloatForKey (b->owner, "angle"); // FIXME: should be set when this entity key is set + + VectorSubtract (origin, b->owner->origin, vRay[0]); + VectorCopy (dir, vRay[1]); + + if (angle > 0) + { + int i; + float s, c; + float x, y; + + s = sin (-angle/180*Q_PI); + c = cos (-angle/180*Q_PI); + + for (i=0; i<2; i++) + { + x = vRay[i][0]; + y = vRay[i][1]; + vRay[i][0] = (x * c) - (y * s); + vRay[i][1] = (x * s) + (y * c); + } + } + + entitymodel *model = b->owner->md3Class->model; + + while (model != NULL) + { + for (i = 0; i < model->nTriCount; i++) + { + for (j = 0; j < 3; j++) + VectorCopy(model->pVertList[model->pTriList[i].indexes[j]].v, xyz[j]); + + if (Triangle_Ray(vRay[0], vRay[1], true, xyz[0], xyz[2], xyz[1], t, u, v)) + { + bIntersect = true; + if (*t < tBest) + tBest = *t; + } + } + model = model->pNext; + } + if (bIntersect) + { + *t = tBest; + return true; + } + else + { + *t = 0; + return false; + } +} +*/ + +/* +============== +Brush_Ray + +Itersects a ray with a brush +Returns the face hit and the distance along the ray the intersection occured at +Returns NULL and 0 if not hit at all + +http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=556 +============== +*/ +extern bool Patch_Ray(patchMesh_t *patch, vec3_t origin, vec3_t dir, double *t, double *u, double *v); +face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist, int nFlags) +{ + face_t *f, *firstface = NULL; + vec3_t p1, p2; + float frac, d1, d2; + int i; + + if (b->owner->eclass->fixedsize + && b->owner->model.pSelect + && !(!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY)) + && g_PrefsDlg.m_nEntityShowState != ENTITY_BOX) + { + ray_t ray_local; + vec_t dist_local = FLT_MAX; + ray_construct_for_vec3(&ray_local, origin, dir); + if (b->owner->model.pSelect->TestRay(&ray_local, &dist_local)) + { + *dist = dist_local; + return b->brush_faces; + } + else + { + *dist = 0.0f; + return NULL; + } + } + + VectorCopy (origin, p1); + for (i=0 ; i<3 ; i++) + p2[i] = p1[i] + dir[i]*2*g_MaxWorldCoord; + + for (f=b->brush_faces ; f ; f=f->next) + { + d1 = DotProduct (p1, f->plane.normal) - f->plane.dist; + d2 = DotProduct (p2, f->plane.normal) - f->plane.dist; + if (d1 >= 0 && d2 >= 0) + { + *dist = 0; + return NULL; // ray is on front side of face + } + if (d1 <=0 && d2 <= 0) + continue; + // clip the ray to the plane + frac = d1 / (d1 - d2); + if (d1 > 0) + { + firstface = f; + for (i=0 ; i<3 ; i++) + p1[i] = p1[i] + frac *(p2[i] - p1[i]); + } + else + { + for (i=0 ; i<3 ; i++) + p2[i] = p1[i] + frac *(p2[i] - p1[i]); + } + } + + // find distance p1 is along dir + VectorSubtract (p1, origin, p1); + d1 = DotProduct (p1, dir); + + *dist = d1; + + // new test stuff for patches + if (!g_PrefsDlg.m_bPatchBBoxSelect && b->patchBrush) + { + double t, u, v; // t is the distance from origin to point-of-intersection.. er.. i don't know what u and v are + if (!Patch_Ray(b->pPatch, origin, dir, &t, &u, &v)) + { + *dist = 0; + return NULL; + } + else + { + *dist = (float)t; + //Sys_Printf("t: %f, u: %f, v: %f\n", t, u, v); + } + } + + // IMPORTANT NOTE: + // modifications to the discarding code here should be matched in the selection code + // see Brush_Draw + + // do some last minute filtering + if (firstface && nFlags & SF_CAMERA) + { + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK) + { + if (strstr(firstface->texdef.GetName(), "caulk")) + { + *dist = 0; + return NULL; + } + } + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP) + { + if (strstr(firstface->texdef.GetName(), "botclip") || strstr(firstface->texdef.GetName(), "clipmonster")) + { + *dist = 0; + return NULL; + } + } + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP) + { + if (strstr(firstface->texdef.GetName(), "clip")) + { + *dist = 0; + return NULL; + } + } + } + + return firstface; +} + +//PGM +face_t *Brush_Point (vec3_t origin, brush_t *b) +{ + face_t *f; + float d1; + + for (f=b->brush_faces ; f ; f=f->next) + { + d1 = DotProduct (origin, f->plane.normal) - f->plane.dist; + if (d1 > 0) + { + return NULL; // point is on front side of face + } + } + + return b->brush_faces; +} +//PGM + + +void Brush_AddToList (brush_t *b, brush_t *blist) +{ + if (b->next || b->prev) + Error ("Brush_AddToList: already linked"); + + if (blist == &selected_brushes || blist == &active_brushes) + { + if (b->patchBrush && blist == &selected_brushes) + { + Patch_Select(b->pPatch); + } + } + b->next = blist->next; + blist->next->prev = b; + blist->next = b; + b->prev = blist; + + // TTimo messaging + DispatchRadiantMsg( RADIANT_SELECTION ); +} + +void Brush_RemoveFromList (brush_t *b) +{ + if (!b->next || !b->prev) + Error ("Brush_RemoveFromList: not linked"); + + if (b->patchBrush) + { + Patch_Deselect(b->pPatch); + } + b->next->prev = b->prev; + b->prev->next = b->next; + b->next = b->prev = NULL; +} + +/* +=============== +SetFaceTexdef + +Doesn't set the curve flags + +NOTE : ( TTimo ) + never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture + use Texture_ForName() to find the right shader + FIXME : send the right shader ( qtexture_t * ) in the parameters ? + +TTimo: surface plugin, added an IPluginTexdef* parameter + if not NULL, get ->Copy() of it into the face ( and remember to hook ) + if NULL, ask for a default + + TTimo - shader code cleanup + added IShader* parameter + =============== +*/ +void SetFaceTexdef2 (brush_t *b, face_t *f, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) { + int oldFlags; + int oldContents; + face_t *tf; + + oldFlags = f->texdef.flags; + oldContents = f->texdef.contents; + if (g_qeglobals.m_bBrushPrimitMode) + { + f->texdef = *texdef; + ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() ); + } + else + if (bFitScale) + { + f->texdef = *texdef; + // fit the scaling of the texture on the actual plane + vec3_t p1,p2,p3; // absolute coordinates + // compute absolute coordinates + ComputeAbsolute(f,p1,p2,p3); + // compute the scale + vec3_t vx,vy; + VectorSubtract(p2,p1,vx); + VectorNormalize(vx, vx); + VectorSubtract(p3,p1,vy); + VectorNormalize(vy, vy); + // assign scale + VectorScale(vx,texdef->scale[0],vx); + VectorScale(vy,texdef->scale[1],vy); + VectorAdd(p1,vx,p2); + VectorAdd(p1,vy,p3); + // compute back shift scale rot + AbsoluteToLocal(f->plane,f,p1,p2,p3); + } + else + f->texdef = *texdef; + f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP); + f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP); + + // if this is a curve face, set all other curve faces to the same texdef + if (f->texdef.flags & SURF_CURVE) + { + for (tf = b->brush_faces ; tf ; tf = tf->next) + { + if (tf->texdef.flags & SURF_CURVE) + tf->texdef = f->texdef; + } + } +} + +/* +=============== +SetFaceTexdef + +Doesn't set the curve flags + +NOTE : ( TTimo ) + never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture + use Texture_ForName() to find the right shader + FIXME : send the right shader ( qtexture_t * ) in the parameters ? + + TTimo: surface plugin, added an IPluginTexdef* parameter + if not NULL, get ->Copy() of it into the face ( and remember to hook ) + if NULL, ask for a default +=============== +*/ +void SetFaceTexdef (face_t *f, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) { + int oldFlags; + int oldContents; + + oldFlags = f->texdef.flags; + oldContents = f->texdef.contents; + + if(strcmp(f->texdef.GetName(), texdef->GetName()) != 0) // set shader here instead of Brush_Build + Face_SetShader(f, texdef->GetName()); + + if (g_qeglobals.m_bBrushPrimitMode) + { + f->texdef = *texdef; + ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() ); + } + else + { + if (bFitScale) + { + f->texdef = *texdef; + // fit the scaling of the texture on the actual plane + vec3_t p1,p2,p3; // absolute coordinates + // compute absolute coordinates + ComputeAbsolute(f,p1,p2,p3); + // compute the scale + vec3_t vx,vy; + VectorSubtract(p2,p1,vx); + VectorNormalize(vx, vx); + VectorSubtract(p3,p1,vy); + VectorNormalize(vy, vy); + // assign scale + VectorScale(vx,texdef->scale[0],vx); + VectorScale(vy,texdef->scale[1],vy); + VectorAdd(p1,vx,p2); + VectorAdd(p1,vy,p3); + // compute back shift scale rot + AbsoluteToLocal(f->plane,f,p1,p2,p3); + } + else + { + f->texdef = *texdef; + } + } + f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP); + f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP); +} + +#ifdef _DEBUG +void Brush_SetTexture2 (brush_t *b, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef) +{ + for (face_t* f = b->brush_faces ; f ; f = f->next) + SetFaceTexdef2 (b, f, pShader, texdef, brushprimit_texdef, bFitScale, pTexdef); + Brush_Build( b ); + if (b->patchBrush) + { + Patch_SetTexture(b->pPatch, texdef, pTexdef ); + b->bFiltered = FilterBrush( b ); + } +} +#endif + +void Brush_SetTexture (brush_t *b, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef) +{ + for (face_t* f = b->brush_faces ; f ; f = f->next) + SetFaceTexdef (f, texdef, brushprimit_texdef, bFitScale, pTexdef); + Brush_Build( b ); + if (b->patchBrush) + { + Patch_SetTexture(b->pPatch, texdef, pTexdef ); + b->bFiltered = FilterBrush( b ); + } +} + + +qboolean ClipLineToFace (vec3_t p1, vec3_t p2, face_t *f) +{ + float d1, d2, fr; + int i; + float *v; + + d1 = DotProduct (p1, f->plane.normal) - f->plane.dist; + d2 = DotProduct (p2, f->plane.normal) - f->plane.dist; + + if (d1 >= 0 && d2 >= 0) + return false; // totally outside + if (d1 <= 0 && d2 <= 0) + return true; // totally inside + + fr = d1 / (d1 - d2); + + if (d1 > 0) + v = p1; + else + v = p2; + + for (i=0 ; i<3 ; i++) + v[i] = p1[i] + fr*(p2[i] - p1[i]); + + return true; +} + + +int AddPlanept (float *f) +{ + int i; + + for (i=0 ; iowner->eclass->fixedsize) + return; + + c = 0; + for (i=0 ; i<3 ; i++) + c += AddPlanept (f->planepts[i]); + if (c == 0) + return; // already completely added + + // select all points on this plane in all brushes the selection + for (b2=selected_brushes.next ; b2 != &selected_brushes ; b2 = b2->next) + { + if (b2 == b) + continue; + for (f2=b2->brush_faces ; f2 ; f2=f2->next) + { + for (i=0 ; i<3 ; i++) + if (fabs(DotProduct(f2->planepts[i], f->plane.normal) + -f->plane.dist) > ON_EPSILON) + break; + if (i==3) + { // move this face as well + Brush_SelectFaceForDragging (b2, f2, shear); + break; + } + } + } + + + // if shearing, take all the planes adjacent to + // selected faces and rotate their points so the + // edge clipped by a selcted face has two of the points + if (!shear) + return; + + for (f2=b->brush_faces ; f2 ; f2=f2->next) + { + if (f2 == f) + continue; + w = Brush_MakeFaceWinding (b, f2); + if (!w) + continue; + + // any points on f will become new control points + for (i=0 ; inumpoints ; i++) + { + d = DotProduct (w->points[i], f->plane.normal) + - f->plane.dist; + if (d > -ON_EPSILON && d < ON_EPSILON) + break; + } + + // + // if none of the points were on the plane, + // leave it alone + // + if (i != w->numpoints) + { + if (i == 0) + { // see if the first clockwise point was the + // last point on the winding + d = DotProduct (w->points[w->numpoints-1] + , f->plane.normal) - f->plane.dist; + if (d > -ON_EPSILON && d < ON_EPSILON) + i = w->numpoints - 1; + } + + AddPlanept (f2->planepts[0]); + + VectorCopy (w->points[i], f2->planepts[0]); + if (++i == w->numpoints) + i = 0; + + // see if the next point is also on the plane + d = DotProduct (w->points[i] + , f->plane.normal) - f->plane.dist; + if (d > -ON_EPSILON && d < ON_EPSILON) + AddPlanept (f2->planepts[1]); + + VectorCopy (w->points[i], f2->planepts[1]); + if (++i == w->numpoints) + i = 0; + + // the third point is never on the plane + + VectorCopy (w->points[i], f2->planepts[2]); + } + + free(w); + } +} + +/* +============== +Brush_SideSelect + +The mouse click did not hit the brush, so grab one or more side +planes for dragging +============== +*/ +void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir + , qboolean shear) +{ + face_t *f, *f2; + vec3_t p1, p2; + + for (f=b->brush_faces ; f ; f=f->next) + { + VectorCopy (origin, p1); + VectorMA (origin, 2*g_MaxWorldCoord, dir, p2); + + for (f2=b->brush_faces ; f2 ; f2=f2->next) + { + if (f2 == f) + continue; + ClipLineToFace (p1, p2, f2); + } + + if (f2) + continue; + + if (VectorCompare (p1, origin)) + continue; + if (ClipLineToFace (p1, p2, f)) + continue; + + Brush_SelectFaceForDragging (b, f, shear); + } +} + +bool g_bBuildWindingsNoTexBuild = false; + +void Brush_SetBuildWindingsNoTexBuild(bool bBuild) +{ + g_bBuildWindingsNoTexBuild = bBuild; +} + +// TTimo: don't rebuild pShader and d_texture if it doesn't seem necessary +// saves quite a lot of time, but on the other hand we've gotta make sure we clean the d_texture in some cases +// ie when we want to update a shader +// default will make Radiant rebuild the texture, but it can be turned off by setting the flag g_bBuildWindingsNoTexBuild +void Brush_BuildWindings( brush_t *b, bool bSnap ) +{ + winding_t *w; + face_t *face; + vec_t v; + + if (bSnap) + Brush_SnapPlanepts( b ); + + // clear the mins/maxs bounds + b->mins[0] = b->mins[1] = b->mins[2] = 99999; + b->maxs[0] = b->maxs[1] = b->maxs[2] = -99999; + + Brush_MakeFacePlanes (b); + + face = b->brush_faces; + + float fCurveColor = 1.0; + + for ( ; face ; face=face->next) + { + int i, j; + free(face->face_winding); + w = face->face_winding = Brush_MakeFaceWinding (b, face); + + if (!g_bBuildWindingsNoTexBuild || !face->d_texture) + { +#ifdef _DEBUG + // if there's no d_texture, then we expect pShader to be empty + if (!face->d_texture && face->pShader) + Sys_FPrintf(SYS_ERR, "ERROR: unexpected face->pShader != NULL with face->d_texture == NULL in Brush_BuildWindings\n"); +#endif + if ((!face->d_texture && !face->pShader) || !face->pShader) + { + // NOTE TTimo + // patch 84 for bug 253 doesn't dec ref the potential face->pShader + // add a debug check to make sure this is actually not necessary +#ifdef _DEBUG + if (face->pShader) + { + Sys_FPrintf(SYS_ERR, "ERROR: face->pShader != NULL in Brush_BuildWindings\n"); + } +#endif + face->pShader = QERApp_Shader_ForName( face->texdef.GetName() ); + face->pShader->IncRef(); + face->d_texture = face->pShader->getTexture(); + } + } + + if (!w) + continue; + + for (i=0 ; inumpoints ; i++) + { + // add to bounding box + for (j=0 ; j<3 ; j++) + { + v = w->points[i][j]; + if (v > b->maxs[j]) + b->maxs[j] = v; + if (v < b->mins[j]) + b->mins[j] = v; + } + } + Face_SetColor (b, face, fCurveColor); + + fCurveColor -= .10f; + if (fCurveColor <= 0) + fCurveColor = 1.0f; + + // computing ST coordinates for the windings + if (g_qeglobals.m_bBrushPrimitMode) + { + if (g_qeglobals.bNeedConvert) + { + // we have parsed old brushes format and need conversion + // convert old brush texture representation to new format + FaceToBrushPrimitFace(face); +#ifdef _DEBUG + // use old texture coordinates code to check against + for (i=0 ; inumpoints ; i++) + EmitTextureCoordinates( w->points[i], face->d_texture, face); +#endif + } + // use new texture representation to compute texture coordinates + // in debug mode we will check against old code and warn if there are differences + EmitBrushPrimitTextureCoordinates(face,w); + } + else + { + if (g_qeglobals.bNeedConvert) + { + BrushPrimitFaceToFace(face); +/* + // we have parsed brush primitives and need conversion back to standard format + // NOTE: converting back is a quick hack, there's some information lost and we can't do anything about it + // FIXME: if we normalize the texture matrix to a standard 2x2 size, we end up with wrong scaling + // I tried various tweaks, no luck .. seems shifting is lost + brushprimit_texdef_t aux; + ConvertTexMatWithQTexture( &face->brushprimit_texdef, face->d_texture, &aux, NULL ); + TexMatToFakeTexCoords( aux.coords, face->texdef.shift, &face->texdef.rotate, face->texdef.scale ); + face->texdef.scale[0]/=2.0; + face->texdef.scale[1]/=2.0; +*/ + } + for (i=0 ; inumpoints ; i++) + EmitTextureCoordinates( w->points[i], face->d_texture, face); + } + } +} + +/* +================== +Brush_RemoveEmptyFaces + +Frees any overconstraining faces +================== +*/ +void Brush_RemoveEmptyFaces ( brush_t *b ) +{ + face_t *f, *next; + + f = b->brush_faces; + b->brush_faces = NULL; + + for ( ; f ; f=next) + { + next = f->next; + if (!f->face_winding) + Face_Free (f); + else + { + f->next = b->brush_faces; + b->brush_faces = f; + } + + } +} + +void Brush_SnapToGrid(brush_t *pb) +{ + face_t *f; + vec3_t temp; + vec3_t diff[2]; + int mult[3]; + int i, j, n; + // TTimo: some brushes are "special" and should not be snapped + // specially fixed-size entity ones + if (pb->owner->eclass->fixedsize) + { + // save current origin + VectorCopy (pb->owner->origin, temp); + // snap the origin + VectorFSnap(pb->owner->origin, g_qeglobals.d_gridsize); + // return if amount is zero + if (VectorCompare (pb->owner->origin, temp)) + return; + // transform brush faces same amount + VectorSubtract (pb->owner->origin, temp, temp); + for (f = pb->brush_faces; f; f = f->next) + { + for (i=0 ; i<3 ; i++) + VectorAdd (f->planepts[i], temp, f->planepts[i]); + } + } + else + { + for (f = pb->brush_faces ; f; f = f->next) + { + for (j=0; j<2; j++) + { + // spog - move planepts apart just far enough to avoid snapping two together + VectorSubtract (f->planepts[j+1], f->planepts[j], diff[j]); + for (i=0; i<3; i++) + { + if (diff[j][i] == 0.0f) + mult[i] = 2; // next value up from 1 + else // multiplier = gridsize / component difference, rounded up + mult[i] = (int)ceil(fabs(g_qeglobals.d_gridsize / diff[j][i])); + } + + if (mult[0] > 1 && mult[1] > 1 && mult[2] > 1) // if all multipliers are greater than 1 + { + n = (mult[0] >= mult[1] && mult[0] >= mult[2]) ? 0 : (mult[1] >= mult[0] && mult[1] >= mult[2]) ? 1 : 2; + for (i=0; i<3; i++) + diff[j][i] *= mult[n]; // multiply difference by multiplier of smallest component + } + VectorAdd (f->planepts[j], diff[j], f->planepts[j+1]); + } + + for (i=0; i<3; i++) + VectorFSnap(f->planepts[i], g_qeglobals.d_gridsize); + + } + } + Brush_Build(pb,true,true,false,false); // don't filter +} + +void Brush_Rotate(brush_t *b, vec3_t vAngle, vec3_t vOrigin, bool bBuild) +{ + for (face_t* f=b->brush_faces ; f ; f=f->next) + { + for (int i=0 ; i<3 ; i++) + { + VectorRotateOrigin (f->planepts[i], vAngle, vOrigin, f->planepts[i]); + } + } + if (bBuild) + { + Brush_Build(b,false,false,false,false); // don't filter + } +} + +void Brush_Center(brush_t *b, vec3_t vNewCenter) +{ + vec3_t vMid; + // get center of the brush + for (int j = 0; j < 3; j++) + { + vMid[j] = b->mins[j] + fabs((b->maxs[j] - b->mins[j]) * 0.5); + } + // calc distance between centers + VectorSubtract(vNewCenter, vMid, vMid); + Brush_Move(b, vMid, true); + +} + +void Brush_Resize(brush_t *b, vec3_t vMin, vec3_t vMax) +{ + face_t *f; + texdef_t texdef; + int i; + short box[3][2] = { { 0, 1 }, { 2, 0 }, { 1, 2 } }; + + for (i=0 ; i<3 ; i++) + if (vMax[i] < vMin[i]) + Error ("Brush_Resize: invalid input"); + + if(b->brush_faces != NULL) + texdef = b->brush_faces->texdef; + else + texdef = g_qeglobals.d_texturewin.texdef; + + while (b->brush_faces != NULL) + { + f = b->brush_faces->next; + Face_Free(b->brush_faces); + b->brush_faces = f; + } + + for(i=0; i<3; i++) + { + f = b->brush_faces; + b->brush_faces = Face_Alloc(); + b->brush_faces->next = f; + f = b->brush_faces; + f->texdef = texdef; + VectorCopy(vMax, f->planepts[0]); + VectorCopy(vMax, f->planepts[1]); + VectorCopy(vMax, f->planepts[2]); + f->planepts[2][box[i][0]] = vMin[box[i][0]]; + f->planepts[1][box[i][1]] = vMin[box[i][1]]; + } + for(i=0; i<3; i++) + { + f = b->brush_faces; + b->brush_faces = Face_Alloc(); + b->brush_faces->next = f; + f = b->brush_faces; + f->texdef = texdef; + VectorCopy(vMin, f->planepts[0]); + VectorCopy(vMin, f->planepts[1]); + VectorCopy(vMin, f->planepts[2]); + f->planepts[1][box[i][0]] = vMax[box[i][0]]; + f->planepts[2][box[i][1]] = vMax[box[i][1]]; + } +} + +void FacingVectors (entity_t *e, vec3_t forward, vec3_t right, vec3_t up) +{ + int angleVal; + vec3_t angles; + + angleVal = IntForKey(e, "angle"); + if (angleVal == -1) // up + { + VectorSet(angles, 270, 0, 0); + } + else if(angleVal == -2) // down + { + VectorSet(angles, 90, 0, 0); + } + else + { + VectorSet(angles, 0, angleVal, 0); + } + + AngleVectors(angles, forward, right, up); +} + +void Brush_DrawFacingAngle (brush_t *b, entity_t *e) +{ + vec3_t forward, right, up; + vec3_t endpoint, tip1, tip2; + vec3_t start; + float dist; + + VectorAdd(e->brushes.onext->mins, e->brushes.onext->maxs, start); + VectorScale(start, 0.5, start); + dist = (b->maxs[0] - start[0]) * 2.5; + + FacingVectors (e, forward, right, up); + VectorMA (start, dist, forward, endpoint); + + dist = (b->maxs[0] - start[0]) * 0.5; + VectorMA (endpoint, -dist, forward, tip1); + VectorMA (tip1, -dist, up, tip1); + VectorMA (tip1, 2*dist, up, tip2); + + qglColor4f (1, 1, 1, 1); + qglLineWidth (4); + qglBegin (GL_LINES); + qglVertex3fv (start); + qglVertex3fv (endpoint); + qglVertex3fv (endpoint); + qglVertex3fv (tip1); + qglVertex3fv (endpoint); + qglVertex3fv (tip2); + qglEnd (); + qglLineWidth (1); +} + +void Brush_FaceDraw(face_t *face, int nGLState) +{ + const winding_t *w = face->face_winding; + if (w == NULL) return; + if (nGLState & DRAW_GL_LIGHTING && g_PrefsDlg.m_bGLLighting) + qglNormal3fv(face->plane.normal); + /* + if (mode & DRAW_GL_TEXTURE_2D) + qglTexCoordPointer(2, GL_FLOAT, 5, &w->points[3]); + qglVertexPointer(3, GL_FLOAT, 5, w->points); + + if (mode & DRAW_GL_FILL) + qglDrawArrays(GL_TRIANGLE_FAN, 0, w->numpoints); + else + qglDrawArrays(GL_POLYGON, 0, w->numpoints); + */ + + if (nGLState & DRAW_GL_FILL) + qglBegin(GL_TRIANGLE_FAN); + else + qglBegin(GL_POLYGON); + + for (int i=0 ; inumpoints ; i++) + { + if (nGLState & DRAW_GL_TEXTURE_2D) + qglTexCoord2fv( &w->points[i][3] ); + qglVertex3fv(w->points[i]); + } + qglEnd(); +} + +void Brush_Draw(brush_t *b) +{ + face_t *face; + int order; + qtexture_t *prev = 0; + winding_t *w; + + int nDrawMode = g_pParentWnd->GetCamWnd()->Camera()->draw_mode; + int nGLState = g_pParentWnd->GetCamWnd()->Camera()->draw_glstate; + + GLfloat material[4], identity[4]; + VectorSet(identity, 0.8f, 0.8f, 0.8f); + IShader *pShader; + qglPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); + qglDisableClientState(GL_NORMAL_ARRAY); + + // guarantee the texture will be set first + bool bTrans; + prev = NULL; + for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++) + { + w = face->face_winding; + if (!w) + { + continue; // freed face + } + + bTrans = (face->pShader->getFlags() & QER_TRANS); + + if (bTrans && !(nGLState & DRAW_GL_BLEND)) + continue; + if (!bTrans && nGLState & DRAW_GL_BLEND) + continue; + + // IMPORTANT NOTE: + // modifications to the discarding code here should be matched in the selection code + // see Brush_Ray + + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK) + { + if (strstr(face->texdef.GetName(), "caulk")) + continue; + } + + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP) + { + if (strstr(face->texdef.GetName(), "botclip") || strstr(face->texdef.GetName(), "clipmonster")) + continue; + } + + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP) + { + if (strstr(face->texdef.GetName(), "clip")) + continue; + } + + if (nGLState & DRAW_GL_TEXTURE_2D && face->d_texture->name[0] == '(') + { + prev = NULL; + qglDisable(GL_TEXTURE_2D); + } + else if (nGLState & DRAW_GL_TEXTURE_2D && (nDrawMode == cd_texture || nDrawMode == cd_light) && face->d_texture != prev) + { + // set the texture for this face + prev = face->d_texture; + qglBindTexture( GL_TEXTURE_2D, face->d_texture->texture_number ); + } + + if (nGLState & DRAW_GL_LIGHTING && !g_PrefsDlg.m_bGLLighting) + { + if (!b->owner->eclass->fixedsize) + material[3] = face->pShader->getTrans(); + else + material[3] = 1; + VectorCopy(face->d_color, material); + + if (nGLState & DRAW_GL_TEXTURE_2D) + qglColor4f(face->d_shade, face->d_shade, face->d_shade, material[3]); + else + qglColor4fv(material); + } + else if (!b->owner->eclass->fixedsize) + { + pShader = face->pShader; + VectorCopy(pShader->getTexture()->color, material); + material[3] = identity[3] = pShader->getTrans(); + + if (nGLState & DRAW_GL_TEXTURE_2D) + qglColor4fv(identity); + else + qglColor4fv(material); + } + + // draw the polygon + + Brush_FaceDraw(face, nGLState); + } + qglPopClientAttrib(); +} + +void Face_Draw( face_t *f ) +{ + int i; + + if ( f->face_winding == 0 ) + return; + qglBegin(GL_POLYGON); + for ( i = 0 ; i < f->face_winding->numpoints; i++) + qglVertex3fv( f->face_winding->points[i] ); + qglEnd(); +} + +entity_t *FindEntity(const char *pszKey, const char *pszValue) +{ + entity_t *pe; + + pe = entities.next; + + for (; pe != NULL && pe != &entities ; pe = pe->next) + { + if (!strcmp(ValueForKey(pe, pszKey), pszValue)) + return pe; + } + + return NULL; +} + +void Brush_DrawXY(brush_t *b, int nViewType) +{ + face_t *face; + int order; + winding_t *w; + int i; + + if (b->patchBrush) + { + Patch_DrawXY(b->pPatch); + if (!g_bPatchShowBounds) + return; + } + + if (b->owner->eclass->fixedsize) + { + if (g_PrefsDlg.m_bNewLightDraw && (b->owner->eclass->nShowFlags & ECLASS_LIGHT)) + { +#if 1 // requires vertex arrays enabled + DrawLight(b->owner, DRAW_GL_WIRE, (IsBrushSelected(b)) ? g_PrefsDlg.m_nLightRadiuses : 0, nViewType); +#else + vec3_t vCorners[4]; + float fMid = b->mins[2] + (b->maxs[2] - b->mins[2]) / 2; + + vCorners[0][0] = b->mins[0]; + vCorners[0][1] = b->mins[1]; + vCorners[0][2] = fMid; + + vCorners[1][0] = b->mins[0]; + vCorners[1][1] = b->maxs[1]; + vCorners[1][2] = fMid; + + vCorners[2][0] = b->maxs[0]; + vCorners[2][1] = b->maxs[1]; + vCorners[2][2] = fMid; + + vCorners[3][0] = b->maxs[0]; + vCorners[3][1] = b->mins[1]; + vCorners[3][2] = fMid; + + vec3_t vTop, vBottom; + + vTop[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) / 2); + vTop[1] = b->mins[1] + ((b->maxs[1] - b->mins[1]) / 2); + vTop[2] = b->maxs[2]; + + VectorCopy(vTop, vBottom); + vBottom[2] = b->mins[2]; + + qglBegin(GL_LINES); + qglVertex3fv(vTop); + qglVertex3fv(vCorners[0]); + qglVertex3fv(vTop); + qglVertex3fv(vCorners[1]); + qglVertex3fv(vTop); + qglVertex3fv(vCorners[2]); + qglVertex3fv(vTop); + qglVertex3fv(vCorners[3]); + qglEnd(); + + qglBegin(GL_LINES); + qglVertex3fv(vBottom); + qglVertex3fv(vCorners[0]); + qglVertex3fv(vBottom); + qglVertex3fv(vCorners[1]); + qglVertex3fv(vBottom); + qglVertex3fv(vCorners[2]); + qglVertex3fv(vBottom); + qglVertex3fv(vCorners[3]); + qglEnd(); + + qglBegin(GL_LINE_LOOP); + qglVertex3fv(vCorners[0]); + qglVertex3fv(vCorners[1]); + qglVertex3fv(vCorners[2]); + qglVertex3fv(vCorners[3]); + qglEnd(); +#endif + DrawBrushEntityName (b); + return; + } + else if (b->owner->model.pRender && !(!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY))) + { + qglPushAttrib(GL_CURRENT_BIT); // save brush colour + qglColor3fv(b->owner->eclass->color); + if( g_PrefsDlg.m_nEntityShowState != ENTITY_BOX ) + b->owner->model.pRender->Draw(DRAW_GL_WIRE, DRAW_RF_XY); + aabb_draw(b->owner->model.pRender->GetAABB(), DRAW_GL_WIRE); + qglPopAttrib(); + return; + } + //} + } + + for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++) + { + // moved so check occurs earlier + w = face->face_winding; + if (!w) + continue; + // only draw polygons facing in a direction we care about + if (nViewType == XY) + { + if (face->plane.normal[2] <= 0) + continue; + } + else + { + if (nViewType == XZ) + { + if (face->plane.normal[1] >= 0) // stop axes being mirrored + continue; + } + else + { + if (face->plane.normal[0] <= 0) + continue; + } + } + + // draw the polygon + qglBegin(GL_LINE_LOOP); + for (i=0 ; inumpoints ; i++) + qglVertex3fv(w->points[i]); + qglEnd(); + } + + DrawBrushEntityName (b); + +} + +/* +============ +Brush_Move +============ +*/ +void Brush_Move (brush_t *b, const vec3_t move, bool bSnap) +{ + int i; + face_t *f; + + for (f=b->brush_faces ; f ; f=f->next) + for (i=0 ; i<3 ; i++) + VectorAdd (f->planepts[i], move, f->planepts[i]); + + if (g_PrefsDlg.m_bTextureLock && !b->owner->eclass->fixedsize) + { + for (f=b->brush_faces ; f ; f=f->next) + { + vec3_t vTemp; + VectorCopy(move, vTemp); + Face_MoveTexture(f, vTemp); + } + } + + Brush_Build( b, bSnap,true,false,false); // don't filter + + + if (b->patchBrush) + { + //Patch_Move(b->nPatchID, move); + Patch_Move(b->pPatch, move); + } + + + // PGM - keep the origin vector up to date on fixed size entities. + if(b->owner->eclass->fixedsize) + { + char text[64]; + VectorAdd(b->owner->origin, move, b->owner->origin); + sprintf (text, "%i %i %i", + (int)b->owner->origin[0], (int)b->owner->origin[1], (int)b->owner->origin[2]); + SetKeyValue(b->owner, "origin", text); + //VectorAdd(b->maxs, b->mins, b->owner->origin); + //VectorScale(b->owner->origin, 0.5, b->owner->origin); + } +} + + + +void Brush_Print(brush_t* b) +{ + int nFace = 0; + for (face_t* f = b->brush_faces ; f ; f=f->next) + { + Sys_Printf("Face %i\n", nFace++); + Sys_Printf("%f %f %f\n", f->planepts[0][0], f->planepts[0][1], f->planepts[0][2]); + Sys_Printf("%f %f %f\n", f->planepts[1][0], f->planepts[1][1], f->planepts[1][2]); + Sys_Printf("%f %f %f\n", f->planepts[2][0], f->planepts[2][1], f->planepts[2][2]); + } + } + + + +/* +============= +Brush_MakeSided + +Makes the current brushhave the given number of 2d sides and turns it into a cone +============= +*/ +void Brush_MakeSidedCone(int sides) +{ + int i; + vec3_t mins, maxs; + brush_t *b; + texdef_t *texdef; + face_t *f; + vec3_t mid; + float width; + float sv, cv; + + if (sides < 3 || sides > 32) + { + Sys_Status ("Bad sides number", 0); + return; + } + + if (!QE_SingleBrush ()) + { + Sys_Status ("Must have a single brush selected", 0 ); + return; + } + + b = selected_brushes.next; + VectorCopy (b->mins, mins); + VectorCopy (b->maxs, maxs); + texdef = &g_qeglobals.d_texturewin.texdef; + + Brush_Free (b); + + // find center of brush + width = 8; + for (i=0 ; i<2 ; i++) + { + mid[i] = (maxs[i] + mins[i])*0.5; + if (maxs[i] - mins[i] > width) + width = maxs[i] - mins[i]; + } + width /= 2; + + b = Brush_Alloc(); + + // create bottom face + f = Face_Alloc(); + f->texdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + + f->planepts[0][0] = mins[0];f->planepts[0][1] = mins[1];f->planepts[0][2] = mins[2]; + f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = mins[2]; + f->planepts[2][0] = maxs[0];f->planepts[2][1] = maxs[1];f->planepts[2][2] = mins[2]; + + for (i=0 ; itexdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + + sv = sin (i*3.14159265*2/sides); + cv = cos (i*3.14159265*2/sides); + + + f->planepts[0][0] = floor(mid[0]+width*cv+0.5); + f->planepts[0][1] = floor(mid[1]+width*sv+0.5); + f->planepts[0][2] = mins[2]; + + f->planepts[1][0] = mid[0]; + f->planepts[1][1] = mid[1]; + f->planepts[1][2] = maxs[2]; + + f->planepts[2][0] = floor(f->planepts[0][0] - width * sv + 0.5); + f->planepts[2][1] = floor(f->planepts[0][1] + width * cv + 0.5); + f->planepts[2][2] = maxs[2]; + + } + + Brush_AddToList (b, &selected_brushes); + + Entity_LinkBrush (world_entity, b); + + Brush_Build( b ); + + Sys_UpdateWindows (W_ALL); +} + +/* +============= +Brush_MakeSided + +Makes the current brushhave the given number of 2d sides and turns it into a sphere +============= + +*/ +void Brush_MakeSidedSphere(int sides) +{ + int i,j; + vec3_t mins, maxs; + brush_t *b; + texdef_t *texdef; + face_t *f; + vec3_t mid; + + if (sides < 4 || sides > 32) + { + Sys_Status ("Bad sides number", 0); + return; + } + + if (!QE_SingleBrush ()) + { + Sys_Status ("Must have a single brush selected", 0 ); + return; + } + + b = selected_brushes.next; + VectorCopy (b->mins, mins); + VectorCopy (b->maxs, maxs); + texdef = &g_qeglobals.d_texturewin.texdef; + + Brush_Free (b); + + // find center of brush + float radius = 8; + for (i=0 ; i<2 ; i++) + { + mid[i] = (maxs[i] + mins[i])*0.5; + if (maxs[i] - mins[i] > radius) + radius = maxs[i] - mins[i]; + } + radius /= 2; + + b = Brush_Alloc(); + + float dt = float(2 * Q_PI / sides); + float dp = float(Q_PI / sides); + float t,p; + for(i=0; i <= sides-1; i++) + { + for(j=0;j <= sides-2; j++) + { + t = i * dt; + p = float(j * dp - Q_PI / 2); + + f = Face_Alloc(); + f->texdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + + VectorPolar(f->planepts[0], radius, t, p); + VectorPolar(f->planepts[1], radius, t, p + dp); + VectorPolar(f->planepts[2], radius, t + dt, p + dp); + + for (int k = 0; k < 3; k++) + VectorAdd(f->planepts[k], mid, f->planepts[k]); + } + } + + p = float((sides - 1) * dp - Q_PI / 2); + for(i = 0; i <= sides-1; i++) + { + t = i * dt; + + f = Face_Alloc(); + f->texdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + + VectorPolar(f->planepts[0], radius, t, p); + VectorPolar(f->planepts[1], radius, t + dt, p + dp); + VectorPolar(f->planepts[2], radius, t + dt, p); + + for (int k = 0; k < 3; k++) + VectorAdd(f->planepts[k], mid, f->planepts[k]); + } + + Brush_AddToList (b, &selected_brushes); + + Entity_LinkBrush (world_entity, b); + + Brush_Build( b ); + + Sys_UpdateWindows (W_ALL); +} + +void Face_FitTexture( face_t * face, int nHeight, int nWidth ) +{ + winding_t *w; + vec3_t mins,maxs; + int i; + float width, height, temp; + float rot_width, rot_height; + float cosv,sinv,ang; + float min_t, min_s, max_t, max_s; + float s,t; + vec3_t vecs[2]; + vec3_t coords[4]; + texdef_t *td; + + if (nHeight < 1) + nHeight = 1; + if (nWidth < 1) + nWidth = 1; + + ClearBounds (mins, maxs); + + w = face->face_winding; + if (!w) + { + return; + } + for (i=0 ; inumpoints ; i++) + { + AddPointToBounds( w->points[i], mins, maxs ); + } + + if (g_qeglobals.m_bBrushPrimitMode) + Face_FitTexture_BrushPrimit( face, mins, maxs, nHeight, nWidth ); + else + { + + td = &face->texdef; + // + // get the current angle + // + ang = td->rotate / 180 * Q_PI; + sinv = sin(ang); + cosv = cos(ang); + + // get natural texture axis + TextureAxisFromPlane(&face->plane, vecs[0], vecs[1]); + + min_s = DotProduct( mins, vecs[0] ); + min_t = DotProduct( mins, vecs[1] ); + max_s = DotProduct( maxs, vecs[0] ); + max_t = DotProduct( maxs, vecs[1] ); + width = max_s - min_s; + height = max_t - min_t; + coords[0][0] = min_s; + coords[0][1] = min_t; + coords[1][0] = max_s; + coords[1][1] = min_t; + coords[2][0] = min_s; + coords[2][1] = max_t; + coords[3][0] = max_s; + coords[3][1] = max_t; + min_s = min_t = 99999; + max_s = max_t = -99999; + for (i=0; i<4; i++) + { + s = cosv * coords[i][0] - sinv * coords[i][1]; + t = sinv * coords[i][0] + cosv * coords[i][1]; + if (i&1) + { + if (s > max_s) + { + max_s = s; + } + } + else + { + if (s < min_s) + { + min_s = s; + } + if (i<2) + { + if (t < min_t) + { + min_t = t; + } + } + else + { + if (t > max_t) + { + max_t = t; + } + } + } + } + rot_width = (max_s - min_s); + rot_height = (max_t - min_t); + td->scale[0] = -(rot_width/((float)(face->d_texture->width*nWidth))); + td->scale[1] = -(rot_height/((float)(face->d_texture->height*nHeight))); + + td->shift[0] = min_s/td->scale[0]; + temp = (int)(td->shift[0] / (face->d_texture->width*nWidth)); + temp = (temp+1)*face->d_texture->width*nWidth; + td->shift[0] = (int)(temp - td->shift[0])%(face->d_texture->width*nWidth); + + td->shift[1] = min_t/td->scale[1]; + temp = (int)(td->shift[1] / (face->d_texture->height*nHeight)); + temp = (temp+1)*(face->d_texture->height*nHeight); + td->shift[1] = (int)(temp - td->shift[1])%(face->d_texture->height*nHeight); + + td->shift[1] = min_t/td->scale[1]; + temp = (int)(td->shift[1] / (face->d_texture->height*nHeight)); + temp = (temp+1)*(face->d_texture->height*nHeight); + td->shift[1] = (int)(temp - td->shift[1])%(face->d_texture->height*nHeight); + + } +} + +void Brush_FitTexture( brush_t *b, int nHeight, int nWidth ) +{ + face_t *face; + + for (face = b->brush_faces ; face ; face=face->next) + { + Face_FitTexture( face, nHeight, nWidth ); + } +} + +void aabb_draw(const aabb_t *aabb, int mode) +{ + vec3_t normals[6] = { { 1, 0, 0}, { 0, 1, 0 }, { 0, 0, 1 }, {-1, 0, 0}, { 0,-1, 0 }, { 0, 0,-1 } }; + vec3_t points[8]; + vec3_t vMin, vMax; + VectorSubtract(aabb->origin, aabb->extents, vMin); + VectorAdd(aabb->origin, aabb->extents, vMax); + VectorSet(points[0], vMin[0], vMax[1], vMax[2]); + VectorSet(points[1], vMax[0], vMax[1], vMax[2]); + VectorSet(points[2], vMax[0], vMin[1], vMax[2]); + VectorSet(points[3], vMin[0], vMin[1], vMax[2]); + VectorSet(points[4], vMin[0], vMax[1], vMin[2]); + VectorSet(points[5], vMax[0], vMax[1], vMin[2]); + VectorSet(points[6], vMax[0], vMin[1], vMin[2]); + VectorSet(points[7], vMin[0], vMin[1], vMin[2]); + + qglBegin(GL_QUADS); + + qglNormal3fv(normals[0]); + qglVertex3fv(points[2]); + qglVertex3fv(points[1]); + qglVertex3fv(points[5]); + qglVertex3fv(points[6]); + + qglNormal3fv(normals[1]); + qglVertex3fv(points[1]); + qglVertex3fv(points[0]); + qglVertex3fv(points[4]); + qglVertex3fv(points[5]); + + qglNormal3fv(normals[2]); + qglVertex3fv(points[0]); + qglVertex3fv(points[1]); + qglVertex3fv(points[2]); + qglVertex3fv(points[3]); + + qglNormal3fv(normals[3]); + qglVertex3fv(points[3]); + qglVertex3fv(points[7]); + qglVertex3fv(points[4]); + qglVertex3fv(points[0]); + + qglNormal3fv(normals[4]); + qglVertex3fv(points[3]); + qglVertex3fv(points[2]); + qglVertex3fv(points[6]); + qglVertex3fv(points[7]); + + qglNormal3fv(normals[5]); + qglVertex3fv(points[7]); + qglVertex3fv(points[6]); + qglVertex3fv(points[5]); + qglVertex3fv(points[4]); + + qglEnd(); + +/* + + + vec3_t Coords[8]; + + vec3_t vMin, vMax; + VectorSubtract(aabb->origin, aabb->extents, vMin); + VectorAdd(aabb->origin, aabb->extents, vMax); + VectorSet(Coords[0], vMin[0], vMax[1], vMax[2]); + VectorSet(Coords[1], vMax[0], vMax[1], vMax[2]); + VectorSet(Coords[2], vMax[0], vMin[1], vMax[2]); + VectorSet(Coords[3], vMin[0], vMin[1], vMax[2]); + VectorSet(Coords[4], vMin[0], vMax[1], vMin[2]); + VectorSet(Coords[5], vMax[0], vMax[1], vMin[2]); + VectorSet(Coords[6], vMax[0], vMin[1], vMin[2]); + VectorSet(Coords[7], vMin[0], vMin[1], vMin[2]); + + vec3_t Normals[8] = { {-1, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 1 }, + { 0, 0,-1 }, + { 0, 1, 0 }, + { 1, 0, 0 }, + { 0,-1, 0 } }; + + unsigned short Indices[24] = { 2, 1, 5, 6, + 1, 0, 4, 5, + 0, 1, 2, 3, + 3, 7, 4, 0, + 3, 2, 6, 7, + 7, 6, 5, 4 }; + + qglVertexPointer(3, GL_FLOAT, 0, Coords); // filling the arrays + qglNormalPointer(GL_FLOAT, 0, Normals); + + //glLockArraysEXT(0, count); // extension GL_EXT_compiled_vertex_array + + qglDrawElements(GL_QUADS, 24, GL_UNSIGNED_SHORT, Indices); + + //glUnlockArraysEXT; // extension GL_EXT_compiled_vertex_array +*/ +} + +qboolean IsBrushSelected(brush_t* bSel) +{ + for (brush_t* b = selected_brushes.next ;b != NULL && b != &selected_brushes; b = b->next) + { + if (b == bSel) + return true; + } + return false; +} + + diff --git a/radiant/brush_primit.cpp b/radiant/brush_primit.cpp index 22fca0ad..915ea332 100644 --- a/radiant/brush_primit.cpp +++ b/radiant/brush_primit.cpp @@ -1,600 +1,600 @@ -/* -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 -*/ - -#include "stdafx.h" - -// compute a determinant using Sarrus rule -//++timo "inline" this with a macro -// NOTE : the three vec3_t are understood as columns of the matrix -vec_t SarrusDet(vec3_t a, vec3_t b, vec3_t c) -{ - return a[0]*b[1]*c[2]+b[0]*c[1]*a[2]+c[0]*a[1]*b[2] - -c[0]*b[1]*a[2]-a[1]*b[0]*c[2]-a[0]*b[2]*c[1]; -} - -// in many case we know three points A,B,C in two axis base B1 and B2 -// and we want the matrix M so that A(B1) = T * A(B2) -// NOTE: 2D homogeneous space stuff -// NOTE: we don't do any check to see if there's a solution or we have a particular case .. need to make sure before calling -// NOTE: the third coord of the A,B,C point is ignored -// NOTE: see the commented out section to fill M and D -//++timo TODO: update the other members to use this when possible -void MatrixForPoints( vec3_t M[3], vec3_t D[2], brushprimit_texdef_t *T ) -{ -// vec3_t M[3]; // columns of the matrix .. easier that way (the indexing is not standard! it's column-line .. later computations are easier that way) - vec_t det; -// vec3_t D[2]; - M[2][0]=1.0f; M[2][1]=1.0f; M[2][2]=1.0f; -#if 0 - // fill the data vectors - M[0][0]=A2[0]; M[0][1]=B2[0]; M[0][2]=C2[0]; - M[1][0]=A2[1]; M[1][1]=B2[1]; M[1][2]=C2[1]; - M[2][0]=1.0f; M[2][1]=1.0f; M[2][2]=1.0f; - D[0][0]=A1[0]; - D[0][1]=B1[0]; - D[0][2]=C1[0]; - D[1][0]=A1[1]; - D[1][1]=B1[1]; - D[1][2]=C1[1]; -#endif - // solve - det = SarrusDet( M[0], M[1], M[2] ); - T->coords[0][0] = SarrusDet( D[0], M[1], M[2] ) / det; - T->coords[0][1] = SarrusDet( M[0], D[0], M[2] ) / det; - T->coords[0][2] = SarrusDet( M[0], M[1], D[0] ) / det; - T->coords[1][0] = SarrusDet( D[1], M[1], M[2] ) / det; - T->coords[1][1] = SarrusDet( M[0], D[1], M[2] ) / det; - T->coords[1][2] = SarrusDet( M[0], M[1], D[1] ) / det; -} - -//++timo replace everywhere texX by texS etc. ( ----> and in q3map !) -// NOTE : ComputeAxisBase here and in q3map code must always BE THE SAME ! -// WARNING : special case behaviour of atan2(y,x) <-> atan(y/x) might not be the same everywhere when x == 0 -// rotation by (0,RotY,RotZ) assigns X to normal -void ComputeAxisBase(vec3_t normal,vec3_t texS,vec3_t texT ) -{ - vec_t RotY,RotZ; - // do some cleaning - if (fabs(normal[0])<1e-6) - normal[0]=0.0f; - if (fabs(normal[1])<1e-6) - normal[1]=0.0f; - if (fabs(normal[2])<1e-6) - normal[2]=0.0f; - RotY=-atan2(normal[2],sqrt(normal[1]*normal[1]+normal[0]*normal[0])); - RotZ=atan2(normal[1],normal[0]); - // rotate (0,1,0) and (0,0,1) to compute texS and texT - texS[0]=-sin(RotZ); - texS[1]=cos(RotZ); - texS[2]=0; - // the texT vector is along -Z ( T texture coorinates axis ) - texT[0]=-sin(RotY)*cos(RotZ); - texT[1]=-sin(RotY)*sin(RotZ); - texT[2]=-cos(RotY); -} - -void FaceToBrushPrimitFace(face_t *f) -{ - vec3_t texX,texY; - vec3_t proj; - // ST of (0,0) (1,0) (0,1) - vec_t ST[3][5]; // [ point index ] [ xyz ST ] - //++timo not used as long as brushprimit_texdef and texdef are static -/* f->brushprimit_texdef.contents=f->texdef.contents; - f->brushprimit_texdef.flags=f->texdef.flags; - f->brushprimit_texdef.value=f->texdef.value; - strcpy(f->brushprimit_texdef.name,f->texdef.name); */ -#ifdef DBG_BP - if ( f->plane.normal[0]==0.0f && f->plane.normal[1]==0.0f && f->plane.normal[2]==0.0f ) - { - Sys_Printf("Warning : f->plane.normal is (0,0,0) in FaceToBrushPrimitFace\n"); - } - // check d_texture - if (!f->d_texture) - { - Sys_Printf("Warning : f.d_texture is NULL in FaceToBrushPrimitFace\n"); - return; - } -#endif - // compute axis base - ComputeAxisBase(f->plane.normal,texX,texY); - // compute projection vector - VectorCopy(f->plane.normal,proj); - VectorScale(proj,f->plane.dist,proj); - // (0,0) in plane axis base is (0,0,0) in world coordinates + projection on the affine plane - // (1,0) in plane axis base is texX in world coordinates + projection on the affine plane - // (0,1) in plane axis base is texY in world coordinates + projection on the affine plane - // use old texture code to compute the ST coords of these points - VectorCopy(proj,ST[0]); - EmitTextureCoordinates(ST[0], f->d_texture, f); - VectorCopy(texX,ST[1]); - VectorAdd(ST[1],proj,ST[1]); - EmitTextureCoordinates(ST[1], f->d_texture, f); - VectorCopy(texY,ST[2]); - VectorAdd(ST[2],proj,ST[2]); - EmitTextureCoordinates(ST[2], f->d_texture, f); - // compute texture matrix - f->brushprimit_texdef.coords[0][2]=ST[0][3]; - f->brushprimit_texdef.coords[1][2]=ST[0][4]; - f->brushprimit_texdef.coords[0][0]=ST[1][3]-f->brushprimit_texdef.coords[0][2]; - f->brushprimit_texdef.coords[1][0]=ST[1][4]-f->brushprimit_texdef.coords[1][2]; - f->brushprimit_texdef.coords[0][1]=ST[2][3]-f->brushprimit_texdef.coords[0][2]; - f->brushprimit_texdef.coords[1][1]=ST[2][4]-f->brushprimit_texdef.coords[1][2]; -} - -// compute texture coordinates for the winding points -void EmitBrushPrimitTextureCoordinates(face_t * f, winding_t * w) -{ - vec3_t texX,texY; - vec_t x,y; - // compute axis base - ComputeAxisBase(f->plane.normal,texX,texY); - // in case the texcoords matrix is empty, build a default one - // same behaviour as if scale[0]==0 && scale[1]==0 in old code - if (f->brushprimit_texdef.coords[0][0]==0 && f->brushprimit_texdef.coords[1][0]==0 && f->brushprimit_texdef.coords[0][1]==0 && f->brushprimit_texdef.coords[1][1]==0) - { - f->brushprimit_texdef.coords[0][0] = 1.0f; - f->brushprimit_texdef.coords[1][1] = 1.0f; - ConvertTexMatWithQTexture( &f->brushprimit_texdef, NULL, &f->brushprimit_texdef, f->d_texture ); - } - int i; - for (i=0 ; inumpoints ; i++) - { - x=DotProduct(w->points[i],texX); - y=DotProduct(w->points[i],texY); -#ifdef DBG_BP - if (g_qeglobals.bNeedConvert) - { - // check we compute the same ST as the traditional texture computation used before - vec_t S=f->brushprimit_texdef.coords[0][0]*x+f->brushprimit_texdef.coords[0][1]*y+f->brushprimit_texdef.coords[0][2]; - vec_t T=f->brushprimit_texdef.coords[1][0]*x+f->brushprimit_texdef.coords[1][1]*y+f->brushprimit_texdef.coords[1][2]; - if ( fabs(S-w->points[i][3])>1e-2 || fabs(T-w->points[i][4])>1e-2 ) - { - if ( fabs(S-w->points[i][3])>1e-4 || fabs(T-w->points[i][4])>1e-4 ) - Sys_Printf("Warning : precision loss in brush -> brush primitive texture computation\n"); - else - Sys_Printf("Warning : brush -> brush primitive texture computation bug detected\n"); - } - } -#endif - w->points[i][3]=f->brushprimit_texdef.coords[0][0]*x+f->brushprimit_texdef.coords[0][1]*y+f->brushprimit_texdef.coords[0][2]; - w->points[i][4]=f->brushprimit_texdef.coords[1][0]*x+f->brushprimit_texdef.coords[1][1]*y+f->brushprimit_texdef.coords[1][2]; - } -} - -// compute a fake shift scale rot representation from the texture matrix -// these shift scale rot values are to be understood in the local axis base -void TexMatToFakeTexCoords( vec_t texMat[2][3], float shift[2], float *rot, float scale[2] ) -{ -#ifdef DBG_BP - // check this matrix is orthogonal - if (fabs(texMat[0][0]*texMat[0][1]+texMat[1][0]*texMat[1][1])>ZERO_EPSILON) - Sys_Printf("Warning : non orthogonal texture matrix in TexMatToFakeTexCoords\n"); -#endif - scale[0]=sqrt(texMat[0][0]*texMat[0][0]+texMat[1][0]*texMat[1][0]); - scale[1]=sqrt(texMat[0][1]*texMat[0][1]+texMat[1][1]*texMat[1][1]); -#ifdef DBG_BP - if (scale[0]0) - *rot=90.0f; - else - *rot=-90.0f; - } - else - *rot = RAD2DEG( atan2( texMat[1][0], texMat[0][0] ) ); - shift[0] = -texMat[0][2]; - shift[1] = texMat[1][2]; -} - -// compute back the texture matrix from fake shift scale rot -// the matrix returned must be understood as a qtexture_t with width=2 height=2 ( the default one ) -void FakeTexCoordsToTexMat( float shift[2], float rot, float scale[2], vec_t texMat[2][3] ) -{ - texMat[0][0] = scale[0] * cos( DEG2RAD( rot ) ); - texMat[1][0] = scale[0] * sin( DEG2RAD( rot ) ); - texMat[0][1] = -1.0f * scale[1] * sin( DEG2RAD( rot ) ); - texMat[1][1] = scale[1] * cos( DEG2RAD( rot ) ); - texMat[0][2] = -shift[0]; - texMat[1][2] = shift[1]; -} - -// convert a texture matrix between two qtexture_t -// if NULL for qtexture_t, basic 2x2 texture is assumed ( straight mapping between s/t coordinates and geometric coordinates ) -void ConvertTexMatWithQTexture( vec_t texMat1[2][3], qtexture_t *qtex1, vec_t texMat2[2][3], qtexture_t *qtex2 ) -{ - float s1,s2; - s1 = ( qtex1 ? static_cast( qtex1->width ) : 2.0f ) / ( qtex2 ? static_cast( qtex2->width ) : 2.0f ); - s2 = ( qtex1 ? static_cast( qtex1->height ) : 2.0f ) / ( qtex2 ? static_cast( qtex2->height ) : 2.0f ); - texMat2[0][0]=s1*texMat1[0][0]; - texMat2[0][1]=s1*texMat1[0][1]; - texMat2[0][2]=s1*texMat1[0][2]; - texMat2[1][0]=s2*texMat1[1][0]; - texMat2[1][1]=s2*texMat1[1][1]; - texMat2[1][2]=s2*texMat1[1][2]; -} - -void ConvertTexMatWithQTexture( brushprimit_texdef_t *texMat1, qtexture_t *qtex1, brushprimit_texdef_t *texMat2, qtexture_t *qtex2 ) -{ - ConvertTexMatWithQTexture(texMat1->coords, qtex1, texMat2->coords, qtex2); -} - -// used for texture locking -// will move the texture according to a geometric vector -void ShiftTextureGeometric_BrushPrimit(face_t *f, vec3_t delta) -{ - vec3_t texS,texT; - vec_t tx,ty; - vec3_t M[3]; // columns of the matrix .. easier that way - vec_t det; - vec3_t D[2]; - // compute plane axis base ( doesn't change with translation ) - ComputeAxisBase( f->plane.normal, texS, texT ); - // compute translation vector in plane axis base - tx = DotProduct( delta, texS ); - ty = DotProduct( delta, texT ); - // fill the data vectors - M[0][0]=tx; M[0][1]=1.0f+tx; M[0][2]=tx; - M[1][0]=ty; M[1][1]=ty; M[1][2]=1.0f+ty; - M[2][0]=1.0f; M[2][1]=1.0f; M[2][2]=1.0f; - D[0][0]=f->brushprimit_texdef.coords[0][2]; - D[0][1]=f->brushprimit_texdef.coords[0][0]+f->brushprimit_texdef.coords[0][2]; - D[0][2]=f->brushprimit_texdef.coords[0][1]+f->brushprimit_texdef.coords[0][2]; - D[1][0]=f->brushprimit_texdef.coords[1][2]; - D[1][1]=f->brushprimit_texdef.coords[1][0]+f->brushprimit_texdef.coords[1][2]; - D[1][2]=f->brushprimit_texdef.coords[1][1]+f->brushprimit_texdef.coords[1][2]; - // solve - det = SarrusDet( M[0], M[1], M[2] ); - f->brushprimit_texdef.coords[0][0] = SarrusDet( D[0], M[1], M[2] ) / det; - f->brushprimit_texdef.coords[0][1] = SarrusDet( M[0], D[0], M[2] ) / det; - f->brushprimit_texdef.coords[0][2] = SarrusDet( M[0], M[1], D[0] ) / det; - f->brushprimit_texdef.coords[1][0] = SarrusDet( D[1], M[1], M[2] ) / det; - f->brushprimit_texdef.coords[1][1] = SarrusDet( M[0], D[1], M[2] ) / det; - f->brushprimit_texdef.coords[1][2] = SarrusDet( M[0], M[1], D[1] ) / det; -} - -// shift a texture (texture adjustments) along it's current texture axes -// x and y are geometric values, which we must compute as ST increments -// this depends on the texture size and the pixel/texel ratio -void ShiftTextureRelative_BrushPrimit( face_t *f, float x, float y) -{ - float s,t; - // as a ratio against texture size - // the scale of the texture is not relevant here (we work directly on a transformation from the base vectors) - s = (x * 2.0) / (float)f->d_texture->width; - t = (y * 2.0) / (float)f->d_texture->height; - f->brushprimit_texdef.coords[0][2] -= s; - f->brushprimit_texdef.coords[1][2] -= t; -} - -// TTimo: FIXME: I don't like that, it feels broken -// (and it's likely that it's not used anymore) -// best fitted 2D vector is x.X+y.Y -void ComputeBest2DVector( vec3_t v, vec3_t X, vec3_t Y, int &x, int &y ) -{ - double sx,sy; - sx = DotProduct( v, X ); - sy = DotProduct( v, Y ); - if ( fabs(sy) > fabs(sx) ) - { - x = 0; - if ( sy > 0.0 ) - y = 1; - else - y = -1; - } - else - { - y = 0; - if ( sx > 0.0 ) - x = 1; - else - x = -1; - } -} - -//++timo FIXME quick'n dirty hack, doesn't care about current texture settings (angle) -// can be improved .. bug #107311 -// mins and maxs are the face bounding box -//++timo fixme: we use the face info, mins and maxs are irrelevant -void Face_FitTexture_BrushPrimit( face_t *f, vec3_t mins, vec3_t maxs, int nHeight, int nWidth ) -{ - vec3_t BBoxSTMin, BBoxSTMax; - winding_t *w; - int i,j; - vec_t val; - vec3_t M[3],D[2]; -// vec3_t N[2],Mf[2]; - brushprimit_texdef_t N; - vec3_t Mf[2]; - - - // we'll be working on a standardized texture size -// ConvertTexMatWithQTexture( &f->brushprimit_texdef, f->d_texture, &f->brushprimit_texdef, NULL ); - // compute the BBox in ST coords - EmitBrushPrimitTextureCoordinates( f, f->face_winding ); - ClearBounds( BBoxSTMin, BBoxSTMax ); - w = f->face_winding; - for (i=0 ; inumpoints ; i++) - { - // AddPointToBounds in 2D on (S,T) coordinates - for (j=0 ; j<2 ; j++) - { - val = w->points[i][j+3]; - if (val < BBoxSTMin[j]) - BBoxSTMin[j] = val; - if (val > BBoxSTMax[j]) - BBoxSTMax[j] = val; - } - } - // we have the three points of the BBox (BBoxSTMin[0].BBoxSTMin[1]) (BBoxSTMax[0],BBoxSTMin[1]) (BBoxSTMin[0],BBoxSTMax[1]) in ST space - // the BP matrix we are looking for gives (0,0) (nwidth,0) (0,nHeight) coordinates in (Sfit,Tfit) space to these three points - // we have A(Sfit,Tfit) = (0,0) = Mf * A(TexS,TexT) = N * M * A(TexS,TexT) = N * A(S,T) - // so we solve the system for N and then Mf = N * M - M[0][0] = BBoxSTMin[0]; M[0][1] = BBoxSTMax[0]; M[0][2] = BBoxSTMin[0]; - M[1][0] = BBoxSTMin[1]; M[1][1] = BBoxSTMin[1]; M[1][2] = BBoxSTMax[1]; - D[0][0] = 0.0f; D[0][1] = nWidth; D[0][2] = 0.0f; - D[1][0] = 0.0f; D[1][1] = 0.0f; D[1][2] = nHeight; - MatrixForPoints( M, D, &N ); - -#if 0 - // FIT operation gives coordinates of three points of the bounding box in (S',T'), our target axis base - // A(S',T')=(0,0) B(S',T')=(nWidth,0) C(S',T')=(0,nHeight) - // and we have them in (S,T) axis base: A(S,T)=(BBoxSTMin[0],BBoxSTMin[1]) B(S,T)=(BBoxSTMax[0],BBoxSTMin[1]) C(S,T)=(BBoxSTMin[0],BBoxSTMax[1]) - // we compute the N transformation so that: A(S',T') = N * A(S,T) - VectorSet( N[0], (BBoxSTMax[0]-BBoxSTMin[0])/(float)nWidth, 0.0f, BBoxSTMin[0] ); - VectorSet( N[1], 0.0f, (BBoxSTMax[1]-BBoxSTMin[1])/(float)nHeight, BBoxSTMin[1] ); -#endif - - // the final matrix is the product (Mf stands for Mfit) - Mf[0][0] = N.coords[0][0] * f->brushprimit_texdef.coords[0][0] + N.coords[0][1] * f->brushprimit_texdef.coords[1][0]; - Mf[0][1] = N.coords[0][0] * f->brushprimit_texdef.coords[0][1] + N.coords[0][1] * f->brushprimit_texdef.coords[1][1]; - Mf[0][2] = N.coords[0][0] * f->brushprimit_texdef.coords[0][2] + N.coords[0][1] * f->brushprimit_texdef.coords[1][2] + N.coords[0][2]; - Mf[1][0] = N.coords[1][0] * f->brushprimit_texdef.coords[0][0] + N.coords[1][1] * f->brushprimit_texdef.coords[1][0]; - Mf[1][1] = N.coords[1][0] * f->brushprimit_texdef.coords[0][1] + N.coords[1][1] * f->brushprimit_texdef.coords[1][1]; - Mf[1][2] = N.coords[1][0] * f->brushprimit_texdef.coords[0][2] + N.coords[1][1] * f->brushprimit_texdef.coords[1][2] + N.coords[1][2]; - // copy back - VectorCopy( Mf[0], f->brushprimit_texdef.coords[0] ); - VectorCopy( Mf[1], f->brushprimit_texdef.coords[1] ); - // handle the texture size -// ConvertTexMatWithQTexture( &f->brushprimit_texdef, NULL, &f->brushprimit_texdef, f->d_texture ); -} - -void BrushPrimitFaceToFace(face_t *face) -{ - // we have parsed brush primitives and need conversion back to standard format - // NOTE: converting back is a quick hack, there's some information lost and we can't do anything about it - // FIXME: if we normalize the texture matrix to a standard 2x2 size, we end up with wrong scaling - // I tried various tweaks, no luck .. seems shifting is lost - brushprimit_texdef_t aux; - ConvertTexMatWithQTexture( &face->brushprimit_texdef, face->d_texture, &aux, NULL ); - TexMatToFakeTexCoords( aux.coords, face->texdef.shift, &face->texdef.rotate, face->texdef.scale ); - face->texdef.scale[0]/=2.0; - face->texdef.scale[1]/=2.0; -} - -// TEXTURE LOCKING ----------------------------------------------------------------------------------------------------- -// (Relevant to the editor only?) - -// internally used for texture locking on rotation and flipping -// the general algorithm is the same for both lockings, it's only the geometric transformation part that changes -// so I wanted to keep it in a single function -// if there are more linear transformations that need the locking, going to a C++ or code pointer solution would be best -// (but right now I want to keep brush_primit.cpp striclty C) - -qboolean txlock_bRotation; - -// rotation locking params -int txl_nAxis; -float txl_fDeg; -vec3_t txl_vOrigin; - -// flip locking params -vec3_t txl_matrix[3]; -vec3_t txl_origin; - -void TextureLockTransformation_BrushPrimit(face_t *f) -{ - vec3_t Orig,texS,texT; // axis base of initial plane - // used by transformation algo - vec3_t temp; int j; - vec3_t vRotate; // rotation vector - - vec3_t rOrig,rvecS,rvecT; // geometric transformation of (0,0) (1,0) (0,1) { initial plane axis base } - vec3_t rNormal,rtexS,rtexT; // axis base for the transformed plane - vec3_t lOrig,lvecS,lvecT; // [2] are not used ( but usefull for debugging ) - vec3_t M[3]; - vec_t det; - vec3_t D[2]; - - // compute plane axis base - ComputeAxisBase( f->plane.normal, texS, texT ); - VectorSet(Orig, 0.0f, 0.0f, 0.0f); - - // compute coordinates of (0,0) (1,0) (0,1) ( expressed in initial plane axis base ) after transformation - // (0,0) (1,0) (0,1) ( expressed in initial plane axis base ) <-> (0,0,0) texS texT ( expressed world axis base ) - // input: Orig, texS, texT (and the global locking params) - // ouput: rOrig, rvecS, rvecT, rNormal - if (txlock_bRotation) { - // rotation vector - VectorSet( vRotate, 0.0f, 0.0f, 0.0f ); - vRotate[txl_nAxis]=txl_fDeg; - VectorRotateOrigin ( Orig, vRotate, txl_vOrigin, rOrig ); - VectorRotateOrigin ( texS, vRotate, txl_vOrigin, rvecS ); - VectorRotateOrigin ( texT, vRotate, txl_vOrigin, rvecT ); - // compute normal of plane after rotation - VectorRotate ( f->plane.normal, vRotate, rNormal ); - } - else - { - VectorSubtract (Orig, txl_origin, temp); - for (j=0 ; j<3 ; j++) - rOrig[j] = DotProduct(temp, txl_matrix[j]) + txl_origin[j]; - VectorSubtract (texS, txl_origin, temp); - for (j=0 ; j<3 ; j++) - rvecS[j] = DotProduct(temp, txl_matrix[j]) + txl_origin[j]; - VectorSubtract (texT, txl_origin, temp); - for (j=0 ; j<3 ; j++) - rvecT[j] = DotProduct(temp, txl_matrix[j]) + txl_origin[j]; - // we also need the axis base of the target plane, apply the transformation matrix to the normal too.. - for (j=0 ; j<3 ; j++) - rNormal[j] = DotProduct(f->plane.normal, txl_matrix[j]); - } - - // compute rotated plane axis base - ComputeAxisBase( rNormal, rtexS, rtexT ); - // compute S/T coordinates of the three points in rotated axis base ( in M matrix ) - lOrig[0] = DotProduct( rOrig, rtexS ); - lOrig[1] = DotProduct( rOrig, rtexT ); - lvecS[0] = DotProduct( rvecS, rtexS ); - lvecS[1] = DotProduct( rvecS, rtexT ); - lvecT[0] = DotProduct( rvecT, rtexS ); - lvecT[1] = DotProduct( rvecT, rtexT ); - M[0][0] = lOrig[0]; M[1][0] = lOrig[1]; M[2][0] = 1.0f; - M[0][1] = lvecS[0]; M[1][1] = lvecS[1]; M[2][1] = 1.0f; - M[0][2] = lvecT[0]; M[1][2] = lvecT[1]; M[2][2] = 1.0f; - // fill data vector - D[0][0]=f->brushprimit_texdef.coords[0][2]; - D[0][1]=f->brushprimit_texdef.coords[0][0]+f->brushprimit_texdef.coords[0][2]; - D[0][2]=f->brushprimit_texdef.coords[0][1]+f->brushprimit_texdef.coords[0][2]; - D[1][0]=f->brushprimit_texdef.coords[1][2]; - D[1][1]=f->brushprimit_texdef.coords[1][0]+f->brushprimit_texdef.coords[1][2]; - D[1][2]=f->brushprimit_texdef.coords[1][1]+f->brushprimit_texdef.coords[1][2]; - // solve - det = SarrusDet( M[0], M[1], M[2] ); - f->brushprimit_texdef.coords[0][0] = SarrusDet( D[0], M[1], M[2] ) / det; - f->brushprimit_texdef.coords[0][1] = SarrusDet( M[0], D[0], M[2] ) / det; - f->brushprimit_texdef.coords[0][2] = SarrusDet( M[0], M[1], D[0] ) / det; - f->brushprimit_texdef.coords[1][0] = SarrusDet( D[1], M[1], M[2] ) / det; - f->brushprimit_texdef.coords[1][1] = SarrusDet( M[0], D[1], M[2] ) / det; - f->brushprimit_texdef.coords[1][2] = SarrusDet( M[0], M[1], D[1] ) / det; -} - -// texture locking -// called before the points on the face are actually rotated -void RotateFaceTexture_BrushPrimit(face_t *f, int nAxis, float fDeg, vec3_t vOrigin ) -{ - // this is a placeholder to call the general texture locking algorithm - txlock_bRotation = true; - txl_nAxis = nAxis; - txl_fDeg = fDeg; - VectorCopy(vOrigin, txl_vOrigin); - TextureLockTransformation_BrushPrimit(f); -} - -// compute the new brush primit texture matrix for a transformation matrix and a flip order flag (change plane orientation) -// this matches the select_matrix algo used in select.cpp -// this needs to be called on the face BEFORE any geometric transformation -// it will compute the texture matrix that will represent the same texture on the face after the geometric transformation is done -void ApplyMatrix_BrushPrimit(face_t *f, vec3_t matrix[3], vec3_t origin) -{ - // this is a placeholder to call the general texture locking algorithm - txlock_bRotation = false; - VectorCopy(matrix[0], txl_matrix[0]); - VectorCopy(matrix[1], txl_matrix[1]); - VectorCopy(matrix[2], txl_matrix[2]); - VectorCopy(origin, txl_origin); - TextureLockTransformation_BrushPrimit(f); -} - -// don't do C==A! -void BPMatMul(vec_t A[2][3], vec_t B[2][3], vec_t C[2][3]) -{ - C[0][0] = A[0][0]*B[0][0]+A[0][1]*B[1][0]; - C[1][0] = A[1][0]*B[0][0]+A[1][1]*B[1][0]; - C[0][1] = A[0][0]*B[0][1]+A[0][1]*B[1][1]; - C[1][1] = A[1][0]*B[0][1]+A[1][1]*B[1][1]; - C[0][2] = A[0][0]*B[0][2]+A[0][1]*B[1][2]+A[0][2]; - C[1][2] = A[1][0]*B[0][2]+A[1][1]*B[1][2]+A[1][2]; -} - -void BPMatDump(vec_t A[2][3]) -{ - Sys_Printf("%g %g %g\n%g %g %g\n0 0 1\n", A[0][0], A[0][1], A[0][2], A[1][0], A[1][1], A[1][2]); -} - -void BPMatRotate(vec_t A[2][3], float theta) -{ - vec_t m[2][3]; - vec_t aux[2][3]; - memset(&m, 0, sizeof(vec_t)*6); - m[0][0] = cos(theta*Q_PI/180.0); - m[0][1] = -sin(theta*Q_PI/180.0); - m[1][0] = -m[0][1]; - m[1][1] = m[0][0]; - BPMatMul(A, m, aux); - BPMatCopy(aux,A); -} - -// get the relative axes of the current texturing -void BrushPrimit_GetRelativeAxes(face_t *f, vec3_t vecS, vec3_t vecT) -{ - vec_t vS[2],vT[2]; - // first we compute them as expressed in plane axis base - // BP matrix has coordinates of plane axis base expressed in geometric axis base - // so we use the line vectors - vS[0] = f->brushprimit_texdef.coords[0][0]; - vS[1] = f->brushprimit_texdef.coords[0][1]; - vT[0] = f->brushprimit_texdef.coords[1][0]; - vT[1] = f->brushprimit_texdef.coords[1][1]; - // now compute those vectors in geometric space - vec3_t texS, texT; // axis base of the plane (geometric) - ComputeAxisBase(f->plane.normal, texS, texT); - // vecS[] = vS[0].texS[] + vS[1].texT[] - // vecT[] = vT[0].texS[] + vT[1].texT[] - vecS[0] = vS[0]*texS[0] + vS[1]*texT[0]; - vecS[1] = vS[0]*texS[1] + vS[1]*texT[1]; - vecS[2] = vS[0]*texS[2] + vS[1]*texT[2]; - vecT[0] = vT[0]*texS[0] + vT[1]*texT[0]; - vecT[1] = vT[0]*texS[1] + vT[1]*texT[1]; - vecT[2] = vT[0]*texS[2] + vT[1]*texT[2]; -} - -// GL matrix 4x4 product (3D homogeneous matrix) -// NOTE: the crappy thing is that GL doesn't follow the standard convention [line][column] -// otherwise it's all good -void GLMatMul(vec_t M[4][4], vec_t A[4], vec_t B[4]) -{ - unsigned short i,j; - for (i=0;i<4;i++) - { - B[i] = 0.0; - for (j=0;j<4;j++) - { - B[i] += M[j][i]*A[j]; - } - } -} - -qboolean IsBrushPrimitMode() -{ - return(g_qeglobals.m_bBrushPrimitMode); -} +/* +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 +*/ + +#include "stdafx.h" + +// compute a determinant using Sarrus rule +//++timo "inline" this with a macro +// NOTE : the three vec3_t are understood as columns of the matrix +vec_t SarrusDet(vec3_t a, vec3_t b, vec3_t c) +{ + return a[0]*b[1]*c[2]+b[0]*c[1]*a[2]+c[0]*a[1]*b[2] + -c[0]*b[1]*a[2]-a[1]*b[0]*c[2]-a[0]*b[2]*c[1]; +} + +// in many case we know three points A,B,C in two axis base B1 and B2 +// and we want the matrix M so that A(B1) = T * A(B2) +// NOTE: 2D homogeneous space stuff +// NOTE: we don't do any check to see if there's a solution or we have a particular case .. need to make sure before calling +// NOTE: the third coord of the A,B,C point is ignored +// NOTE: see the commented out section to fill M and D +//++timo TODO: update the other members to use this when possible +void MatrixForPoints( vec3_t M[3], vec3_t D[2], brushprimit_texdef_t *T ) +{ +// vec3_t M[3]; // columns of the matrix .. easier that way (the indexing is not standard! it's column-line .. later computations are easier that way) + vec_t det; +// vec3_t D[2]; + M[2][0]=1.0f; M[2][1]=1.0f; M[2][2]=1.0f; +#if 0 + // fill the data vectors + M[0][0]=A2[0]; M[0][1]=B2[0]; M[0][2]=C2[0]; + M[1][0]=A2[1]; M[1][1]=B2[1]; M[1][2]=C2[1]; + M[2][0]=1.0f; M[2][1]=1.0f; M[2][2]=1.0f; + D[0][0]=A1[0]; + D[0][1]=B1[0]; + D[0][2]=C1[0]; + D[1][0]=A1[1]; + D[1][1]=B1[1]; + D[1][2]=C1[1]; +#endif + // solve + det = SarrusDet( M[0], M[1], M[2] ); + T->coords[0][0] = SarrusDet( D[0], M[1], M[2] ) / det; + T->coords[0][1] = SarrusDet( M[0], D[0], M[2] ) / det; + T->coords[0][2] = SarrusDet( M[0], M[1], D[0] ) / det; + T->coords[1][0] = SarrusDet( D[1], M[1], M[2] ) / det; + T->coords[1][1] = SarrusDet( M[0], D[1], M[2] ) / det; + T->coords[1][2] = SarrusDet( M[0], M[1], D[1] ) / det; +} + +//++timo replace everywhere texX by texS etc. ( ----> and in q3map !) +// NOTE : ComputeAxisBase here and in q3map code must always BE THE SAME ! +// WARNING : special case behaviour of atan2(y,x) <-> atan(y/x) might not be the same everywhere when x == 0 +// rotation by (0,RotY,RotZ) assigns X to normal +void ComputeAxisBase(vec3_t normal,vec3_t texS,vec3_t texT ) +{ + vec_t RotY,RotZ; + // do some cleaning + if (fabs(normal[0])<1e-6) + normal[0]=0.0f; + if (fabs(normal[1])<1e-6) + normal[1]=0.0f; + if (fabs(normal[2])<1e-6) + normal[2]=0.0f; + RotY=-atan2(normal[2],sqrt(normal[1]*normal[1]+normal[0]*normal[0])); + RotZ=atan2(normal[1],normal[0]); + // rotate (0,1,0) and (0,0,1) to compute texS and texT + texS[0]=-sin(RotZ); + texS[1]=cos(RotZ); + texS[2]=0; + // the texT vector is along -Z ( T texture coorinates axis ) + texT[0]=-sin(RotY)*cos(RotZ); + texT[1]=-sin(RotY)*sin(RotZ); + texT[2]=-cos(RotY); +} + +void FaceToBrushPrimitFace(face_t *f) +{ + vec3_t texX,texY; + vec3_t proj; + // ST of (0,0) (1,0) (0,1) + vec_t ST[3][5]; // [ point index ] [ xyz ST ] + //++timo not used as long as brushprimit_texdef and texdef are static +/* f->brushprimit_texdef.contents=f->texdef.contents; + f->brushprimit_texdef.flags=f->texdef.flags; + f->brushprimit_texdef.value=f->texdef.value; + strcpy(f->brushprimit_texdef.name,f->texdef.name); */ +#ifdef DBG_BP + if ( f->plane.normal[0]==0.0f && f->plane.normal[1]==0.0f && f->plane.normal[2]==0.0f ) + { + Sys_Printf("Warning : f->plane.normal is (0,0,0) in FaceToBrushPrimitFace\n"); + } + // check d_texture + if (!f->d_texture) + { + Sys_Printf("Warning : f.d_texture is NULL in FaceToBrushPrimitFace\n"); + return; + } +#endif + // compute axis base + ComputeAxisBase(f->plane.normal,texX,texY); + // compute projection vector + VectorCopy(f->plane.normal,proj); + VectorScale(proj,f->plane.dist,proj); + // (0,0) in plane axis base is (0,0,0) in world coordinates + projection on the affine plane + // (1,0) in plane axis base is texX in world coordinates + projection on the affine plane + // (0,1) in plane axis base is texY in world coordinates + projection on the affine plane + // use old texture code to compute the ST coords of these points + VectorCopy(proj,ST[0]); + EmitTextureCoordinates(ST[0], f->d_texture, f); + VectorCopy(texX,ST[1]); + VectorAdd(ST[1],proj,ST[1]); + EmitTextureCoordinates(ST[1], f->d_texture, f); + VectorCopy(texY,ST[2]); + VectorAdd(ST[2],proj,ST[2]); + EmitTextureCoordinates(ST[2], f->d_texture, f); + // compute texture matrix + f->brushprimit_texdef.coords[0][2]=ST[0][3]; + f->brushprimit_texdef.coords[1][2]=ST[0][4]; + f->brushprimit_texdef.coords[0][0]=ST[1][3]-f->brushprimit_texdef.coords[0][2]; + f->brushprimit_texdef.coords[1][0]=ST[1][4]-f->brushprimit_texdef.coords[1][2]; + f->brushprimit_texdef.coords[0][1]=ST[2][3]-f->brushprimit_texdef.coords[0][2]; + f->brushprimit_texdef.coords[1][1]=ST[2][4]-f->brushprimit_texdef.coords[1][2]; +} + +// compute texture coordinates for the winding points +void EmitBrushPrimitTextureCoordinates(face_t * f, winding_t * w) +{ + vec3_t texX,texY; + vec_t x,y; + // compute axis base + ComputeAxisBase(f->plane.normal,texX,texY); + // in case the texcoords matrix is empty, build a default one + // same behaviour as if scale[0]==0 && scale[1]==0 in old code + if (f->brushprimit_texdef.coords[0][0]==0 && f->brushprimit_texdef.coords[1][0]==0 && f->brushprimit_texdef.coords[0][1]==0 && f->brushprimit_texdef.coords[1][1]==0) + { + f->brushprimit_texdef.coords[0][0] = 1.0f; + f->brushprimit_texdef.coords[1][1] = 1.0f; + ConvertTexMatWithQTexture( &f->brushprimit_texdef, NULL, &f->brushprimit_texdef, f->d_texture ); + } + int i; + for (i=0 ; inumpoints ; i++) + { + x=DotProduct(w->points[i],texX); + y=DotProduct(w->points[i],texY); +#ifdef DBG_BP + if (g_qeglobals.bNeedConvert) + { + // check we compute the same ST as the traditional texture computation used before + vec_t S=f->brushprimit_texdef.coords[0][0]*x+f->brushprimit_texdef.coords[0][1]*y+f->brushprimit_texdef.coords[0][2]; + vec_t T=f->brushprimit_texdef.coords[1][0]*x+f->brushprimit_texdef.coords[1][1]*y+f->brushprimit_texdef.coords[1][2]; + if ( fabs(S-w->points[i][3])>1e-2 || fabs(T-w->points[i][4])>1e-2 ) + { + if ( fabs(S-w->points[i][3])>1e-4 || fabs(T-w->points[i][4])>1e-4 ) + Sys_Printf("Warning : precision loss in brush -> brush primitive texture computation\n"); + else + Sys_Printf("Warning : brush -> brush primitive texture computation bug detected\n"); + } + } +#endif + w->points[i][3]=f->brushprimit_texdef.coords[0][0]*x+f->brushprimit_texdef.coords[0][1]*y+f->brushprimit_texdef.coords[0][2]; + w->points[i][4]=f->brushprimit_texdef.coords[1][0]*x+f->brushprimit_texdef.coords[1][1]*y+f->brushprimit_texdef.coords[1][2]; + } +} + +// compute a fake shift scale rot representation from the texture matrix +// these shift scale rot values are to be understood in the local axis base +void TexMatToFakeTexCoords( vec_t texMat[2][3], float shift[2], float *rot, float scale[2] ) +{ +#ifdef DBG_BP + // check this matrix is orthogonal + if (fabs(texMat[0][0]*texMat[0][1]+texMat[1][0]*texMat[1][1])>ZERO_EPSILON) + Sys_Printf("Warning : non orthogonal texture matrix in TexMatToFakeTexCoords\n"); +#endif + scale[0]=sqrt(texMat[0][0]*texMat[0][0]+texMat[1][0]*texMat[1][0]); + scale[1]=sqrt(texMat[0][1]*texMat[0][1]+texMat[1][1]*texMat[1][1]); +#ifdef DBG_BP + if (scale[0]0) + *rot=90.0f; + else + *rot=-90.0f; + } + else + *rot = RAD2DEG( atan2( texMat[1][0], texMat[0][0] ) ); + shift[0] = -texMat[0][2]; + shift[1] = texMat[1][2]; +} + +// compute back the texture matrix from fake shift scale rot +// the matrix returned must be understood as a qtexture_t with width=2 height=2 ( the default one ) +void FakeTexCoordsToTexMat( float shift[2], float rot, float scale[2], vec_t texMat[2][3] ) +{ + texMat[0][0] = scale[0] * cos( DEG2RAD( rot ) ); + texMat[1][0] = scale[0] * sin( DEG2RAD( rot ) ); + texMat[0][1] = -1.0f * scale[1] * sin( DEG2RAD( rot ) ); + texMat[1][1] = scale[1] * cos( DEG2RAD( rot ) ); + texMat[0][2] = -shift[0]; + texMat[1][2] = shift[1]; +} + +// convert a texture matrix between two qtexture_t +// if NULL for qtexture_t, basic 2x2 texture is assumed ( straight mapping between s/t coordinates and geometric coordinates ) +void ConvertTexMatWithQTexture( vec_t texMat1[2][3], qtexture_t *qtex1, vec_t texMat2[2][3], qtexture_t *qtex2 ) +{ + float s1,s2; + s1 = ( qtex1 ? static_cast( qtex1->width ) : 2.0f ) / ( qtex2 ? static_cast( qtex2->width ) : 2.0f ); + s2 = ( qtex1 ? static_cast( qtex1->height ) : 2.0f ) / ( qtex2 ? static_cast( qtex2->height ) : 2.0f ); + texMat2[0][0]=s1*texMat1[0][0]; + texMat2[0][1]=s1*texMat1[0][1]; + texMat2[0][2]=s1*texMat1[0][2]; + texMat2[1][0]=s2*texMat1[1][0]; + texMat2[1][1]=s2*texMat1[1][1]; + texMat2[1][2]=s2*texMat1[1][2]; +} + +void ConvertTexMatWithQTexture( brushprimit_texdef_t *texMat1, qtexture_t *qtex1, brushprimit_texdef_t *texMat2, qtexture_t *qtex2 ) +{ + ConvertTexMatWithQTexture(texMat1->coords, qtex1, texMat2->coords, qtex2); +} + +// used for texture locking +// will move the texture according to a geometric vector +void ShiftTextureGeometric_BrushPrimit(face_t *f, vec3_t delta) +{ + vec3_t texS,texT; + vec_t tx,ty; + vec3_t M[3]; // columns of the matrix .. easier that way + vec_t det; + vec3_t D[2]; + // compute plane axis base ( doesn't change with translation ) + ComputeAxisBase( f->plane.normal, texS, texT ); + // compute translation vector in plane axis base + tx = DotProduct( delta, texS ); + ty = DotProduct( delta, texT ); + // fill the data vectors + M[0][0]=tx; M[0][1]=1.0f+tx; M[0][2]=tx; + M[1][0]=ty; M[1][1]=ty; M[1][2]=1.0f+ty; + M[2][0]=1.0f; M[2][1]=1.0f; M[2][2]=1.0f; + D[0][0]=f->brushprimit_texdef.coords[0][2]; + D[0][1]=f->brushprimit_texdef.coords[0][0]+f->brushprimit_texdef.coords[0][2]; + D[0][2]=f->brushprimit_texdef.coords[0][1]+f->brushprimit_texdef.coords[0][2]; + D[1][0]=f->brushprimit_texdef.coords[1][2]; + D[1][1]=f->brushprimit_texdef.coords[1][0]+f->brushprimit_texdef.coords[1][2]; + D[1][2]=f->brushprimit_texdef.coords[1][1]+f->brushprimit_texdef.coords[1][2]; + // solve + det = SarrusDet( M[0], M[1], M[2] ); + f->brushprimit_texdef.coords[0][0] = SarrusDet( D[0], M[1], M[2] ) / det; + f->brushprimit_texdef.coords[0][1] = SarrusDet( M[0], D[0], M[2] ) / det; + f->brushprimit_texdef.coords[0][2] = SarrusDet( M[0], M[1], D[0] ) / det; + f->brushprimit_texdef.coords[1][0] = SarrusDet( D[1], M[1], M[2] ) / det; + f->brushprimit_texdef.coords[1][1] = SarrusDet( M[0], D[1], M[2] ) / det; + f->brushprimit_texdef.coords[1][2] = SarrusDet( M[0], M[1], D[1] ) / det; +} + +// shift a texture (texture adjustments) along it's current texture axes +// x and y are geometric values, which we must compute as ST increments +// this depends on the texture size and the pixel/texel ratio +void ShiftTextureRelative_BrushPrimit( face_t *f, float x, float y) +{ + float s,t; + // as a ratio against texture size + // the scale of the texture is not relevant here (we work directly on a transformation from the base vectors) + s = (x * 2.0) / (float)f->d_texture->width; + t = (y * 2.0) / (float)f->d_texture->height; + f->brushprimit_texdef.coords[0][2] -= s; + f->brushprimit_texdef.coords[1][2] -= t; +} + +// TTimo: FIXME: I don't like that, it feels broken +// (and it's likely that it's not used anymore) +// best fitted 2D vector is x.X+y.Y +void ComputeBest2DVector( vec3_t v, vec3_t X, vec3_t Y, int &x, int &y ) +{ + double sx,sy; + sx = DotProduct( v, X ); + sy = DotProduct( v, Y ); + if ( fabs(sy) > fabs(sx) ) + { + x = 0; + if ( sy > 0.0 ) + y = 1; + else + y = -1; + } + else + { + y = 0; + if ( sx > 0.0 ) + x = 1; + else + x = -1; + } +} + +//++timo FIXME quick'n dirty hack, doesn't care about current texture settings (angle) +// can be improved .. bug #107311 +// mins and maxs are the face bounding box +//++timo fixme: we use the face info, mins and maxs are irrelevant +void Face_FitTexture_BrushPrimit( face_t *f, vec3_t mins, vec3_t maxs, int nHeight, int nWidth ) +{ + vec3_t BBoxSTMin, BBoxSTMax; + winding_t *w; + int i,j; + vec_t val; + vec3_t M[3],D[2]; +// vec3_t N[2],Mf[2]; + brushprimit_texdef_t N; + vec3_t Mf[2]; + + + // we'll be working on a standardized texture size +// ConvertTexMatWithQTexture( &f->brushprimit_texdef, f->d_texture, &f->brushprimit_texdef, NULL ); + // compute the BBox in ST coords + EmitBrushPrimitTextureCoordinates( f, f->face_winding ); + ClearBounds( BBoxSTMin, BBoxSTMax ); + w = f->face_winding; + for (i=0 ; inumpoints ; i++) + { + // AddPointToBounds in 2D on (S,T) coordinates + for (j=0 ; j<2 ; j++) + { + val = w->points[i][j+3]; + if (val < BBoxSTMin[j]) + BBoxSTMin[j] = val; + if (val > BBoxSTMax[j]) + BBoxSTMax[j] = val; + } + } + // we have the three points of the BBox (BBoxSTMin[0].BBoxSTMin[1]) (BBoxSTMax[0],BBoxSTMin[1]) (BBoxSTMin[0],BBoxSTMax[1]) in ST space + // the BP matrix we are looking for gives (0,0) (nwidth,0) (0,nHeight) coordinates in (Sfit,Tfit) space to these three points + // we have A(Sfit,Tfit) = (0,0) = Mf * A(TexS,TexT) = N * M * A(TexS,TexT) = N * A(S,T) + // so we solve the system for N and then Mf = N * M + M[0][0] = BBoxSTMin[0]; M[0][1] = BBoxSTMax[0]; M[0][2] = BBoxSTMin[0]; + M[1][0] = BBoxSTMin[1]; M[1][1] = BBoxSTMin[1]; M[1][2] = BBoxSTMax[1]; + D[0][0] = 0.0f; D[0][1] = nWidth; D[0][2] = 0.0f; + D[1][0] = 0.0f; D[1][1] = 0.0f; D[1][2] = nHeight; + MatrixForPoints( M, D, &N ); + +#if 0 + // FIT operation gives coordinates of three points of the bounding box in (S',T'), our target axis base + // A(S',T')=(0,0) B(S',T')=(nWidth,0) C(S',T')=(0,nHeight) + // and we have them in (S,T) axis base: A(S,T)=(BBoxSTMin[0],BBoxSTMin[1]) B(S,T)=(BBoxSTMax[0],BBoxSTMin[1]) C(S,T)=(BBoxSTMin[0],BBoxSTMax[1]) + // we compute the N transformation so that: A(S',T') = N * A(S,T) + VectorSet( N[0], (BBoxSTMax[0]-BBoxSTMin[0])/(float)nWidth, 0.0f, BBoxSTMin[0] ); + VectorSet( N[1], 0.0f, (BBoxSTMax[1]-BBoxSTMin[1])/(float)nHeight, BBoxSTMin[1] ); +#endif + + // the final matrix is the product (Mf stands for Mfit) + Mf[0][0] = N.coords[0][0] * f->brushprimit_texdef.coords[0][0] + N.coords[0][1] * f->brushprimit_texdef.coords[1][0]; + Mf[0][1] = N.coords[0][0] * f->brushprimit_texdef.coords[0][1] + N.coords[0][1] * f->brushprimit_texdef.coords[1][1]; + Mf[0][2] = N.coords[0][0] * f->brushprimit_texdef.coords[0][2] + N.coords[0][1] * f->brushprimit_texdef.coords[1][2] + N.coords[0][2]; + Mf[1][0] = N.coords[1][0] * f->brushprimit_texdef.coords[0][0] + N.coords[1][1] * f->brushprimit_texdef.coords[1][0]; + Mf[1][1] = N.coords[1][0] * f->brushprimit_texdef.coords[0][1] + N.coords[1][1] * f->brushprimit_texdef.coords[1][1]; + Mf[1][2] = N.coords[1][0] * f->brushprimit_texdef.coords[0][2] + N.coords[1][1] * f->brushprimit_texdef.coords[1][2] + N.coords[1][2]; + // copy back + VectorCopy( Mf[0], f->brushprimit_texdef.coords[0] ); + VectorCopy( Mf[1], f->brushprimit_texdef.coords[1] ); + // handle the texture size +// ConvertTexMatWithQTexture( &f->brushprimit_texdef, NULL, &f->brushprimit_texdef, f->d_texture ); +} + +void BrushPrimitFaceToFace(face_t *face) +{ + // we have parsed brush primitives and need conversion back to standard format + // NOTE: converting back is a quick hack, there's some information lost and we can't do anything about it + // FIXME: if we normalize the texture matrix to a standard 2x2 size, we end up with wrong scaling + // I tried various tweaks, no luck .. seems shifting is lost + brushprimit_texdef_t aux; + ConvertTexMatWithQTexture( &face->brushprimit_texdef, face->d_texture, &aux, NULL ); + TexMatToFakeTexCoords( aux.coords, face->texdef.shift, &face->texdef.rotate, face->texdef.scale ); + face->texdef.scale[0]/=2.0; + face->texdef.scale[1]/=2.0; +} + +// TEXTURE LOCKING ----------------------------------------------------------------------------------------------------- +// (Relevant to the editor only?) + +// internally used for texture locking on rotation and flipping +// the general algorithm is the same for both lockings, it's only the geometric transformation part that changes +// so I wanted to keep it in a single function +// if there are more linear transformations that need the locking, going to a C++ or code pointer solution would be best +// (but right now I want to keep brush_primit.cpp striclty C) + +qboolean txlock_bRotation; + +// rotation locking params +int txl_nAxis; +float txl_fDeg; +vec3_t txl_vOrigin; + +// flip locking params +vec3_t txl_matrix[3]; +vec3_t txl_origin; + +void TextureLockTransformation_BrushPrimit(face_t *f) +{ + vec3_t Orig,texS,texT; // axis base of initial plane + // used by transformation algo + vec3_t temp; int j; + vec3_t vRotate; // rotation vector + + vec3_t rOrig,rvecS,rvecT; // geometric transformation of (0,0) (1,0) (0,1) { initial plane axis base } + vec3_t rNormal,rtexS,rtexT; // axis base for the transformed plane + vec3_t lOrig,lvecS,lvecT; // [2] are not used ( but usefull for debugging ) + vec3_t M[3]; + vec_t det; + vec3_t D[2]; + + // compute plane axis base + ComputeAxisBase( f->plane.normal, texS, texT ); + VectorSet(Orig, 0.0f, 0.0f, 0.0f); + + // compute coordinates of (0,0) (1,0) (0,1) ( expressed in initial plane axis base ) after transformation + // (0,0) (1,0) (0,1) ( expressed in initial plane axis base ) <-> (0,0,0) texS texT ( expressed world axis base ) + // input: Orig, texS, texT (and the global locking params) + // ouput: rOrig, rvecS, rvecT, rNormal + if (txlock_bRotation) { + // rotation vector + VectorSet( vRotate, 0.0f, 0.0f, 0.0f ); + vRotate[txl_nAxis]=txl_fDeg; + VectorRotateOrigin ( Orig, vRotate, txl_vOrigin, rOrig ); + VectorRotateOrigin ( texS, vRotate, txl_vOrigin, rvecS ); + VectorRotateOrigin ( texT, vRotate, txl_vOrigin, rvecT ); + // compute normal of plane after rotation + VectorRotate ( f->plane.normal, vRotate, rNormal ); + } + else + { + VectorSubtract (Orig, txl_origin, temp); + for (j=0 ; j<3 ; j++) + rOrig[j] = DotProduct(temp, txl_matrix[j]) + txl_origin[j]; + VectorSubtract (texS, txl_origin, temp); + for (j=0 ; j<3 ; j++) + rvecS[j] = DotProduct(temp, txl_matrix[j]) + txl_origin[j]; + VectorSubtract (texT, txl_origin, temp); + for (j=0 ; j<3 ; j++) + rvecT[j] = DotProduct(temp, txl_matrix[j]) + txl_origin[j]; + // we also need the axis base of the target plane, apply the transformation matrix to the normal too.. + for (j=0 ; j<3 ; j++) + rNormal[j] = DotProduct(f->plane.normal, txl_matrix[j]); + } + + // compute rotated plane axis base + ComputeAxisBase( rNormal, rtexS, rtexT ); + // compute S/T coordinates of the three points in rotated axis base ( in M matrix ) + lOrig[0] = DotProduct( rOrig, rtexS ); + lOrig[1] = DotProduct( rOrig, rtexT ); + lvecS[0] = DotProduct( rvecS, rtexS ); + lvecS[1] = DotProduct( rvecS, rtexT ); + lvecT[0] = DotProduct( rvecT, rtexS ); + lvecT[1] = DotProduct( rvecT, rtexT ); + M[0][0] = lOrig[0]; M[1][0] = lOrig[1]; M[2][0] = 1.0f; + M[0][1] = lvecS[0]; M[1][1] = lvecS[1]; M[2][1] = 1.0f; + M[0][2] = lvecT[0]; M[1][2] = lvecT[1]; M[2][2] = 1.0f; + // fill data vector + D[0][0]=f->brushprimit_texdef.coords[0][2]; + D[0][1]=f->brushprimit_texdef.coords[0][0]+f->brushprimit_texdef.coords[0][2]; + D[0][2]=f->brushprimit_texdef.coords[0][1]+f->brushprimit_texdef.coords[0][2]; + D[1][0]=f->brushprimit_texdef.coords[1][2]; + D[1][1]=f->brushprimit_texdef.coords[1][0]+f->brushprimit_texdef.coords[1][2]; + D[1][2]=f->brushprimit_texdef.coords[1][1]+f->brushprimit_texdef.coords[1][2]; + // solve + det = SarrusDet( M[0], M[1], M[2] ); + f->brushprimit_texdef.coords[0][0] = SarrusDet( D[0], M[1], M[2] ) / det; + f->brushprimit_texdef.coords[0][1] = SarrusDet( M[0], D[0], M[2] ) / det; + f->brushprimit_texdef.coords[0][2] = SarrusDet( M[0], M[1], D[0] ) / det; + f->brushprimit_texdef.coords[1][0] = SarrusDet( D[1], M[1], M[2] ) / det; + f->brushprimit_texdef.coords[1][1] = SarrusDet( M[0], D[1], M[2] ) / det; + f->brushprimit_texdef.coords[1][2] = SarrusDet( M[0], M[1], D[1] ) / det; +} + +// texture locking +// called before the points on the face are actually rotated +void RotateFaceTexture_BrushPrimit(face_t *f, int nAxis, float fDeg, vec3_t vOrigin ) +{ + // this is a placeholder to call the general texture locking algorithm + txlock_bRotation = true; + txl_nAxis = nAxis; + txl_fDeg = fDeg; + VectorCopy(vOrigin, txl_vOrigin); + TextureLockTransformation_BrushPrimit(f); +} + +// compute the new brush primit texture matrix for a transformation matrix and a flip order flag (change plane orientation) +// this matches the select_matrix algo used in select.cpp +// this needs to be called on the face BEFORE any geometric transformation +// it will compute the texture matrix that will represent the same texture on the face after the geometric transformation is done +void ApplyMatrix_BrushPrimit(face_t *f, vec3_t matrix[3], vec3_t origin) +{ + // this is a placeholder to call the general texture locking algorithm + txlock_bRotation = false; + VectorCopy(matrix[0], txl_matrix[0]); + VectorCopy(matrix[1], txl_matrix[1]); + VectorCopy(matrix[2], txl_matrix[2]); + VectorCopy(origin, txl_origin); + TextureLockTransformation_BrushPrimit(f); +} + +// don't do C==A! +void BPMatMul(vec_t A[2][3], vec_t B[2][3], vec_t C[2][3]) +{ + C[0][0] = A[0][0]*B[0][0]+A[0][1]*B[1][0]; + C[1][0] = A[1][0]*B[0][0]+A[1][1]*B[1][0]; + C[0][1] = A[0][0]*B[0][1]+A[0][1]*B[1][1]; + C[1][1] = A[1][0]*B[0][1]+A[1][1]*B[1][1]; + C[0][2] = A[0][0]*B[0][2]+A[0][1]*B[1][2]+A[0][2]; + C[1][2] = A[1][0]*B[0][2]+A[1][1]*B[1][2]+A[1][2]; +} + +void BPMatDump(vec_t A[2][3]) +{ + Sys_Printf("%g %g %g\n%g %g %g\n0 0 1\n", A[0][0], A[0][1], A[0][2], A[1][0], A[1][1], A[1][2]); +} + +void BPMatRotate(vec_t A[2][3], float theta) +{ + vec_t m[2][3]; + vec_t aux[2][3]; + memset(&m, 0, sizeof(vec_t)*6); + m[0][0] = cos(theta*Q_PI/180.0); + m[0][1] = -sin(theta*Q_PI/180.0); + m[1][0] = -m[0][1]; + m[1][1] = m[0][0]; + BPMatMul(A, m, aux); + BPMatCopy(aux,A); +} + +// get the relative axes of the current texturing +void BrushPrimit_GetRelativeAxes(face_t *f, vec3_t vecS, vec3_t vecT) +{ + vec_t vS[2],vT[2]; + // first we compute them as expressed in plane axis base + // BP matrix has coordinates of plane axis base expressed in geometric axis base + // so we use the line vectors + vS[0] = f->brushprimit_texdef.coords[0][0]; + vS[1] = f->brushprimit_texdef.coords[0][1]; + vT[0] = f->brushprimit_texdef.coords[1][0]; + vT[1] = f->brushprimit_texdef.coords[1][1]; + // now compute those vectors in geometric space + vec3_t texS, texT; // axis base of the plane (geometric) + ComputeAxisBase(f->plane.normal, texS, texT); + // vecS[] = vS[0].texS[] + vS[1].texT[] + // vecT[] = vT[0].texS[] + vT[1].texT[] + vecS[0] = vS[0]*texS[0] + vS[1]*texT[0]; + vecS[1] = vS[0]*texS[1] + vS[1]*texT[1]; + vecS[2] = vS[0]*texS[2] + vS[1]*texT[2]; + vecT[0] = vT[0]*texS[0] + vT[1]*texT[0]; + vecT[1] = vT[0]*texS[1] + vT[1]*texT[1]; + vecT[2] = vT[0]*texS[2] + vT[1]*texT[2]; +} + +// GL matrix 4x4 product (3D homogeneous matrix) +// NOTE: the crappy thing is that GL doesn't follow the standard convention [line][column] +// otherwise it's all good +void GLMatMul(vec_t M[4][4], vec_t A[4], vec_t B[4]) +{ + unsigned short i,j; + for (i=0;i<4;i++) + { + B[i] = 0.0; + for (j=0;j<4;j++) + { + B[i] += M[j][i]*A[j]; + } + } +} + +qboolean IsBrushPrimitMode() +{ + return(g_qeglobals.m_bBrushPrimitMode); +} diff --git a/radiant/brushscript.cpp b/radiant/brushscript.cpp index 3fa141d3..68892fc2 100644 --- a/radiant/brushscript.cpp +++ b/radiant/brushscript.cpp @@ -1,698 +1,698 @@ -/* -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 -*/ - -// BrushScript stuff -// - -/*! -\todo is this still used / in working state? -should we cleanup and remove it for good -*/ - -#include "stdafx.h" -#include "gtkmisc.h" - -// -struct SVariableDef -{ - CString m_strName; - CString m_strInput; - float m_fValue; -}; - -struct SVecVariableDef -{ - CString m_strName; - CString m_strInput; - vec3_t m_vValue; -}; - - - -const int MAX_VARIABLES = 64; - -brush_t* g_pHold1 = NULL; -brush_t* g_pHold2 = NULL; -brush_t* g_pHold3 = NULL; -bool g_bRotateAroundSelection; -int g_nVariableCount; -int g_nVecVariableCount; -int g_nLoopCounter; -float g_fDefault = 9999.9f; -vec3_t g_vDefault; -bool g_bStartLoop; -char* g_pLooper; -bool g_bKeepGoing; - -SVariableDef g_Variables[MAX_VARIABLES]; -SVecVariableDef g_VecVariables[MAX_VARIABLES]; - -void InitForScriptRun() -{ - g_pHold1 = NULL; - g_pHold2 = NULL; - g_pHold3 = NULL; - g_bRotateAroundSelection = true; - g_nVariableCount = 0; - g_nVecVariableCount = 0; - g_nLoopCounter = 0; - g_bStartLoop = false; - g_pLooper = NULL; - g_bKeepGoing = true; -} - -void AddVariable(const char* pName, float fValue, const char* pInput = NULL) -{ - if (g_nVariableCount < MAX_VARIABLES) - { - g_Variables[g_nVariableCount].m_strName = pName; - g_Variables[g_nVariableCount].m_strName.MakeLower(); - g_Variables[g_nVariableCount].m_fValue = fValue; - if (pInput) - g_Variables[g_nVariableCount].m_strInput = pInput; - g_nVariableCount++; - } - else - gtk_MessageBox(g_pParentWnd->m_pWidget, "Maximum script variable limit reached!"); -} - -float VariableValue(const char* pName) -{ - CString strName = pName; - strName.MakeLower(); - for (int n = 0; n < g_nVariableCount; n++) - { - if (strName == g_Variables[n].m_strName) - return g_Variables[n].m_fValue; - } - //strName.Format("Reference to non-existant varirable %s", pName); - //g_pParentWnd->MessageBox(strName); - return g_fDefault; -} - -void SetVariableValue(const char* pName, float fValue) -{ - CString strName = pName; - strName.MakeLower(); - for (int n = 0; n < g_nVariableCount; n++) - { - if (strName == g_Variables[n].m_strName) - g_Variables[n].m_fValue = fValue; - } -} - - - -void AddVectorVariable(const char* pName, const char* pInput = NULL) -{ - if (g_nVecVariableCount < MAX_VARIABLES) - { - g_VecVariables[g_nVecVariableCount].m_strName = pName; - g_VecVariables[g_nVecVariableCount].m_strName.MakeLower(); - if (pInput) - g_VecVariables[g_nVariableCount].m_strInput = pInput; - g_nVecVariableCount++; - } - else - gtk_MessageBox(g_pParentWnd->m_pWidget, "Maximum script variable limit reached!"); -} - -void VectorVariableValue(const char* pName, vec3_t& v) -{ - CString strName = pName; - strName.MakeLower(); - for (int n = 0; n < g_nVecVariableCount; n++) - { - if (strName == g_VecVariables[n].m_strName) - { - VectorCopy(g_VecVariables[n].m_vValue, v); - return; - } - } - strName.Format("Reference to non-existant variable %s", pName); - gtk_MessageBox(g_pParentWnd->m_pWidget, strName); -} - -void SetVectorVariableValue(const char* pName, vec3_t v) -{ - CString strName = pName; - strName.MakeLower(); - for (int n = 0; n < g_nVecVariableCount; n++) - { - if (strName == g_VecVariables[n].m_strName) - VectorCopy(v, g_VecVariables[n].m_vValue); - } -} - - - - - -// commands -// -// _CopySelected(nHoldPos) -// copies selected brush to hold spot 1, 2 or 3 -// -// _MoveSelected(x, y, z) -// moves selected brush by coords provided -// -// _RotateSelected(x, y, z) -// rotates selected brush by coords provided -// -// _MoveHold(nHoldPos, x, y, z) -// moves brush in hold pos by coords provided -// -// _RotateHold(nHoldPos, x, y, z) -// rotates brush in hold pos by coords provided -// -// _CopyToMap(nHoldPos) -// copies hold brush to map -// -// _CopyAndSelect(nHoldPos) -// copies hold brush to map and selects it -// -// _Input(VarName1, ... VarNamennn) -// inputs a list of values from the user -// - -typedef void (PFNScript)(char*&); - - -struct SBrushScript -{ - const char* m_pName; - PFNScript* m_pProc; -}; - - -const char* GetParam(char*& pBuffer) -{ - static CString strParam; - bool bStringMode = false; - - while (*pBuffer != (char)NULL && isspace(*pBuffer)) // skip and whitespace - pBuffer++; - - if (*pBuffer == '(') // if it's an opening paren, skip it - pBuffer++; - - if (*pBuffer == '\"') // string ? - { - pBuffer++; - bStringMode = true; - } - - strParam = ""; - - if (bStringMode) - { - while (*pBuffer != (char)NULL && *pBuffer != '\"') - strParam += *pBuffer++; - } - else - { - while (*pBuffer != (char)NULL && *pBuffer != ' ' && *pBuffer != ')' && *pBuffer != ',') - strParam += *pBuffer++; - } - - if (*pBuffer != (char)NULL) // skip last char - pBuffer++; - - if (strParam.GetLength() > 0) - { - if (strParam.GetAt(0) == '$') // ? variable name - { - float f = VariableValue(strParam); - if (f != g_fDefault) - strParam.Format("%f", f); - } - } - - return strParam; -} - -brush_t* CopyBrush(brush_t* p) -{ - brush_t* pCopy = Brush_Clone(p); - //Brush_AddToList (pCopy, &active_brushes); - //Entity_LinkBrush (world_entity, pCopy); - Brush_Build(pCopy, false); - - return pCopy; -} - - -void CopySelected(char*& pBuffer) -{ - // expects one param - CString strParam = GetParam(pBuffer); - int n = atoi(strParam); - - brush_t* pCopy = NULL; - if (selected_brushes.next != &selected_brushes && - selected_brushes.next->next == &selected_brushes) - pCopy = selected_brushes.next; - - if (pCopy) - { - if (n == 1) - { - //if (g_pHold1) - //Brush_Free(g_pHold1); - g_pHold1 = CopyBrush(pCopy); - } - else if (n == 2) - { - //if (g_pHold2) - //Brush_Free(g_pHold2); - g_pHold2 = CopyBrush(pCopy); - } - else - { - //if (g_pHold3) - //Brush_Free(g_pHold3); - g_pHold3 = CopyBrush(pCopy); - } - } -} - -void MoveSelected(char*& pBuffer) -{ - vec3_t v; - CString strParam = GetParam(pBuffer); - v[0] = atof(strParam); - strParam = GetParam(pBuffer); - v[1] = atof(strParam); - strParam = GetParam(pBuffer); - v[2] = atof(strParam); - Select_Move(v, false); - Sys_UpdateWindows(W_ALL); -} - -void RotateSelected(char*& pBuffer) -{ - vec3_t v; - - if (g_bRotateAroundSelection) - { - Select_GetTrueMid(v); - VectorCopy(v, g_pParentWnd->ActiveXY()->RotateOrigin()); - } - - CString strParam = GetParam(pBuffer); - v[0] = atof(strParam); - strParam = GetParam(pBuffer); - v[1] = atof(strParam); - strParam = GetParam(pBuffer); - v[2] = atof(strParam); - for (int i = 0; i < 3; i++) - if (v[i] != 0.0) - Select_RotateAxis(i, v[i], false , true); - Sys_UpdateWindows(W_ALL); -} - -void MoveHold(char*& pBuffer) -{ - CString strParam = GetParam(pBuffer); - brush_t* pBrush = NULL; - int nHold = atoi(strParam); - if (nHold == 1) - pBrush = g_pHold1; - else if (nHold == 2) - pBrush = g_pHold2; - else - pBrush = g_pHold3; - - if (pBrush) - { - vec3_t v; - strParam = GetParam(pBuffer); - v[0] = atof(strParam); - strParam = GetParam(pBuffer); - v[1] = atof(strParam); - strParam = GetParam(pBuffer); - v[2] = atof(strParam); - Brush_Move (pBrush, v, false); - } -} - -void RotateHold(char*& pBuffer) -{ - CString strParam = GetParam(pBuffer); - brush_t* pBrush = NULL; - int nHold = atoi(strParam); - if (nHold == 1) - pBrush = g_pHold1; - else if (nHold == 2) - pBrush = g_pHold2; - else - pBrush = g_pHold3; - - if (pBrush) - { - vec3_t v; - strParam = GetParam(pBuffer); - v[0] = atof(strParam); - strParam = GetParam(pBuffer); - v[1] = atof(strParam); - strParam = GetParam(pBuffer); - v[2] = atof(strParam); - for (int i = 0; i < 3; i++) - if (v[i] != 0.0) - Select_RotateAxis(i, v[i]); - } -} - -void CopyToMap(char*& pBuffer) -{ - CString strParam = GetParam(pBuffer); - brush_t* pBrush = NULL; - int nHold = atoi(strParam); - if (nHold == 1) - pBrush = g_pHold1; - else if (nHold == 2) - pBrush = g_pHold2; - else - pBrush = g_pHold3; - - if (pBrush) - { - Brush_AddToList(pBrush, &active_brushes); - Entity_LinkBrush (world_entity, pBrush); - Brush_Build(pBrush, false); - - Sys_UpdateWindows(W_ALL); - } -} - -void CopyAndSelect(char*& pBuffer) -{ - CString strParam = GetParam(pBuffer); - brush_t* pBrush = NULL; - int nHold = atoi(strParam); - if (nHold == 1) - pBrush = g_pHold1; - else if (nHold == 2) - pBrush = g_pHold2; - else - pBrush = g_pHold3; - - if (pBrush) - { - Select_Deselect(); - Brush_AddToList(pBrush, &active_brushes); - Entity_LinkBrush (world_entity, pBrush); - Brush_Build(pBrush, false); - - Select_Brush(pBrush); - Sys_UpdateWindows(W_ALL); - } -} - -void Input(char*& pBuffer) -{ - bool bGo = false; - const char *fields[5] = { "", "", "", "", "" }; - float values[5]; - - for (int n = 0; n < g_nVariableCount; n++) - { - if (g_Variables[n].m_strInput.GetLength() > 0) - { - bGo = true; - if (n < 5) - { - switch (n) - { - case 0 : fields[1] = g_Variables[n].m_strInput.GetBuffer (); break; - case 1 : fields[2] = g_Variables[n].m_strInput.GetBuffer (); break; - case 2 : fields[3] = g_Variables[n].m_strInput.GetBuffer (); break; - case 3 : fields[4] = g_Variables[n].m_strInput.GetBuffer (); break; - case 4 : fields[5] = g_Variables[n].m_strInput.GetBuffer (); break; - } - } - } - } - - if (bGo) - { - if (DoBSInputDlg (fields, values) == IDOK) - { - for (int n = 0; n < g_nVariableCount; n++) - { - if (g_Variables[n].m_strInput.GetLength() > 0) - { - if (n < 5) - { - switch (n) - { - case 0 : g_Variables[n].m_fValue = values[1]; break; - case 1 : g_Variables[n].m_fValue = values[2]; break; - case 2 : g_Variables[n].m_fValue = values[3]; break; - case 3 : g_Variables[n].m_fValue = values[4]; break; - case 4 : g_Variables[n].m_fValue = values[5]; break; - } - } - } - } - } - else g_bKeepGoing = false; - } -} - -bool g_bWaiting; -void _3DPointDone(bool b, int n) -{ - g_bWaiting = false; -} - -void _3DPointInput(char*& pBuffer) -{ - CString strParam = GetParam(pBuffer); - CString strParam2 = GetParam(pBuffer); - ShowInfoDialog(strParam2); - AddVectorVariable(strParam, strParam2); - g_bWaiting = true; - AcquirePath(2, &_3DPointDone); - while (g_bWaiting) - gtk_main_iteration (); - HideInfoDialog(); - SetVectorVariableValue(strParam, g_PathPoints[0]); -} - -void SetRotateOrigin(char*& pBuffer) -{ - vec3_t v; - CString strParam = GetParam(pBuffer); - VectorVariableValue(strParam, v); - VectorCopy(v, g_pParentWnd->ActiveXY()->RotateOrigin()); - g_bRotateAroundSelection = false; -} - -void InputVar(char*& pBuffer) -{ - CString strParam = GetParam(pBuffer); - CString strParam2 = GetParam(pBuffer); - AddVariable(strParam, 0.0, strParam2); -} - -void LoopCount(char*& pBuffer) -{ - CString strParam = GetParam(pBuffer); - g_nLoopCounter = atoi(strParam); - if (g_nLoopCounter == 0) - g_nLoopCounter = (int)VariableValue(strParam); - if (g_nLoopCounter > 0) - g_pLooper = pBuffer; -} - -void LoopRun(char*& pBuffer) -{ - if (g_bStartLoop == true) - { - g_nLoopCounter--; - if (g_nLoopCounter == 0) - { - g_bStartLoop = false; - GetParam(pBuffer); - } - else - pBuffer = g_pLooper; - } - else - { - if (g_pLooper && g_nLoopCounter > 0) - { - g_bStartLoop = true; - pBuffer = g_pLooper; - } - else - { - GetParam(pBuffer); - } - } -} - - -void ConfirmMessage(char*& pBuffer) -{ - CString strParam = GetParam(pBuffer); - if (gtk_MessageBox(g_pParentWnd->m_pWidget, strParam, "Script Info", MB_OKCANCEL) == IDCANCEL) - g_bKeepGoing = false; -} - -void Spherize(char*& pBuffer) -{ - g_bScreenUpdates = false; - for (int n = 0; n < 120; n += 36) - { - for (int i = 0; i < 360; i += 36) - { - Select_RotateAxis(0, i, false , true); - CSG_Subtract(); - } - Select_RotateAxis(2, n, false , true); - } - g_bScreenUpdates = true; -} - -void RunIt(char*& pBuffer); -SBrushScript g_ScriptCmds[] = -{ - {"_CopySelected", &CopySelected}, - {"_MoveSelected", &MoveSelected}, - {"_RotateSelected", &RotateSelected}, - {"_MoveHold", &MoveHold}, - {"_RotateHold", &RotateHold}, - {"_CopyToMap", &CopyToMap}, - {"_CopyAndSelect", &CopyAndSelect}, - {"_Input", &Input}, - {"_3DPointInput", &_3DPointInput}, - {"_SetRotateOrigin", &SetRotateOrigin}, - {"_InputVar", &InputVar}, - {"_LoopCount", &LoopCount}, - {"_LoopRun", &LoopRun}, - {"_ConfirmMessage", &ConfirmMessage}, - {"_Spherize", &Spherize}, - {"_RunScript", RunIt} -}; - -const int g_nScriptCmdCount = sizeof(g_ScriptCmds) / sizeof(SBrushScript); - -void RunScript(char* pBuffer) -{ - g_pHold1 = NULL; - g_pHold2 = NULL; - g_pHold3 = NULL; - - while (g_bKeepGoing && pBuffer && *pBuffer) - { - while (*pBuffer != (char)NULL && *pBuffer != '_') - pBuffer++; - - char* pTemp = pBuffer; - int nLen = 0; - while (*pTemp != (char)NULL && *pTemp != '(') - { - pTemp++; - nLen++; - } - if (*pBuffer != (char)NULL) - { - bool bFound = false; - for (int i = 0; i < g_nScriptCmdCount; i++) - { - //if (strnicmp(g_ScriptCmds[i].m_pName, pBuffer, strlen(g_ScriptCmds[i].m_pName)) == 0) - if (strnicmp(g_ScriptCmds[i].m_pName, pBuffer, nLen) == 0) - { - pBuffer += strlen(g_ScriptCmds[i].m_pName); - g_ScriptCmds[i].m_pProc(pBuffer); - if (g_bStartLoop) - { - } - bFound = true; - break; - } - } - if (!bFound) - pBuffer++; - } - } -} - - -void RunScriptByName(char* pBuffer, bool bInit) -{ - if (bInit) - InitForScriptRun(); - char* pScript = new char[4096]; - CString strINI; - strINI = g_strGameToolsPath; - strINI += "/scripts.ini"; - CString strScript; - FILE *f; - - f = fopen (strINI.GetBuffer(), "rt"); - if (f != NULL) - { - char line[1024], *ptr; - - // read section names - while (fgets (line, 1024, f) != 0) - { - if (line[0] != '[') - continue; - - ptr = strchr (line, ']'); - *ptr = '\0'; - - if (strcmp (line, pScript) == 0) - { - while (fgets (line, 1024, f) != 0) - { - if ((strchr (line, '=') == NULL) || - strlen (line) == 0) - break; - strScript += line; - } - break; - } - } - fclose (f); - } - RunScript((char*)strScript.GetBuffer()); -} - - -void RunIt(char*& pBuffer) -{ - brush_t* p1 = g_pHold1; - brush_t* p2 = g_pHold2; - brush_t* p3 = g_pHold3; - - CString strParam = GetParam(pBuffer); - RunScriptByName((char*)strParam.GetBuffer(), false); - - g_pHold3 = p3; - g_pHold2 = p2; - g_pHold1 = p1; -} - +/* +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 +*/ + +// BrushScript stuff +// + +/*! +\todo is this still used / in working state? +should we cleanup and remove it for good +*/ + +#include "stdafx.h" +#include "gtkmisc.h" + +// +struct SVariableDef +{ + CString m_strName; + CString m_strInput; + float m_fValue; +}; + +struct SVecVariableDef +{ + CString m_strName; + CString m_strInput; + vec3_t m_vValue; +}; + + + +const int MAX_VARIABLES = 64; + +brush_t* g_pHold1 = NULL; +brush_t* g_pHold2 = NULL; +brush_t* g_pHold3 = NULL; +bool g_bRotateAroundSelection; +int g_nVariableCount; +int g_nVecVariableCount; +int g_nLoopCounter; +float g_fDefault = 9999.9f; +vec3_t g_vDefault; +bool g_bStartLoop; +char* g_pLooper; +bool g_bKeepGoing; + +SVariableDef g_Variables[MAX_VARIABLES]; +SVecVariableDef g_VecVariables[MAX_VARIABLES]; + +void InitForScriptRun() +{ + g_pHold1 = NULL; + g_pHold2 = NULL; + g_pHold3 = NULL; + g_bRotateAroundSelection = true; + g_nVariableCount = 0; + g_nVecVariableCount = 0; + g_nLoopCounter = 0; + g_bStartLoop = false; + g_pLooper = NULL; + g_bKeepGoing = true; +} + +void AddVariable(const char* pName, float fValue, const char* pInput = NULL) +{ + if (g_nVariableCount < MAX_VARIABLES) + { + g_Variables[g_nVariableCount].m_strName = pName; + g_Variables[g_nVariableCount].m_strName.MakeLower(); + g_Variables[g_nVariableCount].m_fValue = fValue; + if (pInput) + g_Variables[g_nVariableCount].m_strInput = pInput; + g_nVariableCount++; + } + else + gtk_MessageBox(g_pParentWnd->m_pWidget, "Maximum script variable limit reached!"); +} + +float VariableValue(const char* pName) +{ + CString strName = pName; + strName.MakeLower(); + for (int n = 0; n < g_nVariableCount; n++) + { + if (strName == g_Variables[n].m_strName) + return g_Variables[n].m_fValue; + } + //strName.Format("Reference to non-existant varirable %s", pName); + //g_pParentWnd->MessageBox(strName); + return g_fDefault; +} + +void SetVariableValue(const char* pName, float fValue) +{ + CString strName = pName; + strName.MakeLower(); + for (int n = 0; n < g_nVariableCount; n++) + { + if (strName == g_Variables[n].m_strName) + g_Variables[n].m_fValue = fValue; + } +} + + + +void AddVectorVariable(const char* pName, const char* pInput = NULL) +{ + if (g_nVecVariableCount < MAX_VARIABLES) + { + g_VecVariables[g_nVecVariableCount].m_strName = pName; + g_VecVariables[g_nVecVariableCount].m_strName.MakeLower(); + if (pInput) + g_VecVariables[g_nVariableCount].m_strInput = pInput; + g_nVecVariableCount++; + } + else + gtk_MessageBox(g_pParentWnd->m_pWidget, "Maximum script variable limit reached!"); +} + +void VectorVariableValue(const char* pName, vec3_t& v) +{ + CString strName = pName; + strName.MakeLower(); + for (int n = 0; n < g_nVecVariableCount; n++) + { + if (strName == g_VecVariables[n].m_strName) + { + VectorCopy(g_VecVariables[n].m_vValue, v); + return; + } + } + strName.Format("Reference to non-existant variable %s", pName); + gtk_MessageBox(g_pParentWnd->m_pWidget, strName); +} + +void SetVectorVariableValue(const char* pName, vec3_t v) +{ + CString strName = pName; + strName.MakeLower(); + for (int n = 0; n < g_nVecVariableCount; n++) + { + if (strName == g_VecVariables[n].m_strName) + VectorCopy(v, g_VecVariables[n].m_vValue); + } +} + + + + + +// commands +// +// _CopySelected(nHoldPos) +// copies selected brush to hold spot 1, 2 or 3 +// +// _MoveSelected(x, y, z) +// moves selected brush by coords provided +// +// _RotateSelected(x, y, z) +// rotates selected brush by coords provided +// +// _MoveHold(nHoldPos, x, y, z) +// moves brush in hold pos by coords provided +// +// _RotateHold(nHoldPos, x, y, z) +// rotates brush in hold pos by coords provided +// +// _CopyToMap(nHoldPos) +// copies hold brush to map +// +// _CopyAndSelect(nHoldPos) +// copies hold brush to map and selects it +// +// _Input(VarName1, ... VarNamennn) +// inputs a list of values from the user +// + +typedef void (PFNScript)(char*&); + + +struct SBrushScript +{ + const char* m_pName; + PFNScript* m_pProc; +}; + + +const char* GetParam(char*& pBuffer) +{ + static CString strParam; + bool bStringMode = false; + + while (*pBuffer != (char)NULL && isspace(*pBuffer)) // skip and whitespace + pBuffer++; + + if (*pBuffer == '(') // if it's an opening paren, skip it + pBuffer++; + + if (*pBuffer == '\"') // string ? + { + pBuffer++; + bStringMode = true; + } + + strParam = ""; + + if (bStringMode) + { + while (*pBuffer != (char)NULL && *pBuffer != '\"') + strParam += *pBuffer++; + } + else + { + while (*pBuffer != (char)NULL && *pBuffer != ' ' && *pBuffer != ')' && *pBuffer != ',') + strParam += *pBuffer++; + } + + if (*pBuffer != (char)NULL) // skip last char + pBuffer++; + + if (strParam.GetLength() > 0) + { + if (strParam.GetAt(0) == '$') // ? variable name + { + float f = VariableValue(strParam); + if (f != g_fDefault) + strParam.Format("%f", f); + } + } + + return strParam; +} + +brush_t* CopyBrush(brush_t* p) +{ + brush_t* pCopy = Brush_Clone(p); + //Brush_AddToList (pCopy, &active_brushes); + //Entity_LinkBrush (world_entity, pCopy); + Brush_Build(pCopy, false); + + return pCopy; +} + + +void CopySelected(char*& pBuffer) +{ + // expects one param + CString strParam = GetParam(pBuffer); + int n = atoi(strParam); + + brush_t* pCopy = NULL; + if (selected_brushes.next != &selected_brushes && + selected_brushes.next->next == &selected_brushes) + pCopy = selected_brushes.next; + + if (pCopy) + { + if (n == 1) + { + //if (g_pHold1) + //Brush_Free(g_pHold1); + g_pHold1 = CopyBrush(pCopy); + } + else if (n == 2) + { + //if (g_pHold2) + //Brush_Free(g_pHold2); + g_pHold2 = CopyBrush(pCopy); + } + else + { + //if (g_pHold3) + //Brush_Free(g_pHold3); + g_pHold3 = CopyBrush(pCopy); + } + } +} + +void MoveSelected(char*& pBuffer) +{ + vec3_t v; + CString strParam = GetParam(pBuffer); + v[0] = atof(strParam); + strParam = GetParam(pBuffer); + v[1] = atof(strParam); + strParam = GetParam(pBuffer); + v[2] = atof(strParam); + Select_Move(v, false); + Sys_UpdateWindows(W_ALL); +} + +void RotateSelected(char*& pBuffer) +{ + vec3_t v; + + if (g_bRotateAroundSelection) + { + Select_GetTrueMid(v); + VectorCopy(v, g_pParentWnd->ActiveXY()->RotateOrigin()); + } + + CString strParam = GetParam(pBuffer); + v[0] = atof(strParam); + strParam = GetParam(pBuffer); + v[1] = atof(strParam); + strParam = GetParam(pBuffer); + v[2] = atof(strParam); + for (int i = 0; i < 3; i++) + if (v[i] != 0.0) + Select_RotateAxis(i, v[i], false , true); + Sys_UpdateWindows(W_ALL); +} + +void MoveHold(char*& pBuffer) +{ + CString strParam = GetParam(pBuffer); + brush_t* pBrush = NULL; + int nHold = atoi(strParam); + if (nHold == 1) + pBrush = g_pHold1; + else if (nHold == 2) + pBrush = g_pHold2; + else + pBrush = g_pHold3; + + if (pBrush) + { + vec3_t v; + strParam = GetParam(pBuffer); + v[0] = atof(strParam); + strParam = GetParam(pBuffer); + v[1] = atof(strParam); + strParam = GetParam(pBuffer); + v[2] = atof(strParam); + Brush_Move (pBrush, v, false); + } +} + +void RotateHold(char*& pBuffer) +{ + CString strParam = GetParam(pBuffer); + brush_t* pBrush = NULL; + int nHold = atoi(strParam); + if (nHold == 1) + pBrush = g_pHold1; + else if (nHold == 2) + pBrush = g_pHold2; + else + pBrush = g_pHold3; + + if (pBrush) + { + vec3_t v; + strParam = GetParam(pBuffer); + v[0] = atof(strParam); + strParam = GetParam(pBuffer); + v[1] = atof(strParam); + strParam = GetParam(pBuffer); + v[2] = atof(strParam); + for (int i = 0; i < 3; i++) + if (v[i] != 0.0) + Select_RotateAxis(i, v[i]); + } +} + +void CopyToMap(char*& pBuffer) +{ + CString strParam = GetParam(pBuffer); + brush_t* pBrush = NULL; + int nHold = atoi(strParam); + if (nHold == 1) + pBrush = g_pHold1; + else if (nHold == 2) + pBrush = g_pHold2; + else + pBrush = g_pHold3; + + if (pBrush) + { + Brush_AddToList(pBrush, &active_brushes); + Entity_LinkBrush (world_entity, pBrush); + Brush_Build(pBrush, false); + + Sys_UpdateWindows(W_ALL); + } +} + +void CopyAndSelect(char*& pBuffer) +{ + CString strParam = GetParam(pBuffer); + brush_t* pBrush = NULL; + int nHold = atoi(strParam); + if (nHold == 1) + pBrush = g_pHold1; + else if (nHold == 2) + pBrush = g_pHold2; + else + pBrush = g_pHold3; + + if (pBrush) + { + Select_Deselect(); + Brush_AddToList(pBrush, &active_brushes); + Entity_LinkBrush (world_entity, pBrush); + Brush_Build(pBrush, false); + + Select_Brush(pBrush); + Sys_UpdateWindows(W_ALL); + } +} + +void Input(char*& pBuffer) +{ + bool bGo = false; + const char *fields[5] = { "", "", "", "", "" }; + float values[5]; + + for (int n = 0; n < g_nVariableCount; n++) + { + if (g_Variables[n].m_strInput.GetLength() > 0) + { + bGo = true; + if (n < 5) + { + switch (n) + { + case 0 : fields[1] = g_Variables[n].m_strInput.GetBuffer (); break; + case 1 : fields[2] = g_Variables[n].m_strInput.GetBuffer (); break; + case 2 : fields[3] = g_Variables[n].m_strInput.GetBuffer (); break; + case 3 : fields[4] = g_Variables[n].m_strInput.GetBuffer (); break; + case 4 : fields[5] = g_Variables[n].m_strInput.GetBuffer (); break; + } + } + } + } + + if (bGo) + { + if (DoBSInputDlg (fields, values) == IDOK) + { + for (int n = 0; n < g_nVariableCount; n++) + { + if (g_Variables[n].m_strInput.GetLength() > 0) + { + if (n < 5) + { + switch (n) + { + case 0 : g_Variables[n].m_fValue = values[1]; break; + case 1 : g_Variables[n].m_fValue = values[2]; break; + case 2 : g_Variables[n].m_fValue = values[3]; break; + case 3 : g_Variables[n].m_fValue = values[4]; break; + case 4 : g_Variables[n].m_fValue = values[5]; break; + } + } + } + } + } + else g_bKeepGoing = false; + } +} + +bool g_bWaiting; +void _3DPointDone(bool b, int n) +{ + g_bWaiting = false; +} + +void _3DPointInput(char*& pBuffer) +{ + CString strParam = GetParam(pBuffer); + CString strParam2 = GetParam(pBuffer); + ShowInfoDialog(strParam2); + AddVectorVariable(strParam, strParam2); + g_bWaiting = true; + AcquirePath(2, &_3DPointDone); + while (g_bWaiting) + gtk_main_iteration (); + HideInfoDialog(); + SetVectorVariableValue(strParam, g_PathPoints[0]); +} + +void SetRotateOrigin(char*& pBuffer) +{ + vec3_t v; + CString strParam = GetParam(pBuffer); + VectorVariableValue(strParam, v); + VectorCopy(v, g_pParentWnd->ActiveXY()->RotateOrigin()); + g_bRotateAroundSelection = false; +} + +void InputVar(char*& pBuffer) +{ + CString strParam = GetParam(pBuffer); + CString strParam2 = GetParam(pBuffer); + AddVariable(strParam, 0.0, strParam2); +} + +void LoopCount(char*& pBuffer) +{ + CString strParam = GetParam(pBuffer); + g_nLoopCounter = atoi(strParam); + if (g_nLoopCounter == 0) + g_nLoopCounter = (int)VariableValue(strParam); + if (g_nLoopCounter > 0) + g_pLooper = pBuffer; +} + +void LoopRun(char*& pBuffer) +{ + if (g_bStartLoop == true) + { + g_nLoopCounter--; + if (g_nLoopCounter == 0) + { + g_bStartLoop = false; + GetParam(pBuffer); + } + else + pBuffer = g_pLooper; + } + else + { + if (g_pLooper && g_nLoopCounter > 0) + { + g_bStartLoop = true; + pBuffer = g_pLooper; + } + else + { + GetParam(pBuffer); + } + } +} + + +void ConfirmMessage(char*& pBuffer) +{ + CString strParam = GetParam(pBuffer); + if (gtk_MessageBox(g_pParentWnd->m_pWidget, strParam, "Script Info", MB_OKCANCEL) == IDCANCEL) + g_bKeepGoing = false; +} + +void Spherize(char*& pBuffer) +{ + g_bScreenUpdates = false; + for (int n = 0; n < 120; n += 36) + { + for (int i = 0; i < 360; i += 36) + { + Select_RotateAxis(0, i, false , true); + CSG_Subtract(); + } + Select_RotateAxis(2, n, false , true); + } + g_bScreenUpdates = true; +} + +void RunIt(char*& pBuffer); +SBrushScript g_ScriptCmds[] = +{ + {"_CopySelected", &CopySelected}, + {"_MoveSelected", &MoveSelected}, + {"_RotateSelected", &RotateSelected}, + {"_MoveHold", &MoveHold}, + {"_RotateHold", &RotateHold}, + {"_CopyToMap", &CopyToMap}, + {"_CopyAndSelect", &CopyAndSelect}, + {"_Input", &Input}, + {"_3DPointInput", &_3DPointInput}, + {"_SetRotateOrigin", &SetRotateOrigin}, + {"_InputVar", &InputVar}, + {"_LoopCount", &LoopCount}, + {"_LoopRun", &LoopRun}, + {"_ConfirmMessage", &ConfirmMessage}, + {"_Spherize", &Spherize}, + {"_RunScript", RunIt} +}; + +const int g_nScriptCmdCount = sizeof(g_ScriptCmds) / sizeof(SBrushScript); + +void RunScript(char* pBuffer) +{ + g_pHold1 = NULL; + g_pHold2 = NULL; + g_pHold3 = NULL; + + while (g_bKeepGoing && pBuffer && *pBuffer) + { + while (*pBuffer != (char)NULL && *pBuffer != '_') + pBuffer++; + + char* pTemp = pBuffer; + int nLen = 0; + while (*pTemp != (char)NULL && *pTemp != '(') + { + pTemp++; + nLen++; + } + if (*pBuffer != (char)NULL) + { + bool bFound = false; + for (int i = 0; i < g_nScriptCmdCount; i++) + { + //if (strnicmp(g_ScriptCmds[i].m_pName, pBuffer, strlen(g_ScriptCmds[i].m_pName)) == 0) + if (strnicmp(g_ScriptCmds[i].m_pName, pBuffer, nLen) == 0) + { + pBuffer += strlen(g_ScriptCmds[i].m_pName); + g_ScriptCmds[i].m_pProc(pBuffer); + if (g_bStartLoop) + { + } + bFound = true; + break; + } + } + if (!bFound) + pBuffer++; + } + } +} + + +void RunScriptByName(char* pBuffer, bool bInit) +{ + if (bInit) + InitForScriptRun(); + char* pScript = new char[4096]; + CString strINI; + strINI = g_strGameToolsPath; + strINI += "/scripts.ini"; + CString strScript; + FILE *f; + + f = fopen (strINI.GetBuffer(), "rt"); + if (f != NULL) + { + char line[1024], *ptr; + + // read section names + while (fgets (line, 1024, f) != 0) + { + if (line[0] != '[') + continue; + + ptr = strchr (line, ']'); + *ptr = '\0'; + + if (strcmp (line, pScript) == 0) + { + while (fgets (line, 1024, f) != 0) + { + if ((strchr (line, '=') == NULL) || + strlen (line) == 0) + break; + strScript += line; + } + break; + } + } + fclose (f); + } + RunScript((char*)strScript.GetBuffer()); +} + + +void RunIt(char*& pBuffer) +{ + brush_t* p1 = g_pHold1; + brush_t* p2 = g_pHold2; + brush_t* p3 = g_pHold3; + + CString strParam = GetParam(pBuffer); + RunScriptByName((char*)strParam.GetBuffer(), false); + + g_pHold3 = p3; + g_pHold2 = p2; + g_pHold1 = p1; +} + diff --git a/radiant/camwindow.cpp b/radiant/camwindow.cpp index 09edb418..42a569b3 100644 --- a/radiant/camwindow.cpp +++ b/radiant/camwindow.cpp @@ -1,1700 +1,1700 @@ -/* -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 -*/ - -// -// Camera Window -// -// Leonardo Zide (leo@lokigames.com) -// - -#include "stdafx.h" -#include -#include - -extern void DrawPathLines(); -extern void Select_ShiftTexture(int x, int y); -extern void Select_RotateTexture(int amt); -extern void DrawAlternatePoint(vec3_t v, float scale); -//extern void Select_ScaleTexture(int x, int y); - -extern int g_nPatchClickedView; - -brush_t* g_pSplitList = NULL; - -// ============================================================================= -// CamWnd class - -CamWnd::CamWnd () - : GLWindow (TRUE), m_XORRectangle(m_pWidget) -{ - m_nNumTransBrushes = 0; - memset(&m_Camera, 0, sizeof(camera_t)); - m_pSide_select = NULL; - m_bClipMode = false; - m_bFreeMove = false; - Cam_Init(); -} - -CamWnd::~CamWnd () -{ -} - -void CamWnd::OnCreate () -{ - if (!MakeCurrent ()) - Error ("glMakeCurrent failed"); - - gtk_glwidget_create_font (m_pWidget); - - // report OpenGL information - Sys_Printf ("GL_VENDOR: %s\n", qglGetString (GL_VENDOR)); - Sys_Printf ("GL_RENDERER: %s\n", qglGetString (GL_RENDERER)); - Sys_Printf ("GL_VERSION: %s\n", qglGetString (GL_VERSION)); - Sys_Printf ("GL_EXTENSIONS: %s\n", qglGetString (GL_EXTENSIONS)); - - // Set off texture compression supported - g_qeglobals.bTextureCompressionSupported = 0; - - // finalize OpenGL init - // NOTE - // why is this here? well .. the Gtk objects get constructed when you enter gtk_main - // and I wanted to have the extensions information in the editor startup console (avoid looking that up in the early console) - // RIANT - // I Split this up so as to add support for extension and user-friendly - // compression format selection. - // ADD new globals for your new format so as to minimise - // calls to Sys_QGL_ExtensionSupported - // NOTE TTimo: I don't really like this approach with globals. Frequent calls to Sys_QGL_ExtensionSupported don't sound like - // a problem to me. If there is some caching to be done, then I think it should be inside Sys_QGL_ExtensionSupported - /////////////////////////////////////////// - // Check for default OpenGL - if (Sys_QGL_ExtensionSupported ("GL_ARB_texture_compression")) - { - g_qeglobals.bTextureCompressionSupported = 1; - g_qeglobals.m_bOpenGLCompressionSupported = 1; - } - - // INSERT PROPRIETARY EXTENSIONS HERE - // Check for S3 extensions - // create a bool global for extension supported - if (Sys_QGL_ExtensionSupported ("GL_EXT_texture_compression_s3tc")) - { - g_qeglobals.bTextureCompressionSupported = 1; - g_qeglobals.m_bS3CompressionSupported = 1; - } - - g_qeglobals.m_bOpenGLReady = true; - - g_PrefsDlg.UpdateTextureCompression(); - -#ifdef ATIHACK_812 - g_PrefsDlg.UpdateATIHack(); -#endif - - g_qeglobals_gui.d_camera = m_pWidget; -} - -void CamWnd::Cam_Init () -{ - m_Camera.timing = false; - m_Camera.origin[0] = 0.f; - m_Camera.origin[1] = 20.f; - m_Camera.origin[2] = 46.f; - m_Camera.color[0] = 0.3f; - m_Camera.color[1] = 0.3f; - m_Camera.color[2] = 0.3f; - m_nCambuttonstate = 0; -} - -void CamWnd::OnSize(int cx, int cy) -{ - m_Camera.width = cx; - m_Camera.height = cy; - gtk_widget_queue_draw(m_pWidget); -} - -rectangle_t rectangle_from_area_cam() -{ - const float left = MIN(g_qeglobals.d_vAreaTL[0], g_qeglobals.d_vAreaBR[0]); - const float top = MAX(g_qeglobals.d_vAreaTL[1], g_qeglobals.d_vAreaBR[1]); - const float right = MAX(g_qeglobals.d_vAreaTL[0], g_qeglobals.d_vAreaBR[0]); - const float bottom = MIN(g_qeglobals.d_vAreaTL[1], g_qeglobals.d_vAreaBR[1]); - return rectangle_t(left, bottom, right - left, top - bottom); -} - -void update_xor_rectangle(XORRectangle& xor_rectangle) -{ - rectangle_t rectangle; - if ((g_qeglobals.d_select_mode == sel_area)) - rectangle = rectangle_from_area_cam(); - xor_rectangle.set(rectangle); -} - -void CamWnd::OnMouseMove(guint32 flags, int pointx, int pointy) -{ - int height = m_pWidget->allocation.height; - // NOTE RR2DO2 this hasn't got any use anymore really. It is an old qeradiant feature - // that can be re-enabled by removing the checks for HasCapture and not shift/ctrl down - // but the scaling/rotating (unless done with the steps set in the surface inspector - // dialog) is way too sensitive to be of any use - if (HasCapture () && Sys_AltDown () && - !((flags & MK_SHIFT) || (flags & MK_CONTROL))) - { - if (flags & MK_CONTROL) - Select_RotateTexture(pointy - m_ptLastCursorY); - else - if (flags & MK_SHIFT) - Select_ScaleTexture(pointx - m_ptLastCursorX, m_ptLastCursorY - pointy); - else - Select_ShiftTexture(pointx - m_ptLastCursorX, m_ptLastCursorY - pointy); - } - else - { - Cam_MouseMoved(pointx, height - 1 - pointy, flags); - } - m_ptLastCursorX = pointx; - m_ptLastCursorY = pointy; - - update_xor_rectangle(m_XORRectangle); -} - -void CamWnd::OnMouseWheel(bool bUp) -{ - if (bUp) - VectorMA (m_Camera.origin, g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin); - else - VectorMA (m_Camera.origin, -g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin); - - int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); - Sys_UpdateWindows (nUpdate); - g_pParentWnd->OnTimer (); -} - -void CamWnd::OnLButtonDown(guint32 nFlags, int pointx, int pointy) -{ - m_ptLastCursorX = pointx; - m_ptLastCursorY = pointy; - OriginalMouseDown(nFlags, pointx, pointy); -} - -void CamWnd::OnLButtonUp(guint32 nFlags, int pointx, int pointy) -{ - OriginalMouseUp(nFlags, pointx, pointy); -} - -void CamWnd::OnMButtonDown(guint32 nFlags, int pointx, int pointy) -{ - OriginalMouseDown(nFlags, pointx, pointy); -} - -void CamWnd::OnMButtonUp(guint32 nFlags, int pointx, int pointy) -{ - OriginalMouseUp(nFlags, pointx, pointy); -} - -void CamWnd::OnRButtonDown(guint32 nFlags, int pointx, int pointy) -{ - OriginalMouseDown(nFlags, pointx, pointy); -} - -void CamWnd::OnRButtonUp(guint32 nFlags, int pointx, int pointy) -{ - OriginalMouseUp(nFlags, pointx, pointy); -} - -void CamWnd::OriginalMouseUp(guint32 nFlags, int pointx, int pointy) -{ - int height = m_pWidget->allocation.height; - - if(g_qeglobals.d_select_mode == sel_facets_on || g_qeglobals.d_select_mode == sel_facets_off) - { - g_qeglobals.d_select_mode = sel_brush; - } - - Cam_MouseUp(pointx, height - 1 - pointy, nFlags); - ReleaseCapture (); - - update_xor_rectangle(m_XORRectangle); -} - -void CamWnd::OriginalMouseDown(guint32 nFlags, int pointx, int pointy) -{ - int height = m_pWidget->allocation.height; - - SetFocus(); - SetCapture(); - Cam_MouseDown (pointx, height - 1 - pointy, nFlags); - - update_xor_rectangle(m_XORRectangle); -} - -void CamWnd::Cam_BuildMatrix() -{ - float ya; - float matrix[4][4]; - int i; - - if (!m_bFreeMove) - { - ya = m_Camera.angles[1]/180*Q_PI; - - // the movement matrix is kept 2d - m_Camera.forward[0] = cos(ya); - m_Camera.forward[1] = sin(ya); - m_Camera.forward[2] = 0; - m_Camera.right[0] = m_Camera.forward[1]; - m_Camera.right[1] = -m_Camera.forward[0]; - } - else - { - AngleVectors( m_Camera.angles, m_Camera.forward, m_Camera.right, NULL ); - m_Camera.forward[2] = -m_Camera.forward[2]; - } - - memcpy(matrix, m_Camera.projection, sizeof(m4x4_t)); - m4x4_multiply_by_m4x4(&matrix[0][0], &m_Camera.modelview[0][0]); - - //qglGetFloatv (GL_PROJECTION_MATRIX, &matrix[0][0]); - - for (i=0 ; i<3 ; i++) - { - m_Camera.vright[i] = matrix[i][0]; - m_Camera.vup[i] = matrix[i][1]; - m_Camera.vpn[i] = matrix[i][2]; - } - - VectorNormalize (m_Camera.vright, m_Camera.vright); - VectorNormalize (m_Camera.vup, m_Camera.vup); - VectorNormalize (m_Camera.vpn, m_Camera.vpn); -} - -void CamWnd::Cam_ChangeFloor (qboolean up) -{ - brush_t *b; - float d, bestd, current; - vec3_t start, dir; - - start[0] = m_Camera.origin[0]; - start[1] = m_Camera.origin[1]; - start[2] = g_MaxWorldCoord; - dir[0] = dir[1] = 0; - dir[2] = -1; - - current = g_MaxWorldCoord - (m_Camera.origin[2] - 48); - if (up) - bestd = 0; - else - bestd = 2*g_MaxWorldCoord; - - for (b=active_brushes.next ; b != &active_brushes ; b=b->next) - { - if (!Brush_Ray (start, dir, b, &d)) - continue; - if (up && d < current && d > bestd) - bestd = d; - if (!up && d > current && d < bestd) - bestd = d; - } - - if (bestd == 0 || bestd == 2*g_MaxWorldCoord) - return; - - m_Camera.origin[2] += current - bestd; - Sys_UpdateWindows (W_CAMERA|W_Z_OVERLAY); -} - -void CamWnd::Cam_PositionDrag() -{ - int x, y; - - Sys_GetCursorPos (&x, &y); - if (x != m_ptCursorX || y != m_ptCursorY) - { - x -= m_ptCursorX; - VectorMA (m_Camera.origin, x, m_Camera.vright, m_Camera.origin); - y -= m_ptCursorY; - m_Camera.origin[2] -= y; - Sys_SetCursorPos(m_ptCursorX, m_ptCursorY); - Sys_UpdateWindows (W_CAMERA | W_XY_OVERLAY); - } -} - -void CamWnd::Cam_MouseControl (float dtime) -{ - Cam_KeyControl (dtime); - - if( g_PrefsDlg.m_bCamFreeLook ) - { - int dx, dy; - gint x, y; - - if( !m_bFreeMove || m_nCambuttonstate == MK_CONTROL ) - return; - - // Update angles - Sys_GetCursorPos(&m_ptCursorX, &m_ptCursorY); - - dx = m_ptLastCamCursorX - m_ptCursorX; - dy = m_ptLastCamCursorY - m_ptCursorY; - - gdk_window_get_origin( m_pWidget->window, &x, &y); - - m_ptLastCamCursorX = x + (m_Camera.width / 2); - m_ptLastCamCursorY = y + (m_Camera.height / 2); - - Sys_SetCursorPos(m_ptLastCamCursorX, m_ptLastCamCursorY); - - // Don't use pitch - if(!g_PrefsDlg.m_bCamFreeLookStrafe) { - if (g_PrefsDlg.m_bCamInverseMouse) - m_Camera.angles[PITCH] -= dy * dtime * g_PrefsDlg.m_nAngleSpeed; - else - m_Camera.angles[PITCH] += dy * dtime * g_PrefsDlg.m_nAngleSpeed; - } else { - VectorMA (m_Camera.origin, dy * (float) (g_PrefsDlg.m_nMoveSpeed / 6.0f), m_Camera.forward, m_Camera.origin); - } - - m_Camera.angles[YAW] += dx * dtime * g_PrefsDlg.m_nAngleSpeed; - - if (m_Camera.angles[PITCH] > 90) - m_Camera.angles[PITCH] = 90; - else if (m_Camera.angles[PITCH] < -90) - m_Camera.angles[PITCH] = -90; - - if (m_Camera.angles[YAW] >= 360) - m_Camera.angles[YAW] = 0; - else if (m_Camera.angles[YAW] <= -360) - m_Camera.angles[YAW] = 0; - - if( dx || dy || m_Camera.movementflags ) - { - int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); - Sys_UpdateWindows (nUpdate); - g_pParentWnd->OnTimer (); - } - } - else - { - int xl, xh; - int yl, yh; - float xf, yf; - - if (g_PrefsDlg.m_nMouseButtons == 2) - { - if (m_nCambuttonstate != (MK_RBUTTON | MK_SHIFT)) - return; - } - else - { - if (m_nCambuttonstate != MK_RBUTTON) - return; - } - - xf = (float)(m_ptButtonX - m_Camera.width/2) / (m_Camera.width/2); - yf = (float)(m_ptButtonY - m_Camera.height/2) / (m_Camera.height/2); - - xl = m_Camera.width/3; - xh = xl*2; - yl = m_Camera.height/3; - yh = yl*2; - - xf *= 1.0 - fabs(yf); - if (xf < 0) - { - xf += 0.1f; - if (xf > 0) - xf = 0; - } - else - { - xf -= 0.1f; - if (xf < 0) - xf = 0; - } - - VectorMA (m_Camera.origin, yf*dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin); - m_Camera.angles[YAW] += xf*-dtime*g_PrefsDlg.m_nAngleSpeed; - - int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); - Sys_UpdateWindows (nUpdate); - g_pParentWnd->OnTimer (); - } -} - -void CamWnd::Cam_KeyControl (float dtime) { - - // Update angles - if (m_Camera.movementflags & MOVE_ROTLEFT) - m_Camera.angles[YAW] += 15*dtime*g_PrefsDlg.m_nAngleSpeed; - if (m_Camera.movementflags & MOVE_ROTRIGHT) - m_Camera.angles[YAW] -= 15*dtime*g_PrefsDlg.m_nAngleSpeed; - - // Update position - if (m_Camera.movementflags & MOVE_FORWARD) - VectorMA (m_Camera.origin, dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin); - if (m_Camera.movementflags & MOVE_BACK) - VectorMA (m_Camera.origin, -dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin); - if (m_Camera.movementflags & MOVE_STRAFELEFT) - VectorMA (m_Camera.origin, -dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.right, m_Camera.origin); - if (m_Camera.movementflags & MOVE_STRAFERIGHT) - VectorMA (m_Camera.origin, dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.right, m_Camera.origin); - - // Save a screen update (when m_bFreeMove is enabled, mousecontrol does the update) - if( !m_bFreeMove && m_Camera.movementflags ) - { - int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); - Sys_UpdateWindows (nUpdate); - g_pParentWnd->OnTimer (); - } -} - -// NOTE TTimo if there's an OS-level focus out of the application -// then we can release the camera cursor grab -static gint camwindow_focusout(GtkWidget* widget, GdkEventKey* event, gpointer data) -{ - g_pParentWnd->GetCamWnd ()->ToggleFreeMove(); - return FALSE; -} - -void CamWnd::ToggleFreeMove() -{ - GdkWindow *window; - GtkWidget *widget; - - m_bFreeMove = !m_bFreeMove; - Camera()->movementflags = 0; - m_ptLastCamCursorX = m_ptCursorX; - m_ptLastCamCursorY = m_ptCursorY; - - if (g_pParentWnd->CurrentStyle() == MainFrame::eFloating) - { - widget = g_pParentWnd->GetCamWnd ()->m_pParent; - window = widget->window; - } - else - { - widget = g_pParentWnd->m_pWidget; - window = widget->window; - } - - if (m_bFreeMove) - { - - SetFocus(); - SetCapture(); - - { - GdkPixmap *pixmap; - GdkBitmap *mask; - char buffer [(32 * 32)/8]; - memset (buffer, 0, (32 * 32)/8); - GdkColor white = {0, 0xffff, 0xffff, 0xffff}; - GdkColor black = {0, 0x0000, 0x0000, 0x0000}; - pixmap = gdk_bitmap_create_from_data (NULL, buffer, 32, 32); - mask = gdk_bitmap_create_from_data (NULL, buffer, 32, 32); - GdkCursor *cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &white, &black, 1, 1); - - gdk_window_set_cursor (window, cursor); - gdk_cursor_unref (cursor); - gdk_drawable_unref (pixmap); - gdk_drawable_unref (mask); - } - - // RR2DO2: FIXME why does this only work the 2nd and - // further times the event is called? (floating windows - // mode seems to work fine though...) - m_FocusOutHandler_id = gtk_signal_connect (GTK_OBJECT (widget), "focus_out_event", - GTK_SIGNAL_FUNC (camwindow_focusout), g_pParentWnd); - - { - GdkEventMask mask = (GdkEventMask)(GDK_POINTER_MOTION_MASK - | GDK_POINTER_MOTION_HINT_MASK - | GDK_BUTTON_MOTION_MASK - | GDK_BUTTON1_MOTION_MASK - | GDK_BUTTON2_MOTION_MASK - | GDK_BUTTON3_MOTION_MASK - | GDK_BUTTON_PRESS_MASK - | GDK_BUTTON_RELEASE_MASK); - - gdk_pointer_grab(widget->window, TRUE, mask, widget->window, NULL, GDK_CURRENT_TIME); - } - } - else - { - gdk_pointer_ungrab(GDK_CURRENT_TIME); - - gtk_signal_disconnect (GTK_OBJECT (widget), m_FocusOutHandler_id); - - GdkCursor *cursor = gdk_cursor_new (GDK_LEFT_PTR); - gdk_window_set_cursor (window, cursor); - gdk_cursor_unref (cursor); - - ReleaseCapture(); - } - - int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); - Sys_UpdateWindows (nUpdate); - g_pParentWnd->OnTimer (); -} - -void CamWnd::Cam_MouseDown(int x, int y, int buttons) -{ - vec3_t dir; - float f, r, u; - int i; - - - // - // calc ray direction - // - u = (float)( y - ( m_Camera.height * .5f ) ) / ( m_Camera.width * .5f ); - r = (float)( x - ( m_Camera.width * .5f ) ) / ( m_Camera.width * .5f ); - f = 1; - - for (i=0 ; i<3 ; i++) - dir[i] = m_Camera.vpn[i] * f + m_Camera.vright[i] * r + m_Camera.vup[i] * u; - VectorNormalize (dir, dir); - - Sys_GetCursorPos(&m_ptCursorX, &m_ptCursorY); - - m_nCambuttonstate = buttons; - m_ptButtonX = x; - m_ptButtonY = y; - - // LBUTTON = manipulate selection - // shift-LBUTTON = select - // middle button = grab texture - // ctrl-middle button = set entire brush to texture - // ctrl-shift-middle button = set single face to texture - int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON; - if ((buttons == MK_LBUTTON) - || (buttons == (MK_LBUTTON | MK_SHIFT)) - || (buttons == (MK_LBUTTON | MK_CONTROL)) - || (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) - || (buttons == nMouseButton) - || (buttons == (nMouseButton|MK_SHIFT)) - || (buttons == (nMouseButton|MK_CONTROL)) - || (buttons == (nMouseButton|MK_SHIFT|MK_CONTROL))) - { - if (g_PrefsDlg.m_nMouseButtons == 2 && (buttons == (MK_RBUTTON | MK_SHIFT))) - { - if (g_PrefsDlg.m_bCamFreeLook) - ToggleFreeMove(); - else - Cam_MouseControl (0.1f); - } - else - { - // something global needs to track which window is responsible for stuff - Patch_SetView(W_CAMERA); - Drag_Begin (x, y, buttons, m_Camera.vright, m_Camera.vup, m_Camera.origin, dir, true); - } - return; - } - - if (buttons == MK_RBUTTON) - { - if (g_PrefsDlg.m_bCamFreeLook) - ToggleFreeMove(); - else - Cam_MouseControl (0.1f); - return; - } -} - -void CamWnd::Cam_MouseUp (int x, int y, int buttons) -{ - m_nCambuttonstate = 0; - Drag_MouseUp (buttons); -} - -void CamWnd::Cam_MouseMoved (int x, int y, int buttons) -{ - m_nCambuttonstate = buttons; - if (!buttons) - return; - - if( g_PrefsDlg.m_nCamDragMultiSelect ) - { - if (g_qeglobals.d_select_mode == sel_brush_on || g_qeglobals.d_select_mode == sel_brush_off) - { - bool bDoDragMultiSelect = FALSE; - - if( g_PrefsDlg.m_nCamDragMultiSelect == 1 && buttons == (MK_LBUTTON|MK_SHIFT) ) - bDoDragMultiSelect = TRUE; - else if( g_PrefsDlg.m_nCamDragMultiSelect == 2 && buttons == (MK_LBUTTON|MK_CONTROL) && Sys_AltDown() ) - bDoDragMultiSelect = TRUE; - - if( bDoDragMultiSelect ) - { - vec3_t dir; - float f, r, u; - int i; - - // - // calc ray direction - // - u = (float)( y - ( m_Camera.height * .5f ) ) / ( m_Camera.width * .5f ); - r = (float)( x - ( m_Camera.width * .5f ) ) / ( m_Camera.width * .5f ); - f = 1; - - for (i=0 ; i<3 ; i++) - dir[i] = m_Camera.vpn[i] * f + m_Camera.vright[i] * r + m_Camera.vup[i] * u; - VectorNormalize (dir,dir); - - switch( g_qeglobals.d_select_mode ) - { - case sel_brush_on: - Select_Ray( m_Camera.origin, dir, (SF_DRAG_ON|SF_CAMERA) ); - break; - - case sel_brush_off: - Select_Ray( m_Camera.origin, dir, (SF_DRAG_OFF|SF_CAMERA) ); - break; - - default: - break; - } - return; - } - } - else if (g_qeglobals.d_select_mode == sel_facets_on || g_qeglobals.d_select_mode == sel_facets_off) - { - if( buttons == (MK_LBUTTON|MK_CONTROL|MK_SHIFT) ) - { - vec3_t dir; - float f, r, u; - int i; - - // - // calc ray direction - // - u = (float)( y - ( m_Camera.height * .5f ) ) / ( m_Camera.width * .5f ); - r = (float)( x - ( m_Camera.width * .5f ) ) / ( m_Camera.width * .5f ); - f = 1; - - for (i=0 ; i<3 ; i++) - dir[i] = m_Camera.vpn[i] * f + m_Camera.vright[i] * r + m_Camera.vup[i] * u; - VectorNormalize (dir,dir); - - switch( g_qeglobals.d_select_mode ) - { - case sel_facets_on: - Select_Ray( m_Camera.origin, dir, (SF_SINGLEFACE|SF_DRAG_ON|SF_CAMERA) ); - break; - - case sel_facets_off: - Select_Ray( m_Camera.origin, dir, (SF_SINGLEFACE|SF_DRAG_OFF|SF_CAMERA) ); - break; - - default: - break; - } - return; - } - } - } - - m_ptButtonX = x; - m_ptButtonY = y; - - if ( (m_bFreeMove && (buttons & MK_CONTROL) && !(buttons & MK_SHIFT)) || (!m_bFreeMove && (buttons == (MK_RBUTTON|MK_CONTROL))) ) - { - Cam_PositionDrag (); - Sys_UpdateWindows (W_XY|W_CAMERA|W_Z); - return; - } - - Sys_GetCursorPos(&m_ptCursorX, &m_ptCursorY); - - if (buttons & (MK_LBUTTON | MK_MBUTTON) ) - { - Drag_MouseMoved (x, y, buttons); - if(g_qeglobals.d_select_mode != sel_area) - Sys_UpdateWindows (W_XY|W_CAMERA|W_Z); - } -} - -void CamWnd::InitCull() -{ - int i; - - VectorSubtract (m_Camera.vpn, m_Camera.vright, m_vCull1); - VectorAdd (m_Camera.vpn, m_Camera.vright, m_vCull2); - - for (i=0 ; i<3 ; i++) - { - if (m_vCull1[i] > 0) - m_nCullv1[i] = 3+i; - else - m_nCullv1[i] = i; - if (m_vCull2[i] > 0) - m_nCullv2[i] = 3+i; - else - m_nCullv2[i] = i; - } -} - -qboolean CamWnd::CullBrush (brush_t *b) -{ - int i; - vec3_t point; - float d; - - if (g_PrefsDlg.m_bCubicClipping) - { - float fLevel = g_PrefsDlg.m_nCubicScale * 64; - - point[0] = m_Camera.origin[0] - fLevel; - point[1] = m_Camera.origin[1] - fLevel; - point[2] = m_Camera.origin[2] - fLevel; - - for (i=0; i<3; i++) - if (b->mins[i] < point[i] && b->maxs[i] < point[i]) - return true; - - point[0] = m_Camera.origin[0] + fLevel; - point[1] = m_Camera.origin[1] + fLevel; - point[2] = m_Camera.origin[2] + fLevel; - - for (i=0; i<3; i++) - if (b->mins[i] > point[i] && b->maxs[i] > point[i]) - return true; - } - - for (i=0 ; i<3 ; i++) - point[i] = b->mins[m_nCullv1[i]] - m_Camera.origin[i]; - - d = DotProduct (point, m_vCull1); - if (d < -1) - return true; - - for (i=0 ; i<3 ; i++) - point[i] = b->mins[m_nCullv2[i]] - m_Camera.origin[i]; - - d = DotProduct (point, m_vCull2); - if (d < -1) - return true; - - return false; -} - -// project a 3D point onto the camera space -// we use the GL viewing matrixes -// this is the implementation of a glu function (I realized that afterwards): gluProject -void CamWnd::ProjectCamera(const vec3_t A, vec_t B[2]) -{ - - vec_t P1[4],P2[4],P3[4]; - VectorCopy(A,P1); P1[3] = 1; - - GLMatMul(m_Camera.modelview , P1, P2); - GLMatMul(m_Camera.projection, P2, P3); - - // we ASSUME that the view port is 0 0 m_Camera.width m_Camera.height (you can check in Cam_Draw) - B[0] = (float)m_Camera.width * ( P3[0] + 1.0 ) / 2.0; - B[1] = (float)m_Camera.height * ( P3[1] + 1.0 ) / 2.0; - -} - -// vec defines a direction in geometric space and P an origin point -// the user is interacting from the camera view -// (for example with texture adjustment shortcuts) -// and intuitively if he hits left / right / up / down -// what happens in geometric space should match the left/right/up/down move in camera space -// axis = 0: vec is along left/right -// axis = 1: vec is along up/down -// sgn = +1: same directions -// sgn = -1: opposite directions -// Implementation: -// typical use case is giving a face center and a normalized vector -// 1) compute start and endpoint, project them in camera view, get the direction -// depending on the situation, we might bump into precision issues with that -// 2) possible to compute the projected direction independently? -// this solution would be better but right now I don't see how to do it.. -void CamWnd::MatchViewAxes(const vec3_t P, const vec3_t vec, int &axis, float &sgn) -{ - - vec_t A[2],B[2],V[2]; - ProjectCamera(P,A); - vec3_t Q; - VectorAdd(P,vec,Q); - ProjectCamera(Q,B); - // V is the vector projected in camera space - V[0] = B[0] - A[0]; - V[1] = B[1] - A[1]; - if (fabs(V[0])>fabs(V[1])) - { - // best match is against right - axis = 0; - if (V[0]>0) - sgn = +1; - else - sgn = -1; - } - else - { - // best match is against up - axis = 1; - if (V[1]>0) - sgn = +1; - else - sgn = -1; - } -} - -#if 0 -void CamWnd::DrawLightRadius(brush_t* pBrush) -{ - // if lighting - int nRadius = Brush_LightRadius(pBrush); - if (nRadius > 0) - { - Brush_SetLightColor(pBrush); - qglEnable (GL_BLEND); - qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); - qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - qglDisable (GL_TEXTURE_2D); - - qglEnable(GL_TEXTURE_2D); - qglDisable(GL_BLEND); - qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); - } -} -#endif - -extern void DrawPatchMesh(patchMesh_t *pm); -extern void DrawPatchControls(patchMesh_t *pm); -extern void Brush_DrawFacingAngle (brush_t *b, entity_t *e); -extern void Brush_DrawModel(brush_t *b, bool bTextured = false); -extern void DrawModelOrigin(brush_t *b); -extern void DrawModelBBox(brush_t *b); - -void CamWnd::Cam_DrawBrush(brush_t *b, int mode) -{ - int nGLState = m_Camera.draw_glstate; - int nDrawMode = m_Camera.draw_mode; - int nModelMode = g_PrefsDlg.m_nEntityShowState; - - GLfloat material[4], identity[4]; - VectorSet(identity, 0.8f, 0.8f, 0.8f); - IShader *pShader; - - // lights - if (b->owner->eclass->fixedsize && b->owner->eclass->nShowFlags & ECLASS_LIGHT && g_PrefsDlg.m_bNewLightDraw) - { - switch (mode) - { - case DRAW_SOLID: - VectorCopy(b->owner->color, material); - VectorScale(material, 0.8f, material); - material[3] = 1.0f; - - qglColor4fv(material); - - if (g_PrefsDlg.m_bNewLightDraw) - DrawLight(b->owner, nGLState, (IsBrushSelected(b)) ? g_PrefsDlg.m_nLightRadiuses : 0, 0); - - break; - } - } - - // models - else if(b->owner->eclass->fixedsize && b->owner->model.pRender - && !(!IsBrushSelected(b) && (nModelMode & ENTITY_SELECTED_ONLY))) - { - switch (mode) - { - case DRAW_TEXTURED: - if (!(nModelMode & ENTITY_WIREFRAME) && nModelMode != ENTITY_BOX) - { - VectorCopy(b->owner->eclass->color, material); - material[3] = identity[3] = 1.0f; - - qglEnable(GL_CULL_FACE); - - if(!(nGLState & DRAW_GL_TEXTURE_2D)) qglColor4fv(material); - else qglColor4fv(identity); - if(nGLState & DRAW_GL_LIGHTING) qglShadeModel(GL_SMOOTH); - - b->owner->model.pRender->Draw(nGLState, DRAW_RF_CAM); - } - break; - case DRAW_WIRE: - VectorCopy(b->owner->eclass->color, material); - material[3] = 1.0f; - qglColor4fv(material); - - // model view mode "wireframe" or "selected wire" - if(nModelMode & ENTITY_WIREFRAME) - b->owner->model.pRender->Draw(nGLState, DRAW_RF_CAM); - - // model view mode "skinned and boxed" - if(!(b->owner->eclass->nShowFlags & ECLASS_MISCMODEL) ) - { - qglColor4fv(material); - aabb_draw(b->owner->model.pRender->GetAABB(), DRAW_GL_WIRE); - } - else if(nModelMode & ENTITY_BOXED) - { - aabb_draw(b->owner->model.pRender->GetAABB(), DRAW_GL_WIRE); - } -/* - if(!(nModelMode & ENTITY_BOXED) && b->owner->eclass->nShowFlags & ECLASS_MISCMODEL) - DrawModelOrigin(b); -*/ - } - } - - // patches - else if (b->patchBrush) - { - bool bTrans = (b->pPatch->pShader->getTrans() < 1.0f); - switch(mode) - { - case DRAW_TEXTURED: - if (!g_bPatchWireFrame && ((nGLState & DRAW_GL_BLEND && bTrans) || (!(nGLState & DRAW_GL_BLEND) && !bTrans))) - { - qglDisable(GL_CULL_FACE); - - pShader = b->pPatch->pShader; - VectorCopy(pShader->getTexture()->color, material); - material[3] = identity[3] = pShader->getTrans(); - - if(nGLState & DRAW_GL_TEXTURE_2D) { - qglColor4fv(identity); - qglBindTexture(GL_TEXTURE_2D, pShader->getTexture()->texture_number); - } - else - qglColor4fv(material); - if(nGLState & DRAW_GL_LIGHTING) qglShadeModel(GL_SMOOTH); - - DrawPatchMesh(b->pPatch); - } - break; - case DRAW_WIRE: - if (g_bPatchWireFrame) - { - VectorCopy(b->pPatch->pShader->getTexture()->color, material); - material[3] = 1.0; - qglColor4fv(material); - DrawPatchMesh(b->pPatch); - } - if ( b->pPatch->bSelected && (g_qeglobals.d_select_mode == sel_curvepoint - || g_qeglobals.d_select_mode == sel_area - || g_bPatchBendMode)) - DrawPatchControls(b->pPatch); - } - } - - // brushes - else if(b->owner->eclass->fixedsize) - { - switch(mode) - { - case DRAW_SOLID: - VectorCopy(b->owner->eclass->color, material); - VectorScale(material, 0.8f, material); - material[3] = 1.0f; - qglColor4fv(material); - - qglEnable(GL_CULL_FACE); - qglShadeModel(GL_FLAT); - Brush_Draw(b); - break; - case DRAW_WIRE: - if((g_qeglobals.d_savedinfo.include & INCLUDE_ANGLES) - && (b->owner->eclass->nShowFlags & ECLASS_ANGLE)) - Brush_DrawFacingAngle(b, b->owner); - } - } - - // brushes - else - { - switch(mode) - { - case DRAW_TEXTURED: - qglEnable(GL_CULL_FACE); - qglShadeModel(GL_FLAT); - Brush_Draw(b); - } - } -} - -void CamWnd::Cam_DrawBrushes(int mode) -{ - brush_t *b; - brush_t *pList = (g_bClipMode && g_pSplitList) ? g_pSplitList : &selected_brushes; - - for(b = active_brushes.next; b != &active_brushes; b=b->next) - if (!b->bFiltered && !b->bCamCulled) Cam_DrawBrush(b, mode); - for(b = pList->next; b != pList; b=b->next) - if (!b->bFiltered && !b->bCamCulled) Cam_DrawBrush(b, mode); -} - -void CamWnd::Cam_DrawStuff() -{ - GLfloat identity[4]; - VectorSet(identity, 0.8f, 0.8f, 0.8f); - brush_t *b; - - for(b = active_brushes.next; b != &active_brushes; b=b->next) - b->bCamCulled = CullBrush(b); - - for(b = selected_brushes.next; b != &selected_brushes; b=b->next) - b->bCamCulled = CullBrush(b); - - switch (m_Camera.draw_mode) - { - case cd_wire: - qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); - qglDisable(GL_TEXTURE_2D); - qglDisable(GL_TEXTURE_1D); - qglDisable(GL_BLEND); - qglEnable(GL_DEPTH_TEST); - qglEnableClientState(GL_VERTEX_ARRAY); - qglDisableClientState(GL_TEXTURE_COORD_ARRAY); - qglShadeModel(GL_FLAT); - if(g_PrefsDlg.m_bGLLighting) { - qglDisable(GL_LIGHTING); - qglDisable(GL_COLOR_MATERIAL); - qglDisableClientState(GL_NORMAL_ARRAY); - } - m_Camera.draw_glstate = DRAW_GL_WIRE; - break; - - case cd_solid: - qglCullFace(GL_FRONT); - qglEnable(GL_CULL_FACE); - qglShadeModel (GL_FLAT); - qglPolygonMode (GL_FRONT, GL_LINE); - qglPolygonMode (GL_BACK, GL_FILL); - qglDisable(GL_TEXTURE_2D); - qglDisable(GL_BLEND); - qglEnable(GL_DEPTH_TEST); - qglEnableClientState(GL_VERTEX_ARRAY); - qglDisableClientState(GL_TEXTURE_COORD_ARRAY); - qglPolygonOffset(-1.0, 2); - if(g_PrefsDlg.m_bGLLighting) { - qglEnable(GL_LIGHTING); - qglEnable(GL_COLOR_MATERIAL); -// qglEnable(GL_RESCALE_NORMAL); - qglEnableClientState(GL_NORMAL_ARRAY); - } - m_Camera.draw_glstate = DRAW_GL_SOLID; - break; - - case cd_texture: - qglCullFace(GL_FRONT); - qglEnable(GL_CULL_FACE); - qglShadeModel (GL_FLAT); - qglPolygonMode (GL_FRONT, GL_LINE); - qglPolygonMode (GL_BACK, GL_FILL); - qglEnable(GL_TEXTURE_2D); - qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - qglDisable(GL_BLEND); - qglEnable(GL_DEPTH_TEST); - qglEnableClientState(GL_VERTEX_ARRAY); - qglEnableClientState(GL_TEXTURE_COORD_ARRAY); - if(g_PrefsDlg.m_bGLLighting) { - qglEnable(GL_LIGHTING); - qglDisable(GL_COLOR_MATERIAL); - qglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, identity); - qglEnableClientState(GL_NORMAL_ARRAY); -// qglEnable(GL_RESCALE_NORMAL); - } - qglPolygonOffset(-1.0, 2); - m_Camera.draw_glstate = DRAW_GL_TEXTURED; - break; - - default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n"); - } - - Cam_DrawBrushes(DRAW_TEXTURED); - - // setup for solid stuff - switch(m_Camera.draw_mode) - { - case cd_texture: - qglDisable(GL_TEXTURE_2D); - m_Camera.draw_glstate &= ~DRAW_GL_TEXTURE_2D; - if(g_PrefsDlg.m_bGLLighting) - qglEnable(GL_COLOR_MATERIAL); - qglDisableClientState(GL_TEXTURE_COORD_ARRAY); - break; - case cd_solid: - break; - case cd_wire: - break; - default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n"); - } - - qglEnable(GL_CULL_FACE); - qglShadeModel(GL_FLAT); - Cam_DrawBrushes(DRAW_SOLID); - - // setup for wireframe stuff - switch(m_Camera.draw_mode) - { - case cd_texture: - if(g_PrefsDlg.m_bGLLighting) { - qglDisable(GL_LIGHTING); - qglDisable(GL_COLOR_MATERIAL); - qglDisableClientState(GL_NORMAL_ARRAY); -// qglDisable(GL_RESCALE_NORMAL); - } - qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - break; - case cd_solid: - if(g_PrefsDlg.m_bGLLighting) { - qglDisable(GL_LIGHTING); - qglDisable(GL_COLOR_MATERIAL); - qglDisableClientState(GL_NORMAL_ARRAY); -// qglDisable(GL_RESCALE_NORMAL); - } - qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - break; - case cd_wire: - break; - default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n"); - } - - qglDisable(GL_CULL_FACE); - Cam_DrawBrushes(DRAW_WIRE); - - // setup for transparent texture stuff - switch(m_Camera.draw_mode) - { - case cd_texture: - qglPolygonMode (GL_FRONT, GL_LINE); - qglPolygonMode (GL_BACK, GL_FILL); - if(g_PrefsDlg.m_bGLLighting) { - qglEnable(GL_COLOR_MATERIAL); - qglEnableClientState(GL_NORMAL_ARRAY); - qglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, identity); - } - qglEnable(GL_TEXTURE_2D); - qglEnableClientState(GL_TEXTURE_COORD_ARRAY); - m_Camera.draw_glstate = DRAW_GL_TEXTURED; - break; - case cd_solid: - qglPolygonMode (GL_FRONT, GL_LINE); - qglPolygonMode (GL_BACK, GL_FILL); - if(g_PrefsDlg.m_bGLLighting) { - qglEnable(GL_LIGHTING); - qglEnable(GL_COLOR_MATERIAL); - qglEnableClientState(GL_NORMAL_ARRAY); -// qglEnable(GL_RESCALE_NORMAL); - } - m_Camera.draw_glstate = DRAW_GL_SOLID; - break; - case cd_wire: - m_Camera.draw_glstate = DRAW_GL_WIRE; - break; - default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n"); - } - - - qglEnable(GL_BLEND); - m_Camera.draw_glstate |= DRAW_GL_BLEND; - qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - // FIXME: some .TGA are buggy, have a completely empty alpha channel - // if such brushes are rendered in this loop they would be totally transparent with GL_MODULATE - // so I decided using GL_DECAL instead - // if an empty-alpha-channel or nearly-empty texture is used. It will be blank-transparent. - // this could get better if you can get qglTexEnviv (GL_TEXTURE_ENV, to work .. patches are welcome - // Arnout: empty alpha channels are now always filled with data. Don't set this anymore (would cause problems with qer_alphafunc too) -// qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); - - Cam_DrawBrushes(DRAW_TEXTURED); - -// qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - qglDisable(GL_BLEND); - - // setup for wireframe stuff - switch(m_Camera.draw_mode) - { - case cd_texture: - if(g_PrefsDlg.m_bGLLighting) { - qglDisable(GL_COLOR_MATERIAL); - qglDisable(GL_LIGHTING); -// qglDisable(GL_RESCALE_NORMAL); - } - break; - case cd_solid: - if(g_PrefsDlg.m_bGLLighting) { - qglDisable(GL_COLOR_MATERIAL); - qglDisable(GL_LIGHTING); -// qglDisable(GL_RESCALE_NORMAL); - } - break; - case cd_wire: - break; - default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n"); - } - -} - -/* -============== -Cam_Draw -============== -*/ - -void QueueClear (); -void QueueDraw (); - -void CamWnd::Cam_Draw() -{ - brush_t *brush; - face_t *face; - float screenaspect; - float yfov; - double start, end; - int i; - - if (!active_brushes.next) - return; // not valid yet - - if (m_Camera.timing) - start = Sys_DoubleTime (); - - // - // clear - // - QE_CheckOpenGLForErrors(); - - qglViewport(0, 0, m_Camera.width, m_Camera.height); - qglClearColor (g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][0], - g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][1], - g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][2], 0); - qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - // - // set up viewpoint - // - - - qglMatrixMode(GL_PROJECTION); - qglLoadIdentity (); - - screenaspect = (float)m_Camera.width / m_Camera.height; - yfov = 2*atan((float)m_Camera.height / m_Camera.width)*180/Q_PI; - qgluPerspective (yfov, screenaspect, 8, 32768); - - // we're too lazy to calc projection matrix ourselves!!! - qglGetFloatv (GL_PROJECTION_MATRIX, &m_Camera.projection[0][0]); - - vec3_t vec; - - m4x4_identity(&m_Camera.modelview[0][0]); - VectorSet(vec, -90, 0, 0); - m4x4_rotate_by_vec3(&m_Camera.modelview[0][0], vec, eXYZ); - VectorSet(vec, 0, 0, 90); - m4x4_rotate_by_vec3(&m_Camera.modelview[0][0], vec, eXYZ); - VectorSet(vec, 0, m_Camera.angles[0], 0); - m4x4_rotate_by_vec3(&m_Camera.modelview[0][0], vec, eXYZ); - VectorSet(vec, 0, 0, -m_Camera.angles[1]); - m4x4_rotate_by_vec3(&m_Camera.modelview[0][0], vec, eXYZ); - VectorSet(vec, -m_Camera.origin[0], -m_Camera.origin[1], -m_Camera.origin[2]); - m4x4_translate_by_vec3(&m_Camera.modelview[0][0], vec); - - Cam_BuildMatrix (); - - qglMatrixMode(GL_MODELVIEW); - qglLoadIdentity(); - - qglMultMatrixf(&m_Camera.modelview[0][0]); - - // grab the GL_PROJECTION and GL_MODELVIEW matrixes - // used in GetRelativeAxes - //qglGetFloatv (GL_PROJECTION_MATRIX, &m_Camera.projection[0][0]); - //qglGetFloatv (GL_MODELVIEW_MATRIX, &m_Camera.modelview[0][0]); - -#if 0 - // TTimo: this is not used, just for verification (0, 0, m_Camera.width, m_Camera.height) - GLint viewprt[4]; - qglGetIntegerv (GL_VIEWPORT, viewprt); -#endif - - if (g_PrefsDlg.m_bGLLighting) - { - GLfloat inverse_cam_dir[4], ambient[4], diffuse[4];//, material[4]; - - ambient[0] = ambient[1] = ambient[2] = 0.6f; - ambient[3] = 1.0f; - diffuse[0] = diffuse[1] = diffuse[2] = 0.4f; - diffuse[3] = 1.0f; - //material[0] = material[1] = material[2] = 0.8f; - //material[3] = 1.0f; - - vec3_t vCam, vRotate; - VectorSet(vCam, -1, 0, 0); //default cam pos - VectorSet(vRotate, 0, -m_Camera.angles[0], 0); - VectorRotate(vCam, vRotate, vCam); - VectorSet(vRotate, 0, 0, m_Camera.angles[1]); - VectorRotate(vCam, vRotate, vCam); - - inverse_cam_dir[0] = vCam[0]; - inverse_cam_dir[1] = vCam[1]; - inverse_cam_dir[2] = vCam[2]; - inverse_cam_dir[3] = 0; - - qglColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); - - qglLightfv(GL_LIGHT0, GL_POSITION, inverse_cam_dir); - - qglLightfv(GL_LIGHT0, GL_AMBIENT, ambient); - qglLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); - - qglEnable(GL_LIGHT0); - } - - InitCull (); - - // - // draw stuff - // - - Cam_DrawStuff(); - - qglEnableClientState(GL_VERTEX_ARRAY); - qglDisableClientState(GL_NORMAL_ARRAY); - qglDisableClientState(GL_TEXTURE_COORD_ARRAY); - qglDisable (GL_TEXTURE_2D); - qglDisable (GL_LIGHTING); - qglDisable (GL_COLOR_MATERIAL); - - qglEnable (GL_CULL_FACE); - - brush_t* pList = (g_bClipMode && g_pSplitList) ? g_pSplitList : &selected_brushes; - - if (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_BSEL) - { - qglColor4f(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][0], g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][1], g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][2], 0.3f); - qglEnable (GL_BLEND); - qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - qglDepthFunc (GL_LEQUAL); - for (brush = pList->next ; brush != pList ; brush=brush->next) - { - if (brush->bCamCulled) // draw selected faces of filtered brushes to remind that there is a selection - continue; - - if (brush->patchBrush && (g_qeglobals.d_select_mode == sel_curvepoint || g_qeglobals.d_select_mode == sel_area)) - continue; - - if (!g_PrefsDlg.m_bPatchBBoxSelect && brush->patchBrush) - { - DrawPatchMesh(brush->pPatch); - } - else if(brush->owner->model.pRender && g_PrefsDlg.m_nEntityShowState != ENTITY_BOX) - { - brush->owner->model.pRender->Draw(DRAW_GL_FLAT, (DRAW_RF_SEL_OUTLINE|DRAW_RF_CAM)); - } - else - { - for (face=brush->brush_faces ; face ; face=face->next) - Brush_FaceDraw(face, DRAW_GL_FLAT); - } - } - - - int nCount = g_ptrSelectedFaces.GetSize(); - if (nCount > 0) - { - for (int i = 0; i < nCount; i++) - { - face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(i)); - Brush_FaceDraw(selFace, DRAW_GL_FLAT); - } - } - - qglDisableClientState(GL_NORMAL_ARRAY); - qglDepthFunc (GL_LESS); - } - - if (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_ZBUF) - { - // non-zbuffered outline - qglDisable (GL_BLEND); - qglDisable (GL_DEPTH_TEST); - qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); - qglColor3f (1, 1, 1); - for (brush = pList->next ; brush != pList ; brush=brush->next) - { - if ((brush->patchBrush && (g_qeglobals.d_select_mode == sel_curvepoint || g_qeglobals.d_select_mode == sel_area))) - continue; - - if (!g_PrefsDlg.m_bPatchBBoxSelect && brush->patchBrush) - { - DrawPatchMesh(brush->pPatch); - } - else if(brush->owner->model.pRender && g_PrefsDlg.m_nEntityShowState != ENTITY_BOX) - { - brush->owner->model.pRender->Draw(DRAW_GL_WIRE, (DRAW_RF_SEL_FILL|DRAW_RF_CAM)); - - // Hydra : always draw bbox outline! - aabb_draw(brush->owner->model.pRender->GetAABB(), DRAW_GL_WIRE); - } - else - { - for (face=brush->brush_faces ; face ; face=face->next) - Brush_FaceDraw(face, DRAW_GL_WIRE); - } - } - } - - // edge / vertex flags - if (g_qeglobals.d_select_mode == sel_vertex) - { - // GL_POINTS on Kyro Workaround - if(!g_PrefsDlg.m_bGlPtWorkaround) - { - // brush verts - qglPointSize (4); - qglColor3f (0,1,0); - qglBegin (GL_POINTS); - for (i=0 ; inext) - brush->bCamCulled = false; - - for (brush = pList->next ; brush != pList ; brush=brush->next) - brush->bCamCulled = false; -} - -void CamWnd::OnExpose () -{ - if (!MakeCurrent ()) - { - Sys_Printf("ERROR: glXMakeCurrent failed..\n "); - Sys_Printf("Please restart Radiant if the camera view is not working\n"); - } - else - { - QE_CheckOpenGLForErrors(); - g_pSplitList = NULL; - if (g_bClipMode) - { - if (g_Clip1.Set() && g_Clip2.Set()) - { - g_pSplitList = (g_bSwitch) ? - &g_brBackSplits : &g_brFrontSplits; - } - } - - Patch_LODMatchAll(); // spog - - Cam_Draw (); - QE_CheckOpenGLForErrors (); - - m_XORRectangle.set(rectangle_t()); - SwapBuffers (); - } -} - -void CamWnd::BenchMark() -{ - if (!MakeCurrent ()) - Error ("glXMakeCurrent failed in Benchmark"); - - qglDrawBuffer (GL_FRONT); - double dStart = Sys_DoubleTime (); - for (int i=0 ; i < 100 ; i++) - { - m_Camera.angles[YAW] = i*4; - Cam_Draw(); - } - SwapBuffers (); - qglDrawBuffer (GL_BACK); - double dEnd = Sys_DoubleTime (); - Sys_Printf ("%5.2f seconds\n", dEnd - dStart); -} +/* +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 +*/ + +// +// Camera Window +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" +#include +#include + +extern void DrawPathLines(); +extern void Select_ShiftTexture(int x, int y); +extern void Select_RotateTexture(int amt); +extern void DrawAlternatePoint(vec3_t v, float scale); +//extern void Select_ScaleTexture(int x, int y); + +extern int g_nPatchClickedView; + +brush_t* g_pSplitList = NULL; + +// ============================================================================= +// CamWnd class + +CamWnd::CamWnd () + : GLWindow (TRUE), m_XORRectangle(m_pWidget) +{ + m_nNumTransBrushes = 0; + memset(&m_Camera, 0, sizeof(camera_t)); + m_pSide_select = NULL; + m_bClipMode = false; + m_bFreeMove = false; + Cam_Init(); +} + +CamWnd::~CamWnd () +{ +} + +void CamWnd::OnCreate () +{ + if (!MakeCurrent ()) + Error ("glMakeCurrent failed"); + + gtk_glwidget_create_font (m_pWidget); + + // report OpenGL information + Sys_Printf ("GL_VENDOR: %s\n", qglGetString (GL_VENDOR)); + Sys_Printf ("GL_RENDERER: %s\n", qglGetString (GL_RENDERER)); + Sys_Printf ("GL_VERSION: %s\n", qglGetString (GL_VERSION)); + Sys_Printf ("GL_EXTENSIONS: %s\n", qglGetString (GL_EXTENSIONS)); + + // Set off texture compression supported + g_qeglobals.bTextureCompressionSupported = 0; + + // finalize OpenGL init + // NOTE + // why is this here? well .. the Gtk objects get constructed when you enter gtk_main + // and I wanted to have the extensions information in the editor startup console (avoid looking that up in the early console) + // RIANT + // I Split this up so as to add support for extension and user-friendly + // compression format selection. + // ADD new globals for your new format so as to minimise + // calls to Sys_QGL_ExtensionSupported + // NOTE TTimo: I don't really like this approach with globals. Frequent calls to Sys_QGL_ExtensionSupported don't sound like + // a problem to me. If there is some caching to be done, then I think it should be inside Sys_QGL_ExtensionSupported + /////////////////////////////////////////// + // Check for default OpenGL + if (Sys_QGL_ExtensionSupported ("GL_ARB_texture_compression")) + { + g_qeglobals.bTextureCompressionSupported = 1; + g_qeglobals.m_bOpenGLCompressionSupported = 1; + } + + // INSERT PROPRIETARY EXTENSIONS HERE + // Check for S3 extensions + // create a bool global for extension supported + if (Sys_QGL_ExtensionSupported ("GL_EXT_texture_compression_s3tc")) + { + g_qeglobals.bTextureCompressionSupported = 1; + g_qeglobals.m_bS3CompressionSupported = 1; + } + + g_qeglobals.m_bOpenGLReady = true; + + g_PrefsDlg.UpdateTextureCompression(); + +#ifdef ATIHACK_812 + g_PrefsDlg.UpdateATIHack(); +#endif + + g_qeglobals_gui.d_camera = m_pWidget; +} + +void CamWnd::Cam_Init () +{ + m_Camera.timing = false; + m_Camera.origin[0] = 0.f; + m_Camera.origin[1] = 20.f; + m_Camera.origin[2] = 46.f; + m_Camera.color[0] = 0.3f; + m_Camera.color[1] = 0.3f; + m_Camera.color[2] = 0.3f; + m_nCambuttonstate = 0; +} + +void CamWnd::OnSize(int cx, int cy) +{ + m_Camera.width = cx; + m_Camera.height = cy; + gtk_widget_queue_draw(m_pWidget); +} + +rectangle_t rectangle_from_area_cam() +{ + const float left = MIN(g_qeglobals.d_vAreaTL[0], g_qeglobals.d_vAreaBR[0]); + const float top = MAX(g_qeglobals.d_vAreaTL[1], g_qeglobals.d_vAreaBR[1]); + const float right = MAX(g_qeglobals.d_vAreaTL[0], g_qeglobals.d_vAreaBR[0]); + const float bottom = MIN(g_qeglobals.d_vAreaTL[1], g_qeglobals.d_vAreaBR[1]); + return rectangle_t(left, bottom, right - left, top - bottom); +} + +void update_xor_rectangle(XORRectangle& xor_rectangle) +{ + rectangle_t rectangle; + if ((g_qeglobals.d_select_mode == sel_area)) + rectangle = rectangle_from_area_cam(); + xor_rectangle.set(rectangle); +} + +void CamWnd::OnMouseMove(guint32 flags, int pointx, int pointy) +{ + int height = m_pWidget->allocation.height; + // NOTE RR2DO2 this hasn't got any use anymore really. It is an old qeradiant feature + // that can be re-enabled by removing the checks for HasCapture and not shift/ctrl down + // but the scaling/rotating (unless done with the steps set in the surface inspector + // dialog) is way too sensitive to be of any use + if (HasCapture () && Sys_AltDown () && + !((flags & MK_SHIFT) || (flags & MK_CONTROL))) + { + if (flags & MK_CONTROL) + Select_RotateTexture(pointy - m_ptLastCursorY); + else + if (flags & MK_SHIFT) + Select_ScaleTexture(pointx - m_ptLastCursorX, m_ptLastCursorY - pointy); + else + Select_ShiftTexture(pointx - m_ptLastCursorX, m_ptLastCursorY - pointy); + } + else + { + Cam_MouseMoved(pointx, height - 1 - pointy, flags); + } + m_ptLastCursorX = pointx; + m_ptLastCursorY = pointy; + + update_xor_rectangle(m_XORRectangle); +} + +void CamWnd::OnMouseWheel(bool bUp) +{ + if (bUp) + VectorMA (m_Camera.origin, g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin); + else + VectorMA (m_Camera.origin, -g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin); + + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + g_pParentWnd->OnTimer (); +} + +void CamWnd::OnLButtonDown(guint32 nFlags, int pointx, int pointy) +{ + m_ptLastCursorX = pointx; + m_ptLastCursorY = pointy; + OriginalMouseDown(nFlags, pointx, pointy); +} + +void CamWnd::OnLButtonUp(guint32 nFlags, int pointx, int pointy) +{ + OriginalMouseUp(nFlags, pointx, pointy); +} + +void CamWnd::OnMButtonDown(guint32 nFlags, int pointx, int pointy) +{ + OriginalMouseDown(nFlags, pointx, pointy); +} + +void CamWnd::OnMButtonUp(guint32 nFlags, int pointx, int pointy) +{ + OriginalMouseUp(nFlags, pointx, pointy); +} + +void CamWnd::OnRButtonDown(guint32 nFlags, int pointx, int pointy) +{ + OriginalMouseDown(nFlags, pointx, pointy); +} + +void CamWnd::OnRButtonUp(guint32 nFlags, int pointx, int pointy) +{ + OriginalMouseUp(nFlags, pointx, pointy); +} + +void CamWnd::OriginalMouseUp(guint32 nFlags, int pointx, int pointy) +{ + int height = m_pWidget->allocation.height; + + if(g_qeglobals.d_select_mode == sel_facets_on || g_qeglobals.d_select_mode == sel_facets_off) + { + g_qeglobals.d_select_mode = sel_brush; + } + + Cam_MouseUp(pointx, height - 1 - pointy, nFlags); + ReleaseCapture (); + + update_xor_rectangle(m_XORRectangle); +} + +void CamWnd::OriginalMouseDown(guint32 nFlags, int pointx, int pointy) +{ + int height = m_pWidget->allocation.height; + + SetFocus(); + SetCapture(); + Cam_MouseDown (pointx, height - 1 - pointy, nFlags); + + update_xor_rectangle(m_XORRectangle); +} + +void CamWnd::Cam_BuildMatrix() +{ + float ya; + float matrix[4][4]; + int i; + + if (!m_bFreeMove) + { + ya = m_Camera.angles[1]/180*Q_PI; + + // the movement matrix is kept 2d + m_Camera.forward[0] = cos(ya); + m_Camera.forward[1] = sin(ya); + m_Camera.forward[2] = 0; + m_Camera.right[0] = m_Camera.forward[1]; + m_Camera.right[1] = -m_Camera.forward[0]; + } + else + { + AngleVectors( m_Camera.angles, m_Camera.forward, m_Camera.right, NULL ); + m_Camera.forward[2] = -m_Camera.forward[2]; + } + + memcpy(matrix, m_Camera.projection, sizeof(m4x4_t)); + m4x4_multiply_by_m4x4(&matrix[0][0], &m_Camera.modelview[0][0]); + + //qglGetFloatv (GL_PROJECTION_MATRIX, &matrix[0][0]); + + for (i=0 ; i<3 ; i++) + { + m_Camera.vright[i] = matrix[i][0]; + m_Camera.vup[i] = matrix[i][1]; + m_Camera.vpn[i] = matrix[i][2]; + } + + VectorNormalize (m_Camera.vright, m_Camera.vright); + VectorNormalize (m_Camera.vup, m_Camera.vup); + VectorNormalize (m_Camera.vpn, m_Camera.vpn); +} + +void CamWnd::Cam_ChangeFloor (qboolean up) +{ + brush_t *b; + float d, bestd, current; + vec3_t start, dir; + + start[0] = m_Camera.origin[0]; + start[1] = m_Camera.origin[1]; + start[2] = g_MaxWorldCoord; + dir[0] = dir[1] = 0; + dir[2] = -1; + + current = g_MaxWorldCoord - (m_Camera.origin[2] - 48); + if (up) + bestd = 0; + else + bestd = 2*g_MaxWorldCoord; + + for (b=active_brushes.next ; b != &active_brushes ; b=b->next) + { + if (!Brush_Ray (start, dir, b, &d)) + continue; + if (up && d < current && d > bestd) + bestd = d; + if (!up && d > current && d < bestd) + bestd = d; + } + + if (bestd == 0 || bestd == 2*g_MaxWorldCoord) + return; + + m_Camera.origin[2] += current - bestd; + Sys_UpdateWindows (W_CAMERA|W_Z_OVERLAY); +} + +void CamWnd::Cam_PositionDrag() +{ + int x, y; + + Sys_GetCursorPos (&x, &y); + if (x != m_ptCursorX || y != m_ptCursorY) + { + x -= m_ptCursorX; + VectorMA (m_Camera.origin, x, m_Camera.vright, m_Camera.origin); + y -= m_ptCursorY; + m_Camera.origin[2] -= y; + Sys_SetCursorPos(m_ptCursorX, m_ptCursorY); + Sys_UpdateWindows (W_CAMERA | W_XY_OVERLAY); + } +} + +void CamWnd::Cam_MouseControl (float dtime) +{ + Cam_KeyControl (dtime); + + if( g_PrefsDlg.m_bCamFreeLook ) + { + int dx, dy; + gint x, y; + + if( !m_bFreeMove || m_nCambuttonstate == MK_CONTROL ) + return; + + // Update angles + Sys_GetCursorPos(&m_ptCursorX, &m_ptCursorY); + + dx = m_ptLastCamCursorX - m_ptCursorX; + dy = m_ptLastCamCursorY - m_ptCursorY; + + gdk_window_get_origin( m_pWidget->window, &x, &y); + + m_ptLastCamCursorX = x + (m_Camera.width / 2); + m_ptLastCamCursorY = y + (m_Camera.height / 2); + + Sys_SetCursorPos(m_ptLastCamCursorX, m_ptLastCamCursorY); + + // Don't use pitch + if(!g_PrefsDlg.m_bCamFreeLookStrafe) { + if (g_PrefsDlg.m_bCamInverseMouse) + m_Camera.angles[PITCH] -= dy * dtime * g_PrefsDlg.m_nAngleSpeed; + else + m_Camera.angles[PITCH] += dy * dtime * g_PrefsDlg.m_nAngleSpeed; + } else { + VectorMA (m_Camera.origin, dy * (float) (g_PrefsDlg.m_nMoveSpeed / 6.0f), m_Camera.forward, m_Camera.origin); + } + + m_Camera.angles[YAW] += dx * dtime * g_PrefsDlg.m_nAngleSpeed; + + if (m_Camera.angles[PITCH] > 90) + m_Camera.angles[PITCH] = 90; + else if (m_Camera.angles[PITCH] < -90) + m_Camera.angles[PITCH] = -90; + + if (m_Camera.angles[YAW] >= 360) + m_Camera.angles[YAW] = 0; + else if (m_Camera.angles[YAW] <= -360) + m_Camera.angles[YAW] = 0; + + if( dx || dy || m_Camera.movementflags ) + { + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + g_pParentWnd->OnTimer (); + } + } + else + { + int xl, xh; + int yl, yh; + float xf, yf; + + if (g_PrefsDlg.m_nMouseButtons == 2) + { + if (m_nCambuttonstate != (MK_RBUTTON | MK_SHIFT)) + return; + } + else + { + if (m_nCambuttonstate != MK_RBUTTON) + return; + } + + xf = (float)(m_ptButtonX - m_Camera.width/2) / (m_Camera.width/2); + yf = (float)(m_ptButtonY - m_Camera.height/2) / (m_Camera.height/2); + + xl = m_Camera.width/3; + xh = xl*2; + yl = m_Camera.height/3; + yh = yl*2; + + xf *= 1.0 - fabs(yf); + if (xf < 0) + { + xf += 0.1f; + if (xf > 0) + xf = 0; + } + else + { + xf -= 0.1f; + if (xf < 0) + xf = 0; + } + + VectorMA (m_Camera.origin, yf*dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin); + m_Camera.angles[YAW] += xf*-dtime*g_PrefsDlg.m_nAngleSpeed; + + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + g_pParentWnd->OnTimer (); + } +} + +void CamWnd::Cam_KeyControl (float dtime) { + + // Update angles + if (m_Camera.movementflags & MOVE_ROTLEFT) + m_Camera.angles[YAW] += 15*dtime*g_PrefsDlg.m_nAngleSpeed; + if (m_Camera.movementflags & MOVE_ROTRIGHT) + m_Camera.angles[YAW] -= 15*dtime*g_PrefsDlg.m_nAngleSpeed; + + // Update position + if (m_Camera.movementflags & MOVE_FORWARD) + VectorMA (m_Camera.origin, dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin); + if (m_Camera.movementflags & MOVE_BACK) + VectorMA (m_Camera.origin, -dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin); + if (m_Camera.movementflags & MOVE_STRAFELEFT) + VectorMA (m_Camera.origin, -dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.right, m_Camera.origin); + if (m_Camera.movementflags & MOVE_STRAFERIGHT) + VectorMA (m_Camera.origin, dtime*g_PrefsDlg.m_nMoveSpeed, m_Camera.right, m_Camera.origin); + + // Save a screen update (when m_bFreeMove is enabled, mousecontrol does the update) + if( !m_bFreeMove && m_Camera.movementflags ) + { + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + g_pParentWnd->OnTimer (); + } +} + +// NOTE TTimo if there's an OS-level focus out of the application +// then we can release the camera cursor grab +static gint camwindow_focusout(GtkWidget* widget, GdkEventKey* event, gpointer data) +{ + g_pParentWnd->GetCamWnd ()->ToggleFreeMove(); + return FALSE; +} + +void CamWnd::ToggleFreeMove() +{ + GdkWindow *window; + GtkWidget *widget; + + m_bFreeMove = !m_bFreeMove; + Camera()->movementflags = 0; + m_ptLastCamCursorX = m_ptCursorX; + m_ptLastCamCursorY = m_ptCursorY; + + if (g_pParentWnd->CurrentStyle() == MainFrame::eFloating) + { + widget = g_pParentWnd->GetCamWnd ()->m_pParent; + window = widget->window; + } + else + { + widget = g_pParentWnd->m_pWidget; + window = widget->window; + } + + if (m_bFreeMove) + { + + SetFocus(); + SetCapture(); + + { + GdkPixmap *pixmap; + GdkBitmap *mask; + char buffer [(32 * 32)/8]; + memset (buffer, 0, (32 * 32)/8); + GdkColor white = {0, 0xffff, 0xffff, 0xffff}; + GdkColor black = {0, 0x0000, 0x0000, 0x0000}; + pixmap = gdk_bitmap_create_from_data (NULL, buffer, 32, 32); + mask = gdk_bitmap_create_from_data (NULL, buffer, 32, 32); + GdkCursor *cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &white, &black, 1, 1); + + gdk_window_set_cursor (window, cursor); + gdk_cursor_unref (cursor); + gdk_drawable_unref (pixmap); + gdk_drawable_unref (mask); + } + + // RR2DO2: FIXME why does this only work the 2nd and + // further times the event is called? (floating windows + // mode seems to work fine though...) + m_FocusOutHandler_id = gtk_signal_connect (GTK_OBJECT (widget), "focus_out_event", + GTK_SIGNAL_FUNC (camwindow_focusout), g_pParentWnd); + + { + GdkEventMask mask = (GdkEventMask)(GDK_POINTER_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK + | GDK_BUTTON_MOTION_MASK + | GDK_BUTTON1_MOTION_MASK + | GDK_BUTTON2_MOTION_MASK + | GDK_BUTTON3_MOTION_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK); + + gdk_pointer_grab(widget->window, TRUE, mask, widget->window, NULL, GDK_CURRENT_TIME); + } + } + else + { + gdk_pointer_ungrab(GDK_CURRENT_TIME); + + gtk_signal_disconnect (GTK_OBJECT (widget), m_FocusOutHandler_id); + + GdkCursor *cursor = gdk_cursor_new (GDK_LEFT_PTR); + gdk_window_set_cursor (window, cursor); + gdk_cursor_unref (cursor); + + ReleaseCapture(); + } + + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + g_pParentWnd->OnTimer (); +} + +void CamWnd::Cam_MouseDown(int x, int y, int buttons) +{ + vec3_t dir; + float f, r, u; + int i; + + + // + // calc ray direction + // + u = (float)( y - ( m_Camera.height * .5f ) ) / ( m_Camera.width * .5f ); + r = (float)( x - ( m_Camera.width * .5f ) ) / ( m_Camera.width * .5f ); + f = 1; + + for (i=0 ; i<3 ; i++) + dir[i] = m_Camera.vpn[i] * f + m_Camera.vright[i] * r + m_Camera.vup[i] * u; + VectorNormalize (dir, dir); + + Sys_GetCursorPos(&m_ptCursorX, &m_ptCursorY); + + m_nCambuttonstate = buttons; + m_ptButtonX = x; + m_ptButtonY = y; + + // LBUTTON = manipulate selection + // shift-LBUTTON = select + // middle button = grab texture + // ctrl-middle button = set entire brush to texture + // ctrl-shift-middle button = set single face to texture + int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON; + if ((buttons == MK_LBUTTON) + || (buttons == (MK_LBUTTON | MK_SHIFT)) + || (buttons == (MK_LBUTTON | MK_CONTROL)) + || (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) + || (buttons == nMouseButton) + || (buttons == (nMouseButton|MK_SHIFT)) + || (buttons == (nMouseButton|MK_CONTROL)) + || (buttons == (nMouseButton|MK_SHIFT|MK_CONTROL))) + { + if (g_PrefsDlg.m_nMouseButtons == 2 && (buttons == (MK_RBUTTON | MK_SHIFT))) + { + if (g_PrefsDlg.m_bCamFreeLook) + ToggleFreeMove(); + else + Cam_MouseControl (0.1f); + } + else + { + // something global needs to track which window is responsible for stuff + Patch_SetView(W_CAMERA); + Drag_Begin (x, y, buttons, m_Camera.vright, m_Camera.vup, m_Camera.origin, dir, true); + } + return; + } + + if (buttons == MK_RBUTTON) + { + if (g_PrefsDlg.m_bCamFreeLook) + ToggleFreeMove(); + else + Cam_MouseControl (0.1f); + return; + } +} + +void CamWnd::Cam_MouseUp (int x, int y, int buttons) +{ + m_nCambuttonstate = 0; + Drag_MouseUp (buttons); +} + +void CamWnd::Cam_MouseMoved (int x, int y, int buttons) +{ + m_nCambuttonstate = buttons; + if (!buttons) + return; + + if( g_PrefsDlg.m_nCamDragMultiSelect ) + { + if (g_qeglobals.d_select_mode == sel_brush_on || g_qeglobals.d_select_mode == sel_brush_off) + { + bool bDoDragMultiSelect = FALSE; + + if( g_PrefsDlg.m_nCamDragMultiSelect == 1 && buttons == (MK_LBUTTON|MK_SHIFT) ) + bDoDragMultiSelect = TRUE; + else if( g_PrefsDlg.m_nCamDragMultiSelect == 2 && buttons == (MK_LBUTTON|MK_CONTROL) && Sys_AltDown() ) + bDoDragMultiSelect = TRUE; + + if( bDoDragMultiSelect ) + { + vec3_t dir; + float f, r, u; + int i; + + // + // calc ray direction + // + u = (float)( y - ( m_Camera.height * .5f ) ) / ( m_Camera.width * .5f ); + r = (float)( x - ( m_Camera.width * .5f ) ) / ( m_Camera.width * .5f ); + f = 1; + + for (i=0 ; i<3 ; i++) + dir[i] = m_Camera.vpn[i] * f + m_Camera.vright[i] * r + m_Camera.vup[i] * u; + VectorNormalize (dir,dir); + + switch( g_qeglobals.d_select_mode ) + { + case sel_brush_on: + Select_Ray( m_Camera.origin, dir, (SF_DRAG_ON|SF_CAMERA) ); + break; + + case sel_brush_off: + Select_Ray( m_Camera.origin, dir, (SF_DRAG_OFF|SF_CAMERA) ); + break; + + default: + break; + } + return; + } + } + else if (g_qeglobals.d_select_mode == sel_facets_on || g_qeglobals.d_select_mode == sel_facets_off) + { + if( buttons == (MK_LBUTTON|MK_CONTROL|MK_SHIFT) ) + { + vec3_t dir; + float f, r, u; + int i; + + // + // calc ray direction + // + u = (float)( y - ( m_Camera.height * .5f ) ) / ( m_Camera.width * .5f ); + r = (float)( x - ( m_Camera.width * .5f ) ) / ( m_Camera.width * .5f ); + f = 1; + + for (i=0 ; i<3 ; i++) + dir[i] = m_Camera.vpn[i] * f + m_Camera.vright[i] * r + m_Camera.vup[i] * u; + VectorNormalize (dir,dir); + + switch( g_qeglobals.d_select_mode ) + { + case sel_facets_on: + Select_Ray( m_Camera.origin, dir, (SF_SINGLEFACE|SF_DRAG_ON|SF_CAMERA) ); + break; + + case sel_facets_off: + Select_Ray( m_Camera.origin, dir, (SF_SINGLEFACE|SF_DRAG_OFF|SF_CAMERA) ); + break; + + default: + break; + } + return; + } + } + } + + m_ptButtonX = x; + m_ptButtonY = y; + + if ( (m_bFreeMove && (buttons & MK_CONTROL) && !(buttons & MK_SHIFT)) || (!m_bFreeMove && (buttons == (MK_RBUTTON|MK_CONTROL))) ) + { + Cam_PositionDrag (); + Sys_UpdateWindows (W_XY|W_CAMERA|W_Z); + return; + } + + Sys_GetCursorPos(&m_ptCursorX, &m_ptCursorY); + + if (buttons & (MK_LBUTTON | MK_MBUTTON) ) + { + Drag_MouseMoved (x, y, buttons); + if(g_qeglobals.d_select_mode != sel_area) + Sys_UpdateWindows (W_XY|W_CAMERA|W_Z); + } +} + +void CamWnd::InitCull() +{ + int i; + + VectorSubtract (m_Camera.vpn, m_Camera.vright, m_vCull1); + VectorAdd (m_Camera.vpn, m_Camera.vright, m_vCull2); + + for (i=0 ; i<3 ; i++) + { + if (m_vCull1[i] > 0) + m_nCullv1[i] = 3+i; + else + m_nCullv1[i] = i; + if (m_vCull2[i] > 0) + m_nCullv2[i] = 3+i; + else + m_nCullv2[i] = i; + } +} + +qboolean CamWnd::CullBrush (brush_t *b) +{ + int i; + vec3_t point; + float d; + + if (g_PrefsDlg.m_bCubicClipping) + { + float fLevel = g_PrefsDlg.m_nCubicScale * 64; + + point[0] = m_Camera.origin[0] - fLevel; + point[1] = m_Camera.origin[1] - fLevel; + point[2] = m_Camera.origin[2] - fLevel; + + for (i=0; i<3; i++) + if (b->mins[i] < point[i] && b->maxs[i] < point[i]) + return true; + + point[0] = m_Camera.origin[0] + fLevel; + point[1] = m_Camera.origin[1] + fLevel; + point[2] = m_Camera.origin[2] + fLevel; + + for (i=0; i<3; i++) + if (b->mins[i] > point[i] && b->maxs[i] > point[i]) + return true; + } + + for (i=0 ; i<3 ; i++) + point[i] = b->mins[m_nCullv1[i]] - m_Camera.origin[i]; + + d = DotProduct (point, m_vCull1); + if (d < -1) + return true; + + for (i=0 ; i<3 ; i++) + point[i] = b->mins[m_nCullv2[i]] - m_Camera.origin[i]; + + d = DotProduct (point, m_vCull2); + if (d < -1) + return true; + + return false; +} + +// project a 3D point onto the camera space +// we use the GL viewing matrixes +// this is the implementation of a glu function (I realized that afterwards): gluProject +void CamWnd::ProjectCamera(const vec3_t A, vec_t B[2]) +{ + + vec_t P1[4],P2[4],P3[4]; + VectorCopy(A,P1); P1[3] = 1; + + GLMatMul(m_Camera.modelview , P1, P2); + GLMatMul(m_Camera.projection, P2, P3); + + // we ASSUME that the view port is 0 0 m_Camera.width m_Camera.height (you can check in Cam_Draw) + B[0] = (float)m_Camera.width * ( P3[0] + 1.0 ) / 2.0; + B[1] = (float)m_Camera.height * ( P3[1] + 1.0 ) / 2.0; + +} + +// vec defines a direction in geometric space and P an origin point +// the user is interacting from the camera view +// (for example with texture adjustment shortcuts) +// and intuitively if he hits left / right / up / down +// what happens in geometric space should match the left/right/up/down move in camera space +// axis = 0: vec is along left/right +// axis = 1: vec is along up/down +// sgn = +1: same directions +// sgn = -1: opposite directions +// Implementation: +// typical use case is giving a face center and a normalized vector +// 1) compute start and endpoint, project them in camera view, get the direction +// depending on the situation, we might bump into precision issues with that +// 2) possible to compute the projected direction independently? +// this solution would be better but right now I don't see how to do it.. +void CamWnd::MatchViewAxes(const vec3_t P, const vec3_t vec, int &axis, float &sgn) +{ + + vec_t A[2],B[2],V[2]; + ProjectCamera(P,A); + vec3_t Q; + VectorAdd(P,vec,Q); + ProjectCamera(Q,B); + // V is the vector projected in camera space + V[0] = B[0] - A[0]; + V[1] = B[1] - A[1]; + if (fabs(V[0])>fabs(V[1])) + { + // best match is against right + axis = 0; + if (V[0]>0) + sgn = +1; + else + sgn = -1; + } + else + { + // best match is against up + axis = 1; + if (V[1]>0) + sgn = +1; + else + sgn = -1; + } +} + +#if 0 +void CamWnd::DrawLightRadius(brush_t* pBrush) +{ + // if lighting + int nRadius = Brush_LightRadius(pBrush); + if (nRadius > 0) + { + Brush_SetLightColor(pBrush); + qglEnable (GL_BLEND); + qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + qglDisable (GL_TEXTURE_2D); + + qglEnable(GL_TEXTURE_2D); + qglDisable(GL_BLEND); + qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + } +} +#endif + +extern void DrawPatchMesh(patchMesh_t *pm); +extern void DrawPatchControls(patchMesh_t *pm); +extern void Brush_DrawFacingAngle (brush_t *b, entity_t *e); +extern void Brush_DrawModel(brush_t *b, bool bTextured = false); +extern void DrawModelOrigin(brush_t *b); +extern void DrawModelBBox(brush_t *b); + +void CamWnd::Cam_DrawBrush(brush_t *b, int mode) +{ + int nGLState = m_Camera.draw_glstate; + int nDrawMode = m_Camera.draw_mode; + int nModelMode = g_PrefsDlg.m_nEntityShowState; + + GLfloat material[4], identity[4]; + VectorSet(identity, 0.8f, 0.8f, 0.8f); + IShader *pShader; + + // lights + if (b->owner->eclass->fixedsize && b->owner->eclass->nShowFlags & ECLASS_LIGHT && g_PrefsDlg.m_bNewLightDraw) + { + switch (mode) + { + case DRAW_SOLID: + VectorCopy(b->owner->color, material); + VectorScale(material, 0.8f, material); + material[3] = 1.0f; + + qglColor4fv(material); + + if (g_PrefsDlg.m_bNewLightDraw) + DrawLight(b->owner, nGLState, (IsBrushSelected(b)) ? g_PrefsDlg.m_nLightRadiuses : 0, 0); + + break; + } + } + + // models + else if(b->owner->eclass->fixedsize && b->owner->model.pRender + && !(!IsBrushSelected(b) && (nModelMode & ENTITY_SELECTED_ONLY))) + { + switch (mode) + { + case DRAW_TEXTURED: + if (!(nModelMode & ENTITY_WIREFRAME) && nModelMode != ENTITY_BOX) + { + VectorCopy(b->owner->eclass->color, material); + material[3] = identity[3] = 1.0f; + + qglEnable(GL_CULL_FACE); + + if(!(nGLState & DRAW_GL_TEXTURE_2D)) qglColor4fv(material); + else qglColor4fv(identity); + if(nGLState & DRAW_GL_LIGHTING) qglShadeModel(GL_SMOOTH); + + b->owner->model.pRender->Draw(nGLState, DRAW_RF_CAM); + } + break; + case DRAW_WIRE: + VectorCopy(b->owner->eclass->color, material); + material[3] = 1.0f; + qglColor4fv(material); + + // model view mode "wireframe" or "selected wire" + if(nModelMode & ENTITY_WIREFRAME) + b->owner->model.pRender->Draw(nGLState, DRAW_RF_CAM); + + // model view mode "skinned and boxed" + if(!(b->owner->eclass->nShowFlags & ECLASS_MISCMODEL) ) + { + qglColor4fv(material); + aabb_draw(b->owner->model.pRender->GetAABB(), DRAW_GL_WIRE); + } + else if(nModelMode & ENTITY_BOXED) + { + aabb_draw(b->owner->model.pRender->GetAABB(), DRAW_GL_WIRE); + } +/* + if(!(nModelMode & ENTITY_BOXED) && b->owner->eclass->nShowFlags & ECLASS_MISCMODEL) + DrawModelOrigin(b); +*/ + } + } + + // patches + else if (b->patchBrush) + { + bool bTrans = (b->pPatch->pShader->getTrans() < 1.0f); + switch(mode) + { + case DRAW_TEXTURED: + if (!g_bPatchWireFrame && ((nGLState & DRAW_GL_BLEND && bTrans) || (!(nGLState & DRAW_GL_BLEND) && !bTrans))) + { + qglDisable(GL_CULL_FACE); + + pShader = b->pPatch->pShader; + VectorCopy(pShader->getTexture()->color, material); + material[3] = identity[3] = pShader->getTrans(); + + if(nGLState & DRAW_GL_TEXTURE_2D) { + qglColor4fv(identity); + qglBindTexture(GL_TEXTURE_2D, pShader->getTexture()->texture_number); + } + else + qglColor4fv(material); + if(nGLState & DRAW_GL_LIGHTING) qglShadeModel(GL_SMOOTH); + + DrawPatchMesh(b->pPatch); + } + break; + case DRAW_WIRE: + if (g_bPatchWireFrame) + { + VectorCopy(b->pPatch->pShader->getTexture()->color, material); + material[3] = 1.0; + qglColor4fv(material); + DrawPatchMesh(b->pPatch); + } + if ( b->pPatch->bSelected && (g_qeglobals.d_select_mode == sel_curvepoint + || g_qeglobals.d_select_mode == sel_area + || g_bPatchBendMode)) + DrawPatchControls(b->pPatch); + } + } + + // brushes + else if(b->owner->eclass->fixedsize) + { + switch(mode) + { + case DRAW_SOLID: + VectorCopy(b->owner->eclass->color, material); + VectorScale(material, 0.8f, material); + material[3] = 1.0f; + qglColor4fv(material); + + qglEnable(GL_CULL_FACE); + qglShadeModel(GL_FLAT); + Brush_Draw(b); + break; + case DRAW_WIRE: + if((g_qeglobals.d_savedinfo.include & INCLUDE_ANGLES) + && (b->owner->eclass->nShowFlags & ECLASS_ANGLE)) + Brush_DrawFacingAngle(b, b->owner); + } + } + + // brushes + else + { + switch(mode) + { + case DRAW_TEXTURED: + qglEnable(GL_CULL_FACE); + qglShadeModel(GL_FLAT); + Brush_Draw(b); + } + } +} + +void CamWnd::Cam_DrawBrushes(int mode) +{ + brush_t *b; + brush_t *pList = (g_bClipMode && g_pSplitList) ? g_pSplitList : &selected_brushes; + + for(b = active_brushes.next; b != &active_brushes; b=b->next) + if (!b->bFiltered && !b->bCamCulled) Cam_DrawBrush(b, mode); + for(b = pList->next; b != pList; b=b->next) + if (!b->bFiltered && !b->bCamCulled) Cam_DrawBrush(b, mode); +} + +void CamWnd::Cam_DrawStuff() +{ + GLfloat identity[4]; + VectorSet(identity, 0.8f, 0.8f, 0.8f); + brush_t *b; + + for(b = active_brushes.next; b != &active_brushes; b=b->next) + b->bCamCulled = CullBrush(b); + + for(b = selected_brushes.next; b != &selected_brushes; b=b->next) + b->bCamCulled = CullBrush(b); + + switch (m_Camera.draw_mode) + { + case cd_wire: + qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + qglDisable(GL_TEXTURE_2D); + qglDisable(GL_TEXTURE_1D); + qglDisable(GL_BLEND); + qglEnable(GL_DEPTH_TEST); + qglEnableClientState(GL_VERTEX_ARRAY); + qglDisableClientState(GL_TEXTURE_COORD_ARRAY); + qglShadeModel(GL_FLAT); + if(g_PrefsDlg.m_bGLLighting) { + qglDisable(GL_LIGHTING); + qglDisable(GL_COLOR_MATERIAL); + qglDisableClientState(GL_NORMAL_ARRAY); + } + m_Camera.draw_glstate = DRAW_GL_WIRE; + break; + + case cd_solid: + qglCullFace(GL_FRONT); + qglEnable(GL_CULL_FACE); + qglShadeModel (GL_FLAT); + qglPolygonMode (GL_FRONT, GL_LINE); + qglPolygonMode (GL_BACK, GL_FILL); + qglDisable(GL_TEXTURE_2D); + qglDisable(GL_BLEND); + qglEnable(GL_DEPTH_TEST); + qglEnableClientState(GL_VERTEX_ARRAY); + qglDisableClientState(GL_TEXTURE_COORD_ARRAY); + qglPolygonOffset(-1.0, 2); + if(g_PrefsDlg.m_bGLLighting) { + qglEnable(GL_LIGHTING); + qglEnable(GL_COLOR_MATERIAL); +// qglEnable(GL_RESCALE_NORMAL); + qglEnableClientState(GL_NORMAL_ARRAY); + } + m_Camera.draw_glstate = DRAW_GL_SOLID; + break; + + case cd_texture: + qglCullFace(GL_FRONT); + qglEnable(GL_CULL_FACE); + qglShadeModel (GL_FLAT); + qglPolygonMode (GL_FRONT, GL_LINE); + qglPolygonMode (GL_BACK, GL_FILL); + qglEnable(GL_TEXTURE_2D); + qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + qglDisable(GL_BLEND); + qglEnable(GL_DEPTH_TEST); + qglEnableClientState(GL_VERTEX_ARRAY); + qglEnableClientState(GL_TEXTURE_COORD_ARRAY); + if(g_PrefsDlg.m_bGLLighting) { + qglEnable(GL_LIGHTING); + qglDisable(GL_COLOR_MATERIAL); + qglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, identity); + qglEnableClientState(GL_NORMAL_ARRAY); +// qglEnable(GL_RESCALE_NORMAL); + } + qglPolygonOffset(-1.0, 2); + m_Camera.draw_glstate = DRAW_GL_TEXTURED; + break; + + default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n"); + } + + Cam_DrawBrushes(DRAW_TEXTURED); + + // setup for solid stuff + switch(m_Camera.draw_mode) + { + case cd_texture: + qglDisable(GL_TEXTURE_2D); + m_Camera.draw_glstate &= ~DRAW_GL_TEXTURE_2D; + if(g_PrefsDlg.m_bGLLighting) + qglEnable(GL_COLOR_MATERIAL); + qglDisableClientState(GL_TEXTURE_COORD_ARRAY); + break; + case cd_solid: + break; + case cd_wire: + break; + default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n"); + } + + qglEnable(GL_CULL_FACE); + qglShadeModel(GL_FLAT); + Cam_DrawBrushes(DRAW_SOLID); + + // setup for wireframe stuff + switch(m_Camera.draw_mode) + { + case cd_texture: + if(g_PrefsDlg.m_bGLLighting) { + qglDisable(GL_LIGHTING); + qglDisable(GL_COLOR_MATERIAL); + qglDisableClientState(GL_NORMAL_ARRAY); +// qglDisable(GL_RESCALE_NORMAL); + } + qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + break; + case cd_solid: + if(g_PrefsDlg.m_bGLLighting) { + qglDisable(GL_LIGHTING); + qglDisable(GL_COLOR_MATERIAL); + qglDisableClientState(GL_NORMAL_ARRAY); +// qglDisable(GL_RESCALE_NORMAL); + } + qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + break; + case cd_wire: + break; + default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n"); + } + + qglDisable(GL_CULL_FACE); + Cam_DrawBrushes(DRAW_WIRE); + + // setup for transparent texture stuff + switch(m_Camera.draw_mode) + { + case cd_texture: + qglPolygonMode (GL_FRONT, GL_LINE); + qglPolygonMode (GL_BACK, GL_FILL); + if(g_PrefsDlg.m_bGLLighting) { + qglEnable(GL_COLOR_MATERIAL); + qglEnableClientState(GL_NORMAL_ARRAY); + qglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, identity); + } + qglEnable(GL_TEXTURE_2D); + qglEnableClientState(GL_TEXTURE_COORD_ARRAY); + m_Camera.draw_glstate = DRAW_GL_TEXTURED; + break; + case cd_solid: + qglPolygonMode (GL_FRONT, GL_LINE); + qglPolygonMode (GL_BACK, GL_FILL); + if(g_PrefsDlg.m_bGLLighting) { + qglEnable(GL_LIGHTING); + qglEnable(GL_COLOR_MATERIAL); + qglEnableClientState(GL_NORMAL_ARRAY); +// qglEnable(GL_RESCALE_NORMAL); + } + m_Camera.draw_glstate = DRAW_GL_SOLID; + break; + case cd_wire: + m_Camera.draw_glstate = DRAW_GL_WIRE; + break; + default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n"); + } + + + qglEnable(GL_BLEND); + m_Camera.draw_glstate |= DRAW_GL_BLEND; + qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + // FIXME: some .TGA are buggy, have a completely empty alpha channel + // if such brushes are rendered in this loop they would be totally transparent with GL_MODULATE + // so I decided using GL_DECAL instead + // if an empty-alpha-channel or nearly-empty texture is used. It will be blank-transparent. + // this could get better if you can get qglTexEnviv (GL_TEXTURE_ENV, to work .. patches are welcome + // Arnout: empty alpha channels are now always filled with data. Don't set this anymore (would cause problems with qer_alphafunc too) +// qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); + + Cam_DrawBrushes(DRAW_TEXTURED); + +// qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + qglDisable(GL_BLEND); + + // setup for wireframe stuff + switch(m_Camera.draw_mode) + { + case cd_texture: + if(g_PrefsDlg.m_bGLLighting) { + qglDisable(GL_COLOR_MATERIAL); + qglDisable(GL_LIGHTING); +// qglDisable(GL_RESCALE_NORMAL); + } + break; + case cd_solid: + if(g_PrefsDlg.m_bGLLighting) { + qglDisable(GL_COLOR_MATERIAL); + qglDisable(GL_LIGHTING); +// qglDisable(GL_RESCALE_NORMAL); + } + break; + case cd_wire: + break; + default: Sys_Printf("CamWnd::Cam_DrawStuff:invalid render mode\n"); + } + +} + +/* +============== +Cam_Draw +============== +*/ + +void QueueClear (); +void QueueDraw (); + +void CamWnd::Cam_Draw() +{ + brush_t *brush; + face_t *face; + float screenaspect; + float yfov; + double start, end; + int i; + + if (!active_brushes.next) + return; // not valid yet + + if (m_Camera.timing) + start = Sys_DoubleTime (); + + // + // clear + // + QE_CheckOpenGLForErrors(); + + qglViewport(0, 0, m_Camera.width, m_Camera.height); + qglClearColor (g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][0], + g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][1], + g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][2], 0); + qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // + // set up viewpoint + // + + + qglMatrixMode(GL_PROJECTION); + qglLoadIdentity (); + + screenaspect = (float)m_Camera.width / m_Camera.height; + yfov = 2*atan((float)m_Camera.height / m_Camera.width)*180/Q_PI; + qgluPerspective (yfov, screenaspect, 8, 32768); + + // we're too lazy to calc projection matrix ourselves!!! + qglGetFloatv (GL_PROJECTION_MATRIX, &m_Camera.projection[0][0]); + + vec3_t vec; + + m4x4_identity(&m_Camera.modelview[0][0]); + VectorSet(vec, -90, 0, 0); + m4x4_rotate_by_vec3(&m_Camera.modelview[0][0], vec, eXYZ); + VectorSet(vec, 0, 0, 90); + m4x4_rotate_by_vec3(&m_Camera.modelview[0][0], vec, eXYZ); + VectorSet(vec, 0, m_Camera.angles[0], 0); + m4x4_rotate_by_vec3(&m_Camera.modelview[0][0], vec, eXYZ); + VectorSet(vec, 0, 0, -m_Camera.angles[1]); + m4x4_rotate_by_vec3(&m_Camera.modelview[0][0], vec, eXYZ); + VectorSet(vec, -m_Camera.origin[0], -m_Camera.origin[1], -m_Camera.origin[2]); + m4x4_translate_by_vec3(&m_Camera.modelview[0][0], vec); + + Cam_BuildMatrix (); + + qglMatrixMode(GL_MODELVIEW); + qglLoadIdentity(); + + qglMultMatrixf(&m_Camera.modelview[0][0]); + + // grab the GL_PROJECTION and GL_MODELVIEW matrixes + // used in GetRelativeAxes + //qglGetFloatv (GL_PROJECTION_MATRIX, &m_Camera.projection[0][0]); + //qglGetFloatv (GL_MODELVIEW_MATRIX, &m_Camera.modelview[0][0]); + +#if 0 + // TTimo: this is not used, just for verification (0, 0, m_Camera.width, m_Camera.height) + GLint viewprt[4]; + qglGetIntegerv (GL_VIEWPORT, viewprt); +#endif + + if (g_PrefsDlg.m_bGLLighting) + { + GLfloat inverse_cam_dir[4], ambient[4], diffuse[4];//, material[4]; + + ambient[0] = ambient[1] = ambient[2] = 0.6f; + ambient[3] = 1.0f; + diffuse[0] = diffuse[1] = diffuse[2] = 0.4f; + diffuse[3] = 1.0f; + //material[0] = material[1] = material[2] = 0.8f; + //material[3] = 1.0f; + + vec3_t vCam, vRotate; + VectorSet(vCam, -1, 0, 0); //default cam pos + VectorSet(vRotate, 0, -m_Camera.angles[0], 0); + VectorRotate(vCam, vRotate, vCam); + VectorSet(vRotate, 0, 0, m_Camera.angles[1]); + VectorRotate(vCam, vRotate, vCam); + + inverse_cam_dir[0] = vCam[0]; + inverse_cam_dir[1] = vCam[1]; + inverse_cam_dir[2] = vCam[2]; + inverse_cam_dir[3] = 0; + + qglColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); + + qglLightfv(GL_LIGHT0, GL_POSITION, inverse_cam_dir); + + qglLightfv(GL_LIGHT0, GL_AMBIENT, ambient); + qglLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); + + qglEnable(GL_LIGHT0); + } + + InitCull (); + + // + // draw stuff + // + + Cam_DrawStuff(); + + qglEnableClientState(GL_VERTEX_ARRAY); + qglDisableClientState(GL_NORMAL_ARRAY); + qglDisableClientState(GL_TEXTURE_COORD_ARRAY); + qglDisable (GL_TEXTURE_2D); + qglDisable (GL_LIGHTING); + qglDisable (GL_COLOR_MATERIAL); + + qglEnable (GL_CULL_FACE); + + brush_t* pList = (g_bClipMode && g_pSplitList) ? g_pSplitList : &selected_brushes; + + if (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_BSEL) + { + qglColor4f(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][0], g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][1], g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][2], 0.3f); + qglEnable (GL_BLEND); + qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + qglDepthFunc (GL_LEQUAL); + for (brush = pList->next ; brush != pList ; brush=brush->next) + { + if (brush->bCamCulled) // draw selected faces of filtered brushes to remind that there is a selection + continue; + + if (brush->patchBrush && (g_qeglobals.d_select_mode == sel_curvepoint || g_qeglobals.d_select_mode == sel_area)) + continue; + + if (!g_PrefsDlg.m_bPatchBBoxSelect && brush->patchBrush) + { + DrawPatchMesh(brush->pPatch); + } + else if(brush->owner->model.pRender && g_PrefsDlg.m_nEntityShowState != ENTITY_BOX) + { + brush->owner->model.pRender->Draw(DRAW_GL_FLAT, (DRAW_RF_SEL_OUTLINE|DRAW_RF_CAM)); + } + else + { + for (face=brush->brush_faces ; face ; face=face->next) + Brush_FaceDraw(face, DRAW_GL_FLAT); + } + } + + + int nCount = g_ptrSelectedFaces.GetSize(); + if (nCount > 0) + { + for (int i = 0; i < nCount; i++) + { + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(i)); + Brush_FaceDraw(selFace, DRAW_GL_FLAT); + } + } + + qglDisableClientState(GL_NORMAL_ARRAY); + qglDepthFunc (GL_LESS); + } + + if (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_ZBUF) + { + // non-zbuffered outline + qglDisable (GL_BLEND); + qglDisable (GL_DEPTH_TEST); + qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + qglColor3f (1, 1, 1); + for (brush = pList->next ; brush != pList ; brush=brush->next) + { + if ((brush->patchBrush && (g_qeglobals.d_select_mode == sel_curvepoint || g_qeglobals.d_select_mode == sel_area))) + continue; + + if (!g_PrefsDlg.m_bPatchBBoxSelect && brush->patchBrush) + { + DrawPatchMesh(brush->pPatch); + } + else if(brush->owner->model.pRender && g_PrefsDlg.m_nEntityShowState != ENTITY_BOX) + { + brush->owner->model.pRender->Draw(DRAW_GL_WIRE, (DRAW_RF_SEL_FILL|DRAW_RF_CAM)); + + // Hydra : always draw bbox outline! + aabb_draw(brush->owner->model.pRender->GetAABB(), DRAW_GL_WIRE); + } + else + { + for (face=brush->brush_faces ; face ; face=face->next) + Brush_FaceDraw(face, DRAW_GL_WIRE); + } + } + } + + // edge / vertex flags + if (g_qeglobals.d_select_mode == sel_vertex) + { + // GL_POINTS on Kyro Workaround + if(!g_PrefsDlg.m_bGlPtWorkaround) + { + // brush verts + qglPointSize (4); + qglColor3f (0,1,0); + qglBegin (GL_POINTS); + for (i=0 ; inext) + brush->bCamCulled = false; + + for (brush = pList->next ; brush != pList ; brush=brush->next) + brush->bCamCulled = false; +} + +void CamWnd::OnExpose () +{ + if (!MakeCurrent ()) + { + Sys_Printf("ERROR: glXMakeCurrent failed..\n "); + Sys_Printf("Please restart Radiant if the camera view is not working\n"); + } + else + { + QE_CheckOpenGLForErrors(); + g_pSplitList = NULL; + if (g_bClipMode) + { + if (g_Clip1.Set() && g_Clip2.Set()) + { + g_pSplitList = (g_bSwitch) ? + &g_brBackSplits : &g_brFrontSplits; + } + } + + Patch_LODMatchAll(); // spog + + Cam_Draw (); + QE_CheckOpenGLForErrors (); + + m_XORRectangle.set(rectangle_t()); + SwapBuffers (); + } +} + +void CamWnd::BenchMark() +{ + if (!MakeCurrent ()) + Error ("glXMakeCurrent failed in Benchmark"); + + qglDrawBuffer (GL_FRONT); + double dStart = Sys_DoubleTime (); + for (int i=0 ; i < 100 ; i++) + { + m_Camera.angles[YAW] = i*4; + Cam_Draw(); + } + SwapBuffers (); + qglDrawBuffer (GL_BACK); + double dEnd = Sys_DoubleTime (); + Sys_Printf ("%5.2f seconds\n", dEnd - dStart); +} diff --git a/radiant/csg.cpp b/radiant/csg.cpp index 4e41a611..f5da8b74 100644 --- a/radiant/csg.cpp +++ b/radiant/csg.cpp @@ -1,687 +1,687 @@ -/* -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 -*/ - -#include "stdafx.h" -#include "winding.h" -#include "filters.h" - -/* -============= -CSG_MakeHollow -============= -*/ - -void Brush_Scale(brush_t* b) -{ - for (face_t* f = b->brush_faces ; f ; f=f->next) - { - for (int i=0 ; i<3 ; i++) - { - VectorScale (f->planepts[i], g_qeglobals.d_gridsize, f->planepts[i]); - } - } -} - -void CSG_MakeHollow (void) -{ - brush_t *b, *front, *back, *next; - face_t *f; - face_t split; - vec3_t move; - int i; - - for (b = selected_brushes.next ; b != &selected_brushes ; b=next) - { - next = b->next; - - if (b->owner->eclass->fixedsize || b->patchBrush || b->bFiltered) - continue; - - for (f = b->brush_faces ; f ; f=f->next) - { - split = *f; - VectorScale (f->plane.normal, g_qeglobals.d_gridsize, move); - for (i=0 ; i<3 ; i++) - VectorSubtract (split.planepts[i], move, split.planepts[i]); - - Brush_SplitBrushByFace (b, &split, &front, &back); - if (back) - Brush_Free (back); - if (front) - Brush_AddToList (front, &selected_brushes); - } - Brush_Free (b); - } - Sys_UpdateWindows (W_ALL); -} - -/* -============= -Brush_Merge - - Returns a new brush that is created by merging brush1 and brush2. - May return NULL if brush1 and brush2 do not create a convex brush when merged. - The input brushes brush1 and brush2 stay intact. - - if onlyshape is true then the merge is allowed based on the shape only - otherwise the texture/shader references of faces in the same plane have to - be the same as well. -============= -*/ -brush_t *Brush_Merge(brush_t *brush1, brush_t *brush2, int onlyshape) -{ - int i, shared; - brush_t *newbrush; - face_t *face1, *face2, *newface, *f; - - // check for bounding box overlapp - for (i = 0; i < 3; i++) - { - if (brush1->mins[i] > brush2->maxs[i] + ON_EPSILON - || brush1->maxs[i] < brush2->mins[i] - ON_EPSILON) - { - // never merge if the brushes overlap - return NULL; - } - } - // - shared = 0; - // check if the new brush would be convex... flipped planes make a brush non-convex - for (face1 = brush1->brush_faces; face1; face1 = face1->next) - { - // don't check the faces of brush 1 and 2 touching each other - for (face2 = brush2->brush_faces; face2; face2 = face2->next) - { - if (Plane_Equal(&face1->plane, &face2->plane, true)) - { - shared++; - // there may only be ONE shared side - if (shared > 1) - return NULL; - break; - } - } - // if this face plane is shared - if (face2) continue; - // - for (face2 = brush2->brush_faces; face2; face2 = face2->next) - { - // don't check the faces of brush 1 and 2 touching each other - for (f = brush1->brush_faces; f; f = f->next) - { - if (Plane_Equal(&face2->plane, &f->plane, true)) break; - } - if (f) - continue; - // - if (Plane_Equal(&face1->plane, &face2->plane, false)) - { - //if the texture/shader references should be the same but are not - if (!onlyshape && stricmp(face1->texdef.GetName(), face2->texdef.GetName()) != 0) return NULL; - continue; - } - // - if (Winding_PlanesConcave(face1->face_winding, face2->face_winding, - face1->plane.normal, face2->plane.normal, - face1->plane.dist, face2->plane.dist)) - { - return NULL; - } //end if - } //end for - } //end for - // - newbrush = Brush_Alloc(); - // - for (face1 = brush1->brush_faces; face1; face1 = face1->next) - { - // don't add the faces of brush 1 and 2 touching each other - for (face2 = brush2->brush_faces; face2; face2 = face2->next) - { - if (Plane_Equal(&face1->plane, &face2->plane, true)) - break; - } - if (face2) - continue; - // don't add faces with the same plane twice - for (f = newbrush->brush_faces; f; f = f->next) - { - if (Plane_Equal(&face1->plane, &f->plane, false)) - break; - if (Plane_Equal(&face1->plane, &f->plane, true)) - break; - } - if (f) - continue; - // - newface = Face_Alloc(); - newface->texdef = face1->texdef; - VectorCopy(face1->planepts[0], newface->planepts[0]); - VectorCopy(face1->planepts[1], newface->planepts[1]); - VectorCopy(face1->planepts[2], newface->planepts[2]); - newface->plane = face1->plane; - newface->next = newbrush->brush_faces; - newbrush->brush_faces = newface; - } - // - for (face2 = brush2->brush_faces; face2; face2 = face2->next) - { - // don't add the faces of brush 1 and 2 touching each other - for (face1 = brush1->brush_faces; face1; face1 = face1->next) - { - if (Plane_Equal(&face2->plane, &face1->plane, true)) - break; - } - if (face1) - continue; - // don't add faces with the same plane twice - for (f = newbrush->brush_faces; f; f = f->next) - { - if (Plane_Equal(&face2->plane, &f->plane, false)) - break; - if (Plane_Equal(&face2->plane, &f->plane, true)) - break; - } - if (f) - continue; - // - newface = Face_Alloc(); - newface->texdef = face2->texdef; - VectorCopy(face2->planepts[0], newface->planepts[0]); - VectorCopy(face2->planepts[1], newface->planepts[1]); - VectorCopy(face2->planepts[2], newface->planepts[2]); - newface->plane = face2->plane; - newface->next = newbrush->brush_faces; - newbrush->brush_faces = newface; - } - // link the new brush to an entity - Entity_LinkBrush (brush1->owner, newbrush); - // build windings for the faces - Brush_BuildWindings( newbrush, false); - - return newbrush; -} - -/* -============= -Brush_MergeListPairs - - Returns a list with merged brushes. - Tries to merge brushes pair wise. - The input list is destroyed. - Input and output should be a single linked list using .next -============= -*/ -brush_t *Brush_MergeListPairs(brush_t *brushlist, int onlyshape) -{ - int nummerges, merged; - brush_t *b1, *b2, *tail, *newbrush, *newbrushlist; - brush_t *lastb2; - - if (!brushlist) return NULL; - - nummerges = 0; - do - { - for (tail = brushlist; tail; tail = tail->next) - { - if (!tail->next) break; - } - merged = 0; - newbrushlist = NULL; - for (b1 = brushlist; b1; b1 = brushlist) - { - lastb2 = b1; - for (b2 = b1->next; b2; b2 = b2->next) - { - newbrush = Brush_Merge(b1, b2, onlyshape); - if (newbrush) - { - tail->next = newbrush; - lastb2->next = b2->next; - brushlist = brushlist->next; - b1->next = b1->prev = NULL; - b2->next = b2->prev = NULL; - Brush_Free(b1); - Brush_Free(b2); - for (tail = brushlist; tail; tail = tail->next) - { - if (!tail->next) break; - } //end for - merged++; - nummerges++; - break; - } - lastb2 = b2; - } - //if b1 can't be merged with any of the other brushes - if (!b2) - { - brushlist = brushlist->next; - //keep b1 - b1->next = newbrushlist; - newbrushlist = b1; - } - } - brushlist = newbrushlist; - } while(merged); - return newbrushlist; -} - -/* -============= -Brush_MergeList - - Tries to merge all brushes in the list into one new brush. - The input brush list stays intact. - Returns NULL if no merged brush can be created. - To create a new brush the brushes in the list may not overlap and - the outer faces of the brushes together should make a new convex brush. - - if onlyshape is true then the merge is allowed based on the shape only - otherwise the texture/shader references of faces in the same plane have to - be the same as well. -============= -*/ -brush_t *Brush_MergeList(brush_t *brushlist, int onlyshape) -{ - brush_t *brush1, *brush2, *brush3, *newbrush; - face_t *face1, *face2, *face3, *newface, *f; - - if (!brushlist) return NULL; - for (brush1 = brushlist; brush1; brush1 = brush1->next) - { - // check if the new brush would be convex... flipped planes make a brush concave - for (face1 = brush1->brush_faces; face1; face1 = face1->next) - { - // don't check face1 if it touches another brush - for (brush2 = brushlist; brush2; brush2 = brush2->next) - { - if (brush2 == brush1) continue; - for (face2 = brush2->brush_faces; face2; face2 = face2->next) - { - if (Plane_Equal(&face1->plane, &face2->plane, true)) - { - break; - } - } - if (face2) break; - } - // if face1 touches another brush - if (brush2) continue; - // - for (brush2 = brush1->next; brush2; brush2 = brush2->next) - { - // don't check the faces of brush 2 touching another brush - for (face2 = brush2->brush_faces; face2; face2 = face2->next) - { - for (brush3 = brushlist; brush3; brush3 = brush3->next) - { - if (brush3 == brush2) continue; - for (face3 = brush3->brush_faces; face3; face3 = face3->next) - { - if (Plane_Equal(&face2->plane, &face3->plane, true)) break; - } - if (face3) break; - } - // if face2 touches another brush - if (brush3) continue; - // - if (Plane_Equal(&face1->plane, &face2->plane, false)) - { - //if the texture/shader references should be the same but are not - if (!onlyshape && stricmp(face1->texdef.GetName(), face2->texdef.GetName()) != 0) return NULL; - continue; - } - // - if (Winding_PlanesConcave(face1->face_winding, face2->face_winding, - face1->plane.normal, face2->plane.normal, - face1->plane.dist, face2->plane.dist)) - { - return NULL; - } - } - } - } - } - // - newbrush = Brush_Alloc(); - // - for (brush1 = brushlist; brush1; brush1 = brush1->next) - { - for (face1 = brush1->brush_faces; face1; face1 = face1->next) - { - // don't add face1 to the new brush if it touches another brush - for (brush2 = brushlist; brush2; brush2 = brush2->next) - { - if (brush2 == brush1) continue; - for (face2 = brush2->brush_faces; face2; face2 = face2->next) - { - if (Plane_Equal(&face1->plane, &face2->plane, true)) - { - break; - } - } - if (face2) break; - } - if (brush2) continue; - // don't add faces with the same plane twice - for (f = newbrush->brush_faces; f; f = f->next) - { - if (Plane_Equal(&face1->plane, &f->plane, false)) - break; - if (Plane_Equal(&face1->plane, &f->plane, true)) - break; - } - if (f) - continue; - // - newface = Face_Alloc(); - newface->texdef = face1->texdef; - VectorCopy(face1->planepts[0], newface->planepts[0]); - VectorCopy(face1->planepts[1], newface->planepts[1]); - VectorCopy(face1->planepts[2], newface->planepts[2]); - newface->plane = face1->plane; - newface->next = newbrush->brush_faces; - newbrush->brush_faces = newface; - } - } - // link the new brush to an entity - Entity_LinkBrush (brushlist->owner, newbrush); - // build windings for the faces - Brush_BuildWindings( newbrush, false); - - return newbrush; -} - -/* -============= -Brush_Subtract - - Returns a list of brushes that remain after B is subtracted from A. - May by empty if A is contained inside B. - The originals are undisturbed. -============= -*/ -brush_t *Brush_Subtract(brush_t *a, brush_t *b) -{ - // a - b = out (list) - brush_t *front, *back; - brush_t *in, *out, *next; - face_t *f; - - in = a; - out = NULL; - for (f = b->brush_faces; f && in; f = f->next) - { - Brush_SplitBrushByFace(in, f, &front, &back); - if (in != a) Brush_Free(in); - if (front) - { // add to list - front->next = out; - out = front; - } - in = back; - } - //NOTE: in != a just in case brush b has no faces - if (in && in != a) - { - Brush_Free(in); - } - else - { //didn't really intersect - for (b = out; b; b = next) - { - next = b->next; - b->next = b->prev = NULL; - Brush_Free(b); - } - return a; - } - return out; -} - -/* -============= -CSG_Subtract -============= -*/ -void CSG_Subtract (void) -{ - brush_t *b, *s, *fragments, *nextfragment, *frag, *next, *snext; - brush_t fragmentlist; - int i, numfragments, numbrushes; - - Sys_Printf ("Subtracting...\n"); - - if (selected_brushes.next == &selected_brushes) - { - Sys_Printf("No brushes selected.\n"); - return; - } - - fragmentlist.next = &fragmentlist; - fragmentlist.prev = &fragmentlist; - - numfragments = 0; - numbrushes = 0; - for (b = selected_brushes.next ; b != &selected_brushes ; b=next) - { - next = b->next; - - if (b->owner->eclass->fixedsize) - continue; // can't use texture from a fixed entity, so don't subtract - - // chop all fragments further up - for (s = fragmentlist.next; s != &fragmentlist; s = snext) - { - snext = s->next; - - for (i=0 ; i<3 ; i++) - if (b->mins[i] >= s->maxs[i] - ON_EPSILON - || b->maxs[i] <= s->mins[i] + ON_EPSILON) - break; - if (i != 3) - continue; // definately don't touch - fragments = Brush_Subtract(s, b); - // if the brushes did not really intersect - if (fragments == s) - continue; - // try to merge fragments - fragments = Brush_MergeListPairs(fragments, true); - // add the fragments to the list - for (frag = fragments; frag; frag = nextfragment) - { - nextfragment = frag->next; - frag->next = NULL; - frag->owner = s->owner; - Brush_AddToList(frag, &fragmentlist); - } - // free the original brush - Brush_Free(s); - } - - // chop any active brushes up - for (s = active_brushes.next; s != &active_brushes; s = snext) - { - snext = s->next; - - if (s->owner->eclass->fixedsize || s->patchBrush || s->bFiltered) - continue; - - if (s->brush_faces->pShader->getFlags() & QER_NOCARVE) - { - continue; - } - - for (i=0 ; i<3 ; i++) - if (b->mins[i] >= s->maxs[i] - ON_EPSILON - || b->maxs[i] <= s->mins[i] + ON_EPSILON) - break; - if (i != 3) - continue; // definately don't touch - - fragments = Brush_Subtract(s, b); - // if the brushes did not really intersect - if (fragments == s) - continue; - // - Undo_AddBrush(s); - // one extra brush chopped up - numbrushes++; - // try to merge fragments - fragments = Brush_MergeListPairs(fragments, true); - // add the fragments to the list - for (frag = fragments; frag; frag = nextfragment) - { - nextfragment = frag->next; - frag->next = NULL; - frag->owner = s->owner; - Brush_AddToList(frag, &fragmentlist); - } - // free the original brush - Brush_Free(s); - } - } - - // move all fragments to the active brush list - for (frag = fragmentlist.next; frag != &fragmentlist; frag = nextfragment) - { - nextfragment = frag->next; - numfragments++; - Brush_RemoveFromList(frag); - Brush_AddToList(frag, &active_brushes); - Undo_EndBrush(frag); - } - - /*if (numfragments == 0) - { - Sys_Printf("Selected brush%s did not intersect with any other brushes.\n", - (selected_brushes.next->next == &selected_brushes) ? "":"es"); - return; - }*/ - Sys_Printf("done. (created %d fragment%s out of %d brush%s)\n", numfragments, (numfragments == 1)?"":"s", - numbrushes, (numbrushes == 1)?"":"es"); - Sys_UpdateWindows(W_ALL); -} - -/* -============= -CSG_Merge -============= -*/ -void CSG_Merge(void) -{ - brush_t *b, *next, *newlist, *newbrush; - struct entity_s *owner; - - Sys_Printf ("Merging...\n"); - - if (selected_brushes.next == &selected_brushes) - { - Sys_Printf("No brushes selected.\n"); - return; - } - - if (selected_brushes.next->next == &selected_brushes) - { - Sys_Printf("At least two brushes have to be selected.\n"); - return; - } - - owner = selected_brushes.next->owner; - - for (b = selected_brushes.next; b != &selected_brushes; b = next) - { - next = b->next; - - if (b->owner->eclass->fixedsize) - { - // can't use texture from a fixed entity, so don't subtract - Sys_Printf("Cannot add fixed size entities.\n"); - return; - } - - if (b->patchBrush) - { - Sys_Printf("Cannot add patches.\n"); - return; - } - - // TTimo: cleanup - // disable the qer_nocarve for CSG-MERGE operations -#if 0 - if (b->brush_faces->d_texture->bFromShader && (b->brush_faces->d_texture->nShaderFlags & QER_NOCARVE)) - { - Sys_Printf("Cannot add brushes using shaders that don't allows CSG operations.\n"); - return; - } -#endif - - if (b->owner != owner) - { - Sys_Printf("Cannot add brushes from different entities.\n"); - return; - } - - } - - newlist = NULL; - for (b = selected_brushes.next; b != &selected_brushes; b = next) - { - next = b->next; - - Brush_RemoveFromList(b); - b->next = newlist; - b->prev = NULL; - newlist = b; - } - - newbrush = Brush_MergeList(newlist, true); - // if the new brush would not be convex - if (!newbrush) - { - // add the brushes back into the selection - for (b = newlist; b; b = next) - { - next = b->next; - b->next = NULL; - b->prev = NULL; - Brush_AddToList(b, &selected_brushes); - } - Sys_Printf("Cannot add a set of brushes with a concave hull.\n"); - return; - } - // free the original brushes - for (b = newlist; b; b = next) - { - next = b->next; - b->next = NULL; - b->prev = NULL; - Brush_Free(b); - } - - newbrush->bFiltered = FilterBrush(newbrush); // spog - set filters for the new brush - - Brush_AddToList(newbrush, &selected_brushes); - - Sys_Printf ("done.\n"); - Sys_UpdateWindows (W_ALL); -} +/* +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 +*/ + +#include "stdafx.h" +#include "winding.h" +#include "filters.h" + +/* +============= +CSG_MakeHollow +============= +*/ + +void Brush_Scale(brush_t* b) +{ + for (face_t* f = b->brush_faces ; f ; f=f->next) + { + for (int i=0 ; i<3 ; i++) + { + VectorScale (f->planepts[i], g_qeglobals.d_gridsize, f->planepts[i]); + } + } +} + +void CSG_MakeHollow (void) +{ + brush_t *b, *front, *back, *next; + face_t *f; + face_t split; + vec3_t move; + int i; + + for (b = selected_brushes.next ; b != &selected_brushes ; b=next) + { + next = b->next; + + if (b->owner->eclass->fixedsize || b->patchBrush || b->bFiltered) + continue; + + for (f = b->brush_faces ; f ; f=f->next) + { + split = *f; + VectorScale (f->plane.normal, g_qeglobals.d_gridsize, move); + for (i=0 ; i<3 ; i++) + VectorSubtract (split.planepts[i], move, split.planepts[i]); + + Brush_SplitBrushByFace (b, &split, &front, &back); + if (back) + Brush_Free (back); + if (front) + Brush_AddToList (front, &selected_brushes); + } + Brush_Free (b); + } + Sys_UpdateWindows (W_ALL); +} + +/* +============= +Brush_Merge + + Returns a new brush that is created by merging brush1 and brush2. + May return NULL if brush1 and brush2 do not create a convex brush when merged. + The input brushes brush1 and brush2 stay intact. + + if onlyshape is true then the merge is allowed based on the shape only + otherwise the texture/shader references of faces in the same plane have to + be the same as well. +============= +*/ +brush_t *Brush_Merge(brush_t *brush1, brush_t *brush2, int onlyshape) +{ + int i, shared; + brush_t *newbrush; + face_t *face1, *face2, *newface, *f; + + // check for bounding box overlapp + for (i = 0; i < 3; i++) + { + if (brush1->mins[i] > brush2->maxs[i] + ON_EPSILON + || brush1->maxs[i] < brush2->mins[i] - ON_EPSILON) + { + // never merge if the brushes overlap + return NULL; + } + } + // + shared = 0; + // check if the new brush would be convex... flipped planes make a brush non-convex + for (face1 = brush1->brush_faces; face1; face1 = face1->next) + { + // don't check the faces of brush 1 and 2 touching each other + for (face2 = brush2->brush_faces; face2; face2 = face2->next) + { + if (Plane_Equal(&face1->plane, &face2->plane, true)) + { + shared++; + // there may only be ONE shared side + if (shared > 1) + return NULL; + break; + } + } + // if this face plane is shared + if (face2) continue; + // + for (face2 = brush2->brush_faces; face2; face2 = face2->next) + { + // don't check the faces of brush 1 and 2 touching each other + for (f = brush1->brush_faces; f; f = f->next) + { + if (Plane_Equal(&face2->plane, &f->plane, true)) break; + } + if (f) + continue; + // + if (Plane_Equal(&face1->plane, &face2->plane, false)) + { + //if the texture/shader references should be the same but are not + if (!onlyshape && stricmp(face1->texdef.GetName(), face2->texdef.GetName()) != 0) return NULL; + continue; + } + // + if (Winding_PlanesConcave(face1->face_winding, face2->face_winding, + face1->plane.normal, face2->plane.normal, + face1->plane.dist, face2->plane.dist)) + { + return NULL; + } //end if + } //end for + } //end for + // + newbrush = Brush_Alloc(); + // + for (face1 = brush1->brush_faces; face1; face1 = face1->next) + { + // don't add the faces of brush 1 and 2 touching each other + for (face2 = brush2->brush_faces; face2; face2 = face2->next) + { + if (Plane_Equal(&face1->plane, &face2->plane, true)) + break; + } + if (face2) + continue; + // don't add faces with the same plane twice + for (f = newbrush->brush_faces; f; f = f->next) + { + if (Plane_Equal(&face1->plane, &f->plane, false)) + break; + if (Plane_Equal(&face1->plane, &f->plane, true)) + break; + } + if (f) + continue; + // + newface = Face_Alloc(); + newface->texdef = face1->texdef; + VectorCopy(face1->planepts[0], newface->planepts[0]); + VectorCopy(face1->planepts[1], newface->planepts[1]); + VectorCopy(face1->planepts[2], newface->planepts[2]); + newface->plane = face1->plane; + newface->next = newbrush->brush_faces; + newbrush->brush_faces = newface; + } + // + for (face2 = brush2->brush_faces; face2; face2 = face2->next) + { + // don't add the faces of brush 1 and 2 touching each other + for (face1 = brush1->brush_faces; face1; face1 = face1->next) + { + if (Plane_Equal(&face2->plane, &face1->plane, true)) + break; + } + if (face1) + continue; + // don't add faces with the same plane twice + for (f = newbrush->brush_faces; f; f = f->next) + { + if (Plane_Equal(&face2->plane, &f->plane, false)) + break; + if (Plane_Equal(&face2->plane, &f->plane, true)) + break; + } + if (f) + continue; + // + newface = Face_Alloc(); + newface->texdef = face2->texdef; + VectorCopy(face2->planepts[0], newface->planepts[0]); + VectorCopy(face2->planepts[1], newface->planepts[1]); + VectorCopy(face2->planepts[2], newface->planepts[2]); + newface->plane = face2->plane; + newface->next = newbrush->brush_faces; + newbrush->brush_faces = newface; + } + // link the new brush to an entity + Entity_LinkBrush (brush1->owner, newbrush); + // build windings for the faces + Brush_BuildWindings( newbrush, false); + + return newbrush; +} + +/* +============= +Brush_MergeListPairs + + Returns a list with merged brushes. + Tries to merge brushes pair wise. + The input list is destroyed. + Input and output should be a single linked list using .next +============= +*/ +brush_t *Brush_MergeListPairs(brush_t *brushlist, int onlyshape) +{ + int nummerges, merged; + brush_t *b1, *b2, *tail, *newbrush, *newbrushlist; + brush_t *lastb2; + + if (!brushlist) return NULL; + + nummerges = 0; + do + { + for (tail = brushlist; tail; tail = tail->next) + { + if (!tail->next) break; + } + merged = 0; + newbrushlist = NULL; + for (b1 = brushlist; b1; b1 = brushlist) + { + lastb2 = b1; + for (b2 = b1->next; b2; b2 = b2->next) + { + newbrush = Brush_Merge(b1, b2, onlyshape); + if (newbrush) + { + tail->next = newbrush; + lastb2->next = b2->next; + brushlist = brushlist->next; + b1->next = b1->prev = NULL; + b2->next = b2->prev = NULL; + Brush_Free(b1); + Brush_Free(b2); + for (tail = brushlist; tail; tail = tail->next) + { + if (!tail->next) break; + } //end for + merged++; + nummerges++; + break; + } + lastb2 = b2; + } + //if b1 can't be merged with any of the other brushes + if (!b2) + { + brushlist = brushlist->next; + //keep b1 + b1->next = newbrushlist; + newbrushlist = b1; + } + } + brushlist = newbrushlist; + } while(merged); + return newbrushlist; +} + +/* +============= +Brush_MergeList + + Tries to merge all brushes in the list into one new brush. + The input brush list stays intact. + Returns NULL if no merged brush can be created. + To create a new brush the brushes in the list may not overlap and + the outer faces of the brushes together should make a new convex brush. + + if onlyshape is true then the merge is allowed based on the shape only + otherwise the texture/shader references of faces in the same plane have to + be the same as well. +============= +*/ +brush_t *Brush_MergeList(brush_t *brushlist, int onlyshape) +{ + brush_t *brush1, *brush2, *brush3, *newbrush; + face_t *face1, *face2, *face3, *newface, *f; + + if (!brushlist) return NULL; + for (brush1 = brushlist; brush1; brush1 = brush1->next) + { + // check if the new brush would be convex... flipped planes make a brush concave + for (face1 = brush1->brush_faces; face1; face1 = face1->next) + { + // don't check face1 if it touches another brush + for (brush2 = brushlist; brush2; brush2 = brush2->next) + { + if (brush2 == brush1) continue; + for (face2 = brush2->brush_faces; face2; face2 = face2->next) + { + if (Plane_Equal(&face1->plane, &face2->plane, true)) + { + break; + } + } + if (face2) break; + } + // if face1 touches another brush + if (brush2) continue; + // + for (brush2 = brush1->next; brush2; brush2 = brush2->next) + { + // don't check the faces of brush 2 touching another brush + for (face2 = brush2->brush_faces; face2; face2 = face2->next) + { + for (brush3 = brushlist; brush3; brush3 = brush3->next) + { + if (brush3 == brush2) continue; + for (face3 = brush3->brush_faces; face3; face3 = face3->next) + { + if (Plane_Equal(&face2->plane, &face3->plane, true)) break; + } + if (face3) break; + } + // if face2 touches another brush + if (brush3) continue; + // + if (Plane_Equal(&face1->plane, &face2->plane, false)) + { + //if the texture/shader references should be the same but are not + if (!onlyshape && stricmp(face1->texdef.GetName(), face2->texdef.GetName()) != 0) return NULL; + continue; + } + // + if (Winding_PlanesConcave(face1->face_winding, face2->face_winding, + face1->plane.normal, face2->plane.normal, + face1->plane.dist, face2->plane.dist)) + { + return NULL; + } + } + } + } + } + // + newbrush = Brush_Alloc(); + // + for (brush1 = brushlist; brush1; brush1 = brush1->next) + { + for (face1 = brush1->brush_faces; face1; face1 = face1->next) + { + // don't add face1 to the new brush if it touches another brush + for (brush2 = brushlist; brush2; brush2 = brush2->next) + { + if (brush2 == brush1) continue; + for (face2 = brush2->brush_faces; face2; face2 = face2->next) + { + if (Plane_Equal(&face1->plane, &face2->plane, true)) + { + break; + } + } + if (face2) break; + } + if (brush2) continue; + // don't add faces with the same plane twice + for (f = newbrush->brush_faces; f; f = f->next) + { + if (Plane_Equal(&face1->plane, &f->plane, false)) + break; + if (Plane_Equal(&face1->plane, &f->plane, true)) + break; + } + if (f) + continue; + // + newface = Face_Alloc(); + newface->texdef = face1->texdef; + VectorCopy(face1->planepts[0], newface->planepts[0]); + VectorCopy(face1->planepts[1], newface->planepts[1]); + VectorCopy(face1->planepts[2], newface->planepts[2]); + newface->plane = face1->plane; + newface->next = newbrush->brush_faces; + newbrush->brush_faces = newface; + } + } + // link the new brush to an entity + Entity_LinkBrush (brushlist->owner, newbrush); + // build windings for the faces + Brush_BuildWindings( newbrush, false); + + return newbrush; +} + +/* +============= +Brush_Subtract + + Returns a list of brushes that remain after B is subtracted from A. + May by empty if A is contained inside B. + The originals are undisturbed. +============= +*/ +brush_t *Brush_Subtract(brush_t *a, brush_t *b) +{ + // a - b = out (list) + brush_t *front, *back; + brush_t *in, *out, *next; + face_t *f; + + in = a; + out = NULL; + for (f = b->brush_faces; f && in; f = f->next) + { + Brush_SplitBrushByFace(in, f, &front, &back); + if (in != a) Brush_Free(in); + if (front) + { // add to list + front->next = out; + out = front; + } + in = back; + } + //NOTE: in != a just in case brush b has no faces + if (in && in != a) + { + Brush_Free(in); + } + else + { //didn't really intersect + for (b = out; b; b = next) + { + next = b->next; + b->next = b->prev = NULL; + Brush_Free(b); + } + return a; + } + return out; +} + +/* +============= +CSG_Subtract +============= +*/ +void CSG_Subtract (void) +{ + brush_t *b, *s, *fragments, *nextfragment, *frag, *next, *snext; + brush_t fragmentlist; + int i, numfragments, numbrushes; + + Sys_Printf ("Subtracting...\n"); + + if (selected_brushes.next == &selected_brushes) + { + Sys_Printf("No brushes selected.\n"); + return; + } + + fragmentlist.next = &fragmentlist; + fragmentlist.prev = &fragmentlist; + + numfragments = 0; + numbrushes = 0; + for (b = selected_brushes.next ; b != &selected_brushes ; b=next) + { + next = b->next; + + if (b->owner->eclass->fixedsize) + continue; // can't use texture from a fixed entity, so don't subtract + + // chop all fragments further up + for (s = fragmentlist.next; s != &fragmentlist; s = snext) + { + snext = s->next; + + for (i=0 ; i<3 ; i++) + if (b->mins[i] >= s->maxs[i] - ON_EPSILON + || b->maxs[i] <= s->mins[i] + ON_EPSILON) + break; + if (i != 3) + continue; // definately don't touch + fragments = Brush_Subtract(s, b); + // if the brushes did not really intersect + if (fragments == s) + continue; + // try to merge fragments + fragments = Brush_MergeListPairs(fragments, true); + // add the fragments to the list + for (frag = fragments; frag; frag = nextfragment) + { + nextfragment = frag->next; + frag->next = NULL; + frag->owner = s->owner; + Brush_AddToList(frag, &fragmentlist); + } + // free the original brush + Brush_Free(s); + } + + // chop any active brushes up + for (s = active_brushes.next; s != &active_brushes; s = snext) + { + snext = s->next; + + if (s->owner->eclass->fixedsize || s->patchBrush || s->bFiltered) + continue; + + if (s->brush_faces->pShader->getFlags() & QER_NOCARVE) + { + continue; + } + + for (i=0 ; i<3 ; i++) + if (b->mins[i] >= s->maxs[i] - ON_EPSILON + || b->maxs[i] <= s->mins[i] + ON_EPSILON) + break; + if (i != 3) + continue; // definately don't touch + + fragments = Brush_Subtract(s, b); + // if the brushes did not really intersect + if (fragments == s) + continue; + // + Undo_AddBrush(s); + // one extra brush chopped up + numbrushes++; + // try to merge fragments + fragments = Brush_MergeListPairs(fragments, true); + // add the fragments to the list + for (frag = fragments; frag; frag = nextfragment) + { + nextfragment = frag->next; + frag->next = NULL; + frag->owner = s->owner; + Brush_AddToList(frag, &fragmentlist); + } + // free the original brush + Brush_Free(s); + } + } + + // move all fragments to the active brush list + for (frag = fragmentlist.next; frag != &fragmentlist; frag = nextfragment) + { + nextfragment = frag->next; + numfragments++; + Brush_RemoveFromList(frag); + Brush_AddToList(frag, &active_brushes); + Undo_EndBrush(frag); + } + + /*if (numfragments == 0) + { + Sys_Printf("Selected brush%s did not intersect with any other brushes.\n", + (selected_brushes.next->next == &selected_brushes) ? "":"es"); + return; + }*/ + Sys_Printf("done. (created %d fragment%s out of %d brush%s)\n", numfragments, (numfragments == 1)?"":"s", + numbrushes, (numbrushes == 1)?"":"es"); + Sys_UpdateWindows(W_ALL); +} + +/* +============= +CSG_Merge +============= +*/ +void CSG_Merge(void) +{ + brush_t *b, *next, *newlist, *newbrush; + struct entity_s *owner; + + Sys_Printf ("Merging...\n"); + + if (selected_brushes.next == &selected_brushes) + { + Sys_Printf("No brushes selected.\n"); + return; + } + + if (selected_brushes.next->next == &selected_brushes) + { + Sys_Printf("At least two brushes have to be selected.\n"); + return; + } + + owner = selected_brushes.next->owner; + + for (b = selected_brushes.next; b != &selected_brushes; b = next) + { + next = b->next; + + if (b->owner->eclass->fixedsize) + { + // can't use texture from a fixed entity, so don't subtract + Sys_Printf("Cannot add fixed size entities.\n"); + return; + } + + if (b->patchBrush) + { + Sys_Printf("Cannot add patches.\n"); + return; + } + + // TTimo: cleanup + // disable the qer_nocarve for CSG-MERGE operations +#if 0 + if (b->brush_faces->d_texture->bFromShader && (b->brush_faces->d_texture->nShaderFlags & QER_NOCARVE)) + { + Sys_Printf("Cannot add brushes using shaders that don't allows CSG operations.\n"); + return; + } +#endif + + if (b->owner != owner) + { + Sys_Printf("Cannot add brushes from different entities.\n"); + return; + } + + } + + newlist = NULL; + for (b = selected_brushes.next; b != &selected_brushes; b = next) + { + next = b->next; + + Brush_RemoveFromList(b); + b->next = newlist; + b->prev = NULL; + newlist = b; + } + + newbrush = Brush_MergeList(newlist, true); + // if the new brush would not be convex + if (!newbrush) + { + // add the brushes back into the selection + for (b = newlist; b; b = next) + { + next = b->next; + b->next = NULL; + b->prev = NULL; + Brush_AddToList(b, &selected_brushes); + } + Sys_Printf("Cannot add a set of brushes with a concave hull.\n"); + return; + } + // free the original brushes + for (b = newlist; b; b = next) + { + next = b->next; + b->next = NULL; + b->prev = NULL; + Brush_Free(b); + } + + newbrush->bFiltered = FilterBrush(newbrush); // spog - set filters for the new brush + + Brush_AddToList(newbrush, &selected_brushes); + + Sys_Printf ("done.\n"); + Sys_UpdateWindows (W_ALL); +} diff --git a/radiant/dialog.cpp b/radiant/dialog.cpp index bbaa84d2..b85e3ed7 100644 --- a/radiant/dialog.cpp +++ b/radiant/dialog.cpp @@ -1,295 +1,295 @@ -/* -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 -*/ - -// -// Base dialog class, provides a way to run modal dialogs and -// set/get the widget values in member variables. -// -// Leonardo Zide (leo@lokigames.com) -// - -#include "stdafx.h" -#include -#include -#include - -typedef struct -{ - GtkObject *object; - void *buffer; - DLG_DATA_TYPE type; -} DLG_DATA; - -// ============================================================================= -// Dialog class - -Dialog::Dialog () -{ - m_pDataList = (GSList*)NULL; - m_nReturn = IDCANCEL; - m_bNeedBuild = true; - m_nLoop = 0; -} - -Dialog::~Dialog () -{ - while (m_pDataList) - { - free (m_pDataList->data); - m_pDataList = g_slist_remove (m_pDataList, m_pDataList->data); - } - - if (m_pWidget != NULL) - gtk_widget_destroy (m_pWidget); -} - -// i suspect that this is redundant - gtk manages to remember the data stored in its widgets across a hide/show -void Dialog::ShowDlg () -{ - Create (); - UpdateData (FALSE); - gtk_widget_show (m_pWidget); -} - -void Dialog::HideDlg () -{ - UpdateData (TRUE); - gtk_widget_hide (m_pWidget); -} - -static gint delete_event_callback(GtkWidget *widget, GdkEvent* event, gpointer data) -{ - reinterpret_cast(data)->HideDlg(); - reinterpret_cast(data)->EndModal(IDCANCEL); - return TRUE; -} - -void Dialog::Create () -{ - if (m_bNeedBuild) - { - m_pWidget = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_signal_connect (GTK_OBJECT (m_pWidget), "delete_event", - GTK_SIGNAL_FUNC (delete_event_callback), this); - gtk_signal_connect (GTK_OBJECT (m_pWidget), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (m_pWidget), "loop", &m_nLoop); - g_object_set_data (G_OBJECT (m_pWidget), "ret", &m_nReturn); - - BuildDialog (); - m_bNeedBuild = false; - } -} - -void Dialog::Destroy () -{ - if (m_pWidget != NULL) - { - gtk_widget_destroy (m_pWidget); - m_pWidget = NULL; - } -} - -void Dialog::AddDialogData (GtkObject *object, void *buf, DLG_DATA_TYPE type) -{ - DLG_DATA *data; - - data = (DLG_DATA*)qmalloc (sizeof(DLG_DATA)); - data->object = object; - data->buffer = buf; - data->type = type; - - m_pDataList = g_slist_append (m_pDataList, data); -} - -void Dialog::AddModalButton (GtkWidget *widget, int ret) -{ - gtk_signal_connect (GTK_OBJECT (widget), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (ret)); -} - -void Dialog::UpdateData (bool retrieve) - { - DLG_DATA *data; - GSList *lst; - char buf[32]; - - if (retrieve) - { - for (lst = m_pDataList; lst != NULL; lst = g_slist_next (lst)) - { - data = (DLG_DATA*)lst->data; - - switch (data->type) - { - case DLG_CHECK_BOOL: - *(bool*)data->buffer = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->object)); - break; - case DLG_RADIO_INT: - { - GSList *radio = gtk_radio_button_group (GTK_RADIO_BUTTON (data->object)); - *(int*)data->buffer = g_slist_length (radio) - 1; - for (; radio; radio = g_slist_next (radio)) - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio->data))) - break; - else - (*(int*)data->buffer)--; - } break; - case DLG_ENTRY_TEXT: - { - const char *txt; - Str* str; - str = (Str*)data->buffer; - txt = gtk_entry_get_text (GTK_ENTRY (data->object)); - *str = txt; - } break; - case DLG_ENTRY_FLOAT: - *(float*)data->buffer = atof (gtk_entry_get_text (GTK_ENTRY (data->object))); - break; - case DLG_ENTRY_INT: - *(int*)data->buffer = atoi (gtk_entry_get_text (GTK_ENTRY (data->object))); - break; - case DLG_SPIN_FLOAT: - *(float*)data->buffer = gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (data->object)); - break; - case DLG_SPIN_INT: - *(int*)data->buffer = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (data->object)); - break; - case DLG_ADJ_INT: - *(int*)data->buffer = (int) GTK_ADJUSTMENT (data->object)->value; - break; - case DLG_COMBO_INT: - { - GList *lst = GTK_LIST (GTK_COMBO (data->object)->list)->children; - char *label; - const char *entry; - int i; - - *(int*)data->buffer = -1; - entry = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (data->object)->entry)); - - for (i = 0; lst != NULL; lst = g_list_next (lst)) - { - gtk_label_get (GTK_LABEL (GTK_BIN (lst->data)->child), &label); - - if (strcmp (label, entry) == 0) - { - *(int*)data->buffer = i; - break; - } - i++; - } - } break; - } - } - } - else - { - for (lst = m_pDataList; lst != NULL; lst = g_slist_next (lst)) - { - data = (DLG_DATA*)lst->data; - - switch (data->type) - { - case DLG_CHECK_BOOL: - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (data->object), *(bool*)data->buffer); - break; - case DLG_RADIO_INT: - { - GSList *radio = gtk_radio_button_group (GTK_RADIO_BUTTON (data->object)); - gpointer btn = g_slist_nth_data (radio, g_slist_length (radio) - (*(int*)data->buffer) - 1); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (btn), TRUE); - } break; - case DLG_ENTRY_TEXT: - { - Str* str; - str = (Str*)data->buffer; - const char *txt = str->GetBuffer (); - gtk_entry_set_text (GTK_ENTRY (data->object), txt); - } break; - case DLG_ENTRY_FLOAT: - sprintf (buf, "%g", (*(float*)data->buffer)); - gtk_entry_set_text (GTK_ENTRY (data->object), buf); - break; - case DLG_ENTRY_INT: - sprintf (buf, "%d", (*(int*)data->buffer)); - gtk_entry_set_text (GTK_ENTRY (data->object), buf); - break; - case DLG_SPIN_FLOAT: - gtk_spin_button_set_value (GTK_SPIN_BUTTON (data->object), (*(float*)data->buffer)); - break; - case DLG_SPIN_INT: - gtk_spin_button_set_value (GTK_SPIN_BUTTON (data->object), (*(int*)data->buffer)); - break; - case DLG_ADJ_INT: - gtk_adjustment_set_value (GTK_ADJUSTMENT (data->object), (*(int*)data->buffer)); - break; - case DLG_COMBO_INT: - { - GList *lst = GTK_LIST (GTK_COMBO (data->object)->list)->children; - char *entry = ""; - - if (*(int*)data->buffer != -1) - { - lst = g_list_nth (lst, *(int*)data->buffer); - if (lst != NULL) - gtk_label_get (GTK_LABEL (GTK_BIN (lst->data)->child), &entry); - } - - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (data->object)->entry), entry); - } break; - } - } - } -} - -void Dialog::EndModal (int code) -{ - m_nLoop = 0; - m_nReturn = code; -} - -int Dialog::DoModal () -{ - Create (); - UpdateData (FALSE); - - PreModal(); - - gtk_grab_add (m_pWidget); - gtk_widget_show (m_pWidget); - - m_nLoop = 1; - while (m_nLoop) - gtk_main_iteration (); - - if (m_pWidget != NULL) - { - UpdateData (TRUE); - - gtk_grab_remove (m_pWidget); - gtk_widget_hide (m_pWidget); - } - PostModal (m_nReturn); - - return m_nReturn; -} - +/* +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 +*/ + +// +// Base dialog class, provides a way to run modal dialogs and +// set/get the widget values in member variables. +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" +#include +#include +#include + +typedef struct +{ + GtkObject *object; + void *buffer; + DLG_DATA_TYPE type; +} DLG_DATA; + +// ============================================================================= +// Dialog class + +Dialog::Dialog () +{ + m_pDataList = (GSList*)NULL; + m_nReturn = IDCANCEL; + m_bNeedBuild = true; + m_nLoop = 0; +} + +Dialog::~Dialog () +{ + while (m_pDataList) + { + free (m_pDataList->data); + m_pDataList = g_slist_remove (m_pDataList, m_pDataList->data); + } + + if (m_pWidget != NULL) + gtk_widget_destroy (m_pWidget); +} + +// i suspect that this is redundant - gtk manages to remember the data stored in its widgets across a hide/show +void Dialog::ShowDlg () +{ + Create (); + UpdateData (FALSE); + gtk_widget_show (m_pWidget); +} + +void Dialog::HideDlg () +{ + UpdateData (TRUE); + gtk_widget_hide (m_pWidget); +} + +static gint delete_event_callback(GtkWidget *widget, GdkEvent* event, gpointer data) +{ + reinterpret_cast(data)->HideDlg(); + reinterpret_cast(data)->EndModal(IDCANCEL); + return TRUE; +} + +void Dialog::Create () +{ + if (m_bNeedBuild) + { + m_pWidget = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_signal_connect (GTK_OBJECT (m_pWidget), "delete_event", + GTK_SIGNAL_FUNC (delete_event_callback), this); + gtk_signal_connect (GTK_OBJECT (m_pWidget), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (m_pWidget), "loop", &m_nLoop); + g_object_set_data (G_OBJECT (m_pWidget), "ret", &m_nReturn); + + BuildDialog (); + m_bNeedBuild = false; + } +} + +void Dialog::Destroy () +{ + if (m_pWidget != NULL) + { + gtk_widget_destroy (m_pWidget); + m_pWidget = NULL; + } +} + +void Dialog::AddDialogData (GtkObject *object, void *buf, DLG_DATA_TYPE type) +{ + DLG_DATA *data; + + data = (DLG_DATA*)qmalloc (sizeof(DLG_DATA)); + data->object = object; + data->buffer = buf; + data->type = type; + + m_pDataList = g_slist_append (m_pDataList, data); +} + +void Dialog::AddModalButton (GtkWidget *widget, int ret) +{ + gtk_signal_connect (GTK_OBJECT (widget), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (ret)); +} + +void Dialog::UpdateData (bool retrieve) + { + DLG_DATA *data; + GSList *lst; + char buf[32]; + + if (retrieve) + { + for (lst = m_pDataList; lst != NULL; lst = g_slist_next (lst)) + { + data = (DLG_DATA*)lst->data; + + switch (data->type) + { + case DLG_CHECK_BOOL: + *(bool*)data->buffer = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->object)); + break; + case DLG_RADIO_INT: + { + GSList *radio = gtk_radio_button_group (GTK_RADIO_BUTTON (data->object)); + *(int*)data->buffer = g_slist_length (radio) - 1; + for (; radio; radio = g_slist_next (radio)) + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio->data))) + break; + else + (*(int*)data->buffer)--; + } break; + case DLG_ENTRY_TEXT: + { + const char *txt; + Str* str; + str = (Str*)data->buffer; + txt = gtk_entry_get_text (GTK_ENTRY (data->object)); + *str = txt; + } break; + case DLG_ENTRY_FLOAT: + *(float*)data->buffer = atof (gtk_entry_get_text (GTK_ENTRY (data->object))); + break; + case DLG_ENTRY_INT: + *(int*)data->buffer = atoi (gtk_entry_get_text (GTK_ENTRY (data->object))); + break; + case DLG_SPIN_FLOAT: + *(float*)data->buffer = gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (data->object)); + break; + case DLG_SPIN_INT: + *(int*)data->buffer = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (data->object)); + break; + case DLG_ADJ_INT: + *(int*)data->buffer = (int) GTK_ADJUSTMENT (data->object)->value; + break; + case DLG_COMBO_INT: + { + GList *lst = GTK_LIST (GTK_COMBO (data->object)->list)->children; + char *label; + const char *entry; + int i; + + *(int*)data->buffer = -1; + entry = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (data->object)->entry)); + + for (i = 0; lst != NULL; lst = g_list_next (lst)) + { + gtk_label_get (GTK_LABEL (GTK_BIN (lst->data)->child), &label); + + if (strcmp (label, entry) == 0) + { + *(int*)data->buffer = i; + break; + } + i++; + } + } break; + } + } + } + else + { + for (lst = m_pDataList; lst != NULL; lst = g_slist_next (lst)) + { + data = (DLG_DATA*)lst->data; + + switch (data->type) + { + case DLG_CHECK_BOOL: + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (data->object), *(bool*)data->buffer); + break; + case DLG_RADIO_INT: + { + GSList *radio = gtk_radio_button_group (GTK_RADIO_BUTTON (data->object)); + gpointer btn = g_slist_nth_data (radio, g_slist_length (radio) - (*(int*)data->buffer) - 1); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (btn), TRUE); + } break; + case DLG_ENTRY_TEXT: + { + Str* str; + str = (Str*)data->buffer; + const char *txt = str->GetBuffer (); + gtk_entry_set_text (GTK_ENTRY (data->object), txt); + } break; + case DLG_ENTRY_FLOAT: + sprintf (buf, "%g", (*(float*)data->buffer)); + gtk_entry_set_text (GTK_ENTRY (data->object), buf); + break; + case DLG_ENTRY_INT: + sprintf (buf, "%d", (*(int*)data->buffer)); + gtk_entry_set_text (GTK_ENTRY (data->object), buf); + break; + case DLG_SPIN_FLOAT: + gtk_spin_button_set_value (GTK_SPIN_BUTTON (data->object), (*(float*)data->buffer)); + break; + case DLG_SPIN_INT: + gtk_spin_button_set_value (GTK_SPIN_BUTTON (data->object), (*(int*)data->buffer)); + break; + case DLG_ADJ_INT: + gtk_adjustment_set_value (GTK_ADJUSTMENT (data->object), (*(int*)data->buffer)); + break; + case DLG_COMBO_INT: + { + GList *lst = GTK_LIST (GTK_COMBO (data->object)->list)->children; + char *entry = ""; + + if (*(int*)data->buffer != -1) + { + lst = g_list_nth (lst, *(int*)data->buffer); + if (lst != NULL) + gtk_label_get (GTK_LABEL (GTK_BIN (lst->data)->child), &entry); + } + + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (data->object)->entry), entry); + } break; + } + } + } +} + +void Dialog::EndModal (int code) +{ + m_nLoop = 0; + m_nReturn = code; +} + +int Dialog::DoModal () +{ + Create (); + UpdateData (FALSE); + + PreModal(); + + gtk_grab_add (m_pWidget); + gtk_widget_show (m_pWidget); + + m_nLoop = 1; + while (m_nLoop) + gtk_main_iteration (); + + if (m_pWidget != NULL) + { + UpdateData (TRUE); + + gtk_grab_remove (m_pWidget); + gtk_widget_hide (m_pWidget); + } + PostModal (m_nReturn); + + return m_nReturn; +} + diff --git a/radiant/dialoginfo.cpp b/radiant/dialoginfo.cpp index cdba7f24..54a7472c 100644 --- a/radiant/dialoginfo.cpp +++ b/radiant/dialoginfo.cpp @@ -1,75 +1,75 @@ -/* -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 -*/ - -// -// InfoDialog - non-modal, not derived from Dialog -// -// Leonardo Zide (leo@lokigames.com) -// - -#include "stdafx.h" -#include -//#include "qe3.h" - -GtkWidget *g_dlgInfo; -GtkWidget *s_pEdit; - -// ============================================================================= -// Global functions - -void ShowInfoDialog(const char* pText) -{ - if (g_dlgInfo == NULL) - { - GtkWidget *dlg, *scr, *text; - - g_dlgInfo = dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "Information"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (gtk_widget_hide), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - gtk_window_set_default_size (GTK_WINDOW (dlg), 300, 150); - - scr = gtk_scrolled_window_new (NULL, NULL); - gtk_widget_show (scr); - gtk_container_add (GTK_CONTAINER (dlg), scr); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_container_set_border_width (GTK_CONTAINER (scr), 5); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); - - s_pEdit = text = gtk_text_view_new(); - gtk_container_add (GTK_CONTAINER (scr), text); - gtk_widget_show (text); - gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD); - } - - GtkTextBuffer* buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(s_pEdit)); - gtk_text_buffer_set_text (buffer, pText, -1); - gtk_widget_show (g_dlgInfo); -} - -void HideInfoDialog() -{ - if (g_dlgInfo) - gtk_widget_hide (g_dlgInfo); -} - +/* +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 +*/ + +// +// InfoDialog - non-modal, not derived from Dialog +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" +#include +//#include "qe3.h" + +GtkWidget *g_dlgInfo; +GtkWidget *s_pEdit; + +// ============================================================================= +// Global functions + +void ShowInfoDialog(const char* pText) +{ + if (g_dlgInfo == NULL) + { + GtkWidget *dlg, *scr, *text; + + g_dlgInfo = dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Information"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (gtk_widget_hide), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_window_set_default_size (GTK_WINDOW (dlg), 300, 150); + + scr = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scr); + gtk_container_add (GTK_CONTAINER (dlg), scr); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_container_set_border_width (GTK_CONTAINER (scr), 5); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); + + s_pEdit = text = gtk_text_view_new(); + gtk_container_add (GTK_CONTAINER (scr), text); + gtk_widget_show (text); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD); + } + + GtkTextBuffer* buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(s_pEdit)); + gtk_text_buffer_set_text (buffer, pText, -1); + gtk_widget_show (g_dlgInfo); +} + +void HideInfoDialog() +{ + if (g_dlgInfo) + gtk_widget_hide (g_dlgInfo); +} + diff --git a/radiant/drag.cpp b/radiant/drag.cpp index f9e67aef..d8df7b82 100644 --- a/radiant/drag.cpp +++ b/radiant/drag.cpp @@ -1,845 +1,845 @@ -/* -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 -*/ - -#include "stdafx.h" -//#include "qe3.h" - -/* - - drag either multiple brushes, or select plane points from - a single brush. - -*/ - -extern int g_nPatchClickedView; - -qboolean drag_ok; -vec3_t drag_xvec; -vec3_t drag_yvec; - -//static int buttonstate; -int pressx, pressy; -static vec3_t pressdelta; -static vec3_t vPressStart; -//static int buttonx, buttony; - - -//int num_move_points; -//float *move_points[1024]; - -int lastx, lasty; - -qboolean drag_first; - - -void AxializeVector (vec3_t v) -{ - vec3_t a; - float o; - int i; - - if (!v[0] && !v[1]) - return; - if (!v[1] && !v[2]) - return; - if (!v[0] && !v[2]) - return; - - for (i=0 ; i<3 ; i++) - a[i] = fabs(v[i]); - if (a[0] > a[1] && a[0] > a[2]) - i = 0; - else if (a[1] > a[0] && a[1] > a[2]) - i = 1; - else - i = 2; - - o = v[i]; - VectorCopy (vec3_origin, v); - if (o<0) - v[i] = -1; - else - v[i] = 1; - -} - -/* -=========== -Drag_Setup -=========== -*/ -extern void SelectCurvePointByRay (vec3_t org, vec3_t dir, int buttons); - -void Drag_Setup (int x, int y, int buttons, - vec3_t xaxis, vec3_t yaxis, - vec3_t origin, vec3_t dir) -{ - trace_t t; - face_t *f; - - drag_first = true; - - VectorCopy (vec3_origin, pressdelta); - pressx = x; - pressy = y; - - // snap to nearest axis for camwindow drags - VectorCopy (xaxis, drag_xvec); - AxializeVector (drag_xvec); - VectorCopy (yaxis, drag_yvec); - AxializeVector (drag_yvec); - - if (g_qeglobals.d_select_mode == sel_curvepoint) - { - SelectCurvePointByRay (origin, dir, buttons); - - if(g_qeglobals.d_select_mode == sel_area) - { - drag_ok = true; - - if(g_nPatchClickedView == W_CAMERA ) { - VectorSet( g_qeglobals.d_vAreaTL, x, y, 0 ); - VectorSet( g_qeglobals.d_vAreaBR, x, y, 0 ); - } - } - else if (g_qeglobals.d_num_move_points) // don't add an undo if there are no points selected - { - drag_ok = true; - Sys_UpdateWindows(W_ALL); - Undo_Start("drag curve point"); - Undo_AddBrushList(&selected_brushes); - } - return; - } - else - { - g_qeglobals.d_num_move_points = 0; - } - - if (g_qeglobals.d_select_mode == sel_areatall) - { - VectorCopy(origin, g_qeglobals.d_vAreaTL); - VectorCopy(origin, g_qeglobals.d_vAreaBR); - - Sys_UpdateWindows(W_ALL); - - drag_ok = true; - return; - } - - if (selected_brushes.next == &selected_brushes) - { - //in this case a new brush is created when the dragging - //takes place in the XYWnd, An useless undo is created - //when the dragging takes place in the CamWnd - Undo_Start("create brush"); - - Sys_Status("No selection to drag", 0); - return; - } - - if (g_qeglobals.d_select_mode == sel_vertex) - { - SelectVertexByRay (origin, dir); - if (g_qeglobals.d_num_move_points) - { - drag_ok = true; - Undo_Start("drag vertex"); - Undo_AddBrushList(&selected_brushes); - // Need an update here for highlighting selected vertices - Sys_UpdateWindows(W_XY | W_CAMERA); - return; - } - } - - if (g_qeglobals.d_select_mode == sel_edge) - { - SelectEdgeByRay (origin, dir); - if (g_qeglobals.d_num_move_points) - { - drag_ok = true; - Undo_Start("drag edge"); - Undo_AddBrushList(&selected_brushes); - return; - } - } - - // - // check for direct hit first - // - t = Test_Ray (origin, dir, true); - if (t.selected) - { - drag_ok = true; - - Undo_Start("drag selection"); - Undo_AddBrushList(&selected_brushes); - - if (buttons == (MK_LBUTTON|MK_CONTROL) ) - { - Sys_Printf ("Shear dragging face\n"); - Brush_SelectFaceForDragging (t.brush, t.face, true); - } - else if (buttons == (MK_LBUTTON|MK_CONTROL|MK_SHIFT) ) - { - Sys_Printf ("Sticky dragging brush\n"); - for (f=t.brush->brush_faces ; f ; f=f->next) - Brush_SelectFaceForDragging (t.brush, f, false); - } - else - Sys_Printf ("Dragging entire selection\n"); - - return; - } - - if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge) - return; - - // - // check for side hit - // - // multiple brushes selected? - if (selected_brushes.next->next != &selected_brushes) - { - // yes, special handling - bool bOK = (g_PrefsDlg.m_bALTEdge) ? Sys_AltDown() : true; - if (bOK) - { - for (brush_t* pBrush = selected_brushes.next ; pBrush != &selected_brushes ; pBrush = pBrush->next) - { - if (buttons & MK_CONTROL) - Brush_SideSelect (pBrush, origin, dir, true); - else - Brush_SideSelect (pBrush, origin, dir, false); - } - } - else - { - Sys_Printf ("press ALT to drag multiple edges\n"); - return; - } - } - else - { - // single select.. trying to drag fixed entities handle themselves and just move - if (buttons & MK_CONTROL) - Brush_SideSelect (selected_brushes.next, origin, dir, true); - else - Brush_SideSelect (selected_brushes.next, origin, dir, false); - } - - Sys_Printf ("Side stretch\n"); - drag_ok = true; - - Undo_Start("side stretch"); - Undo_AddBrushList(&selected_brushes); -} - -entity_t *peLink; - -void UpdateTarget(vec3_t origin, vec3_t dir) -{ - trace_t t; - entity_t *pe; - int i; - char sz[128]; - - t = Test_Ray (origin, dir, 0); - - if (!t.brush) - return; - - pe = t.brush->owner; - - if (pe == NULL) - return; - - // is this the first? - if (peLink != NULL) - { - - // Get the target id from out current target - // if there is no id, make one - - i = IntForKey(pe, "target"); - if (i <= 0) - { - i = GetUniqueTargetId(1); - sprintf(sz, "%d", i); - - SetKeyValue(pe, "target", sz); - } - - // set the target # into our src - - sprintf(sz, "%d", i); - SetKeyValue(peLink, "targetname", sz); - - Sys_UpdateWindows(W_ENTITY); - - } - - // promote the target to the src - - peLink = pe; - -} - -/* -=========== -Drag_Begin -//++timo test three button mouse and three button emulation here ? -=========== -*/ -void Drag_Begin (int x, int y, int buttons, - vec3_t xaxis, vec3_t yaxis, - vec3_t origin, vec3_t dir, bool sf_camera) -{ - trace_t t; - bool altdown; - int nFlag; - - drag_ok = false; - VectorCopy (vec3_origin, pressdelta); - VectorCopy (vec3_origin, vPressStart); - - drag_first = true; - peLink = NULL; - - altdown = Sys_AltDown(); - - // shift-LBUTTON = select entire brush - // shift-alt-LBUTTON = drill select - if (buttons == (MK_LBUTTON | MK_SHIFT) && g_qeglobals.d_select_mode != sel_curvepoint) - { - nFlag = altdown ? SF_CYCLE : 0; - if (sf_camera) - nFlag |= SF_CAMERA; - else - nFlag |= SF_ENTITIES_FIRST; - Select_Ray(origin, dir, nFlag); - return; - } - - // (shift-)alt-LBUTTON = area select completely tall - if ( !sf_camera && - ( g_PrefsDlg.m_bALTEdge ? buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT) : (buttons == MK_LBUTTON || buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) ) && - altdown && g_qeglobals.d_select_mode != sel_curvepoint) - { - if (g_pParentWnd->ActiveXY()->AreaSelectOK()) - { - g_qeglobals.d_select_mode = sel_areatall; - - Drag_Setup (x, y, buttons, xaxis, yaxis, origin, dir); - return; - } - } - - // ctrl-alt-LBUTTON = multiple brush select without selecting whole entities - if (buttons == (MK_LBUTTON | MK_CONTROL) && altdown && g_qeglobals.d_select_mode != sel_curvepoint) - { - nFlag = 0; - if (sf_camera) - nFlag |= SF_CAMERA; - else - nFlag |= SF_ENTITIES_FIRST; - Select_Ray (origin, dir, nFlag); - UpdateSurfaceDialog(); - - return; - } - - // ctrl-shift LBUTTON = select single face - if (sf_camera && buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT) && g_qeglobals.d_select_mode != sel_curvepoint) - { - if(Sys_AltDown()) - { - brush_t *b; - for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - { - if(b->pPatch) - continue; - - for (face_t* pFace = b->brush_faces; pFace; pFace = pFace->next) - { - g_ptrSelectedFaces.Add(pFace); - g_ptrSelectedFaceBrushes.Add(b); - } - } - - for (b = selected_brushes.next; b != &selected_brushes; ) - { - brush_t *pb = b; - b = b->next; - Brush_RemoveFromList (pb); - Brush_AddToList (pb, &active_brushes); - } - } - else - Select_Deselect (true); - - Select_Ray (origin, dir, (SF_SINGLEFACE|SF_CAMERA)); - return; - } - - - // LBUTTON + all other modifiers = manipulate selection - if (buttons & MK_LBUTTON) - { - Drag_Setup (x, y, buttons, xaxis, yaxis, origin, dir); - return; - } - - int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON; - // middle button = grab texture - if (buttons == nMouseButton) - { - t = Test_Ray (origin, dir, false); - if (t.face) - { - UpdateWorkzone_ForBrush( t.brush ); - // use a local brushprimit_texdef fitted to a default 2x2 texture - brushprimit_texdef_t bp_local; - ConvertTexMatWithQTexture( &t.face->brushprimit_texdef, t.face->d_texture, &bp_local, NULL ); - Texture_SetTexture ( &t.face->texdef, &bp_local, false, NULL); - UpdateSurfaceDialog(); - UpdatePatchInspector(); - } - else - Sys_Printf ("Did not select a texture\n"); - return; - } - - // ctrl-middle button = set entire brush to texture - if (buttons == (nMouseButton|MK_CONTROL) ) - { - t = Test_Ray (origin, dir, false); - if (t.brush) - { - if (t.brush->brush_faces->texdef.GetName()[0] == '(') - Sys_Printf ("Can't change an entity texture\n"); - else - { - Brush_SetTexture (t.brush, &g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef, false, static_cast( g_qeglobals.d_texturewin.pTexdef ) ); - Sys_UpdateWindows (W_ALL); - } - } - else - Sys_Printf ("Didn't hit a btrush\n"); - return; - } - - // ctrl-shift-middle button = set single face to texture - if (buttons == (nMouseButton|MK_SHIFT|MK_CONTROL) ) - { - t = Test_Ray (origin, dir, false); - if (t.brush) - { - if (t.brush->brush_faces->texdef.GetName()[0] == '(') - Sys_Printf ("Can't change an entity texture\n"); - else - { - SetFaceTexdef (t.face, &g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef); - Brush_Build( t.brush ); - - Sys_UpdateWindows (W_ALL); - } - } - else - Sys_Printf ("Didn't hit a btrush\n"); - return; - } - - if (buttons == (nMouseButton | MK_SHIFT)) - { - Sys_Printf("Set brush face texture info\n"); - t = Test_Ray (origin, dir, false); - if (t.brush) - { - if (t.brush->brush_faces->texdef.GetName()[0] == '(') - { - if (t.brush->owner->eclass->nShowFlags & ECLASS_LIGHT) - { - CString strBuff; - qtexture_t* pTex = g_qeglobals.d_texturewin.pShader->getTexture(); - if (pTex) - { - vec3_t vColor; - VectorCopy(pTex->color, vColor); - - float fLargest = 0.0f; - for (int i = 0; i < 3; i++) - { - if (vColor[i] > fLargest) - fLargest = vColor[i]; - } - - if (fLargest == 0.0f) - { - vColor[0] = vColor[1] = vColor[2] = 1.0f; - } - else - { - float fScale = 1.0f / fLargest; - for (int i = 0; i < 3; i++) - { - vColor[i] *= fScale; - } - } - strBuff.Format("%f %f %f",pTex->color[0], pTex->color[1], pTex->color[2]); - SetKeyValue(t.brush->owner, "_color", strBuff.GetBuffer()); - Sys_UpdateWindows (W_ALL); - } - } - else - { - Sys_Printf ("Can't select an entity brush face\n"); - } - } - else - { - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=425 - Face_SetShader(t.face, g_qeglobals.d_texturewin.texdef.GetName()); - Brush_Build(t.brush); - - Sys_UpdateWindows (W_ALL); - } - } - else - Sys_Printf ("Didn't hit a brush\n"); - return; - } - -} - - -// -//=========== -//MoveSelection -//=========== -// -void MoveSelection (vec3_t move) -{ - int i, success; - brush_t *b; - CString strStatus; - vec3_t vTemp, vTemp2, end; - - if (!move[0] && !move[1] && !move[2]) - { - return; - } - - if (!(g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall)) - { - move[0] = (g_nScaleHow & SCALE_X) ? 0 : move[0]; - move[1] = (g_nScaleHow & SCALE_Y) ? 0 : move[1]; - move[2] = (g_nScaleHow & SCALE_Z) ? 0 : move[2]; - } - - if (g_pParentWnd->ActiveXY()->RotateMode() || g_bPatchBendMode) - { - float fDeg = -move[2]; - float fAdj = move[2]; - int nAxis = 0; - if (g_pParentWnd->ActiveXY()->GetViewType() == XY) - { - fDeg = -move[1]; - fAdj = move[1]; - nAxis = 2; - } - else - if (g_pParentWnd->ActiveXY()->GetViewType() == XZ) - { - fDeg = move[2]; - fAdj = move[2]; - nAxis = 1; - } - else - nAxis = 0; - - g_pParentWnd->ActiveXY()->Rotation()[nAxis] += fAdj; - strStatus.Format("%s x:: %.1f y:: %.1f z:: %.1f", (g_bPatchBendMode) ? "Bend angle" : "Rotation", g_pParentWnd->ActiveXY()->Rotation()[0], g_pParentWnd->ActiveXY()->Rotation()[1], g_pParentWnd->ActiveXY()->Rotation()[2]); - g_pParentWnd->SetStatusText(2, strStatus); - - if (g_bPatchBendMode) - { - Patch_SelectBendNormal(); - Select_RotateAxis(nAxis, fDeg*2, false, true); - Patch_SelectBendAxis(); - Select_RotateAxis(nAxis, fDeg, false, true); - } - else - { - Select_RotateAxis(nAxis, fDeg, false, true); - } - return; - } - - if (g_pParentWnd->ActiveXY()->ScaleMode()) - { - vec3_t v; - v[0] = v[1] = v[2] = 1.0f; - if (move[1] > 0) - { - v[0] = 1.1f; - v[1] = 1.1f; - v[2] = 1.1f; - } - else - if (move[1] < 0) - { - v[0] = 0.9f; - v[1] = 0.9f; - v[2] = 0.9f; - } - - Select_Scale((g_nScaleHow & SCALE_X) ? 1.0f : v[0], - (g_nScaleHow & SCALE_Y) ? 1.0f : v[1], - (g_nScaleHow & SCALE_Z) ? 1.0f : v[2]); - // is that really necessary??? - Sys_UpdateWindows (W_ALL); - return; - } - - - vec3_t vDistance; - VectorSubtract(pressdelta, vPressStart, vDistance); - strStatus.Format("Distance x: %.1f y: %.1f z: %.1f", vDistance[0], vDistance[1], vDistance[2]); - g_pParentWnd->SetStatusText(3, strStatus); - - // - // dragging only a part of the selection - // - - // this is fairly crappy way to deal with curvepoint and area selection - // but it touches the smallest amount of code this way - // - if (g_qeglobals.d_num_move_points || g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall) - { - //area selection - if (g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall) - { - VectorAdd(g_qeglobals.d_vAreaBR, move, g_qeglobals.d_vAreaBR); - return; - } - //curve point selection - if (g_qeglobals.d_select_mode == sel_curvepoint) - { - Patch_UpdateSelected(move); - return; - } - //vertex selection - if (g_qeglobals.d_select_mode == sel_vertex && g_PrefsDlg.m_bVertexSplit) - { - if(g_qeglobals.d_num_move_points) { - success = true; - for (b = selected_brushes.next; b != &selected_brushes; b = b->next) - { - success &= Brush_MoveVertex(b, g_qeglobals.d_move_points[0], move, end, true); - } - if (success) - VectorCopy(end, g_qeglobals.d_move_points[0]); - } - return; - } - //all other selection types - for (i=0 ; inext) - { - bool bMoved = false; - for(face_t *f = b->brush_faces; !bMoved && f!=NULL; f=f->next) - for(int p=0; !bMoved && p<3; p++) - for (i=0 ; !bMoved && iplanepts[p] == g_qeglobals.d_move_points[i]) - bMoved = true; - if(!bMoved) continue; - - VectorCopy(b->maxs, vTemp); - VectorSubtract(vTemp, b->mins, vTemp); - Brush_Build(b,true,true,false,false); // don't filter - for (i=0 ; i<3 ; i++) - { - if (b->mins[i] > b->maxs[i] - || b->maxs[i] - b->mins[i] > g_MaxBrushSize) - break; // dragged backwards or fucked up - } - if (i != 3) - break; - if (b->patchBrush) - { - VectorCopy(b->maxs, vTemp2); - VectorSubtract(vTemp2, b->mins, vTemp2); - VectorSubtract(vTemp2, vTemp, vTemp2); - //if (!Patch_DragScale(b->nPatchID, vTemp2, move)) - if (!Patch_DragScale(b->pPatch, vTemp2, move)) - { - b = NULL; - break; - } - } - } - // if any of the brushes were crushed out of existance - // calcel the entire move - if (b != &selected_brushes) - { - Sys_Printf ("Brush dragged backwards, move canceled\n"); - for (i=0 ; inext) - Brush_Build(b,true,true,false,false); // don't filter - } - - } - else - { - // reset face originals from vertex edit mode - // this is dirty, but unfortunately necessary because Brush_Build - // can remove windings - for (b = selected_brushes.next; b != &selected_brushes; b = b->next) - { - Brush_ResetFaceOriginals(b); - } - // - // if there are lots of brushes selected, just translate instead - // of rebuilding the brushes - // NOTE: this is not actually done, but would be a good idea - // - Select_Move (move); - } -} - -/* -=========== -Drag_MouseMoved -=========== -*/ -void Drag_MouseMoved (int x, int y, int buttons) -{ - vec3_t move, delta; - int i; - - if (!buttons) - { - drag_ok = false; - return; - } - if (!drag_ok) - return; - - // clear along one axis - if (buttons & MK_SHIFT && (g_PrefsDlg.m_bALTEdge && g_qeglobals.d_select_mode != sel_areatall)) - { - drag_first = false; - if (abs(x-pressx) > abs(y-pressy)) - y = pressy; - else - x = pressx; - } - - if (g_qeglobals.d_select_mode == sel_area && g_nPatchClickedView == W_CAMERA) - { - camera_t *m_pCamera = g_pParentWnd->GetCamWnd()->Camera(); - - // snap to window - if( y > m_pCamera->height ) y = m_pCamera->height - 1; else if( y < 0 ) y = 0; - if( x > m_pCamera->width ) x = m_pCamera->width - 1; else if( x < 0 ) x = 0; - - VectorSet (move, x - pressx, y - pressy, 0); - } else - { - for (i=0 ; i<3 ; i++) - { - move[i] = drag_xvec[i]*(x - pressx) + drag_yvec[i]*(y - pressy); - if (!g_PrefsDlg.m_bNoClamp) - { - move[i] = floor(move[i]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; - } - } - } - - VectorSubtract (move, pressdelta, delta); - VectorCopy (move, pressdelta); - - MoveSelection (delta); -} - -/* -=========== -Drag_MouseUp -=========== -*/ -void Drag_MouseUp (int nButtons) -{ - Sys_Status ("Drag completed.", 0); - - if (g_qeglobals.d_select_mode == sel_area) - { - Patch_SelectAreaPoints(nButtons & MK_CONTROL); // adds to selection and/or deselects selected points if ctrl is held - g_qeglobals.d_select_mode = sel_curvepoint; - Sys_UpdateWindows (W_ALL); - } - - if (g_qeglobals.d_select_mode == sel_areatall) - { - vec3_t mins, maxs; - - int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0; - int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2; - - // get our rectangle - mins[nDim1] = MIN( g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1] ); - mins[nDim2] = MIN( g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2] ); - maxs[nDim1] = MAX( g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1] ); - maxs[nDim2] = MAX( g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2] ); - - // deselect current selection - if( !(nButtons & (MK_CONTROL|MK_SHIFT)) ) - Select_Deselect(); - - // select new selection - Select_RealCompleteTall( mins, maxs ); - - Sys_UpdateWindows (W_ALL); - } - - if (g_qeglobals.d_select_translate[0] || g_qeglobals.d_select_translate[1] || g_qeglobals.d_select_translate[2]) - { - Select_Move (g_qeglobals.d_select_translate); - VectorCopy (vec3_origin, g_qeglobals.d_select_translate); - Sys_UpdateWindows (W_CAMERA); - } - - /* note: added cleanup here, since an edge drag will leave selected vertices - in g_qeglobals.d_num_move_points - */ - if ( g_qeglobals.d_select_mode != sel_vertex && - g_qeglobals.d_select_mode != sel_curvepoint && - g_qeglobals.d_select_mode != sel_edge) - g_qeglobals.d_num_move_points = 0; - - g_pParentWnd->SetStatusText(3, ""); - Undo_EndBrushList(&selected_brushes); - Undo_End(); - UpdateSurfaceDialog(); -} +/* +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 +*/ + +#include "stdafx.h" +//#include "qe3.h" + +/* + + drag either multiple brushes, or select plane points from + a single brush. + +*/ + +extern int g_nPatchClickedView; + +qboolean drag_ok; +vec3_t drag_xvec; +vec3_t drag_yvec; + +//static int buttonstate; +int pressx, pressy; +static vec3_t pressdelta; +static vec3_t vPressStart; +//static int buttonx, buttony; + + +//int num_move_points; +//float *move_points[1024]; + +int lastx, lasty; + +qboolean drag_first; + + +void AxializeVector (vec3_t v) +{ + vec3_t a; + float o; + int i; + + if (!v[0] && !v[1]) + return; + if (!v[1] && !v[2]) + return; + if (!v[0] && !v[2]) + return; + + for (i=0 ; i<3 ; i++) + a[i] = fabs(v[i]); + if (a[0] > a[1] && a[0] > a[2]) + i = 0; + else if (a[1] > a[0] && a[1] > a[2]) + i = 1; + else + i = 2; + + o = v[i]; + VectorCopy (vec3_origin, v); + if (o<0) + v[i] = -1; + else + v[i] = 1; + +} + +/* +=========== +Drag_Setup +=========== +*/ +extern void SelectCurvePointByRay (vec3_t org, vec3_t dir, int buttons); + +void Drag_Setup (int x, int y, int buttons, + vec3_t xaxis, vec3_t yaxis, + vec3_t origin, vec3_t dir) +{ + trace_t t; + face_t *f; + + drag_first = true; + + VectorCopy (vec3_origin, pressdelta); + pressx = x; + pressy = y; + + // snap to nearest axis for camwindow drags + VectorCopy (xaxis, drag_xvec); + AxializeVector (drag_xvec); + VectorCopy (yaxis, drag_yvec); + AxializeVector (drag_yvec); + + if (g_qeglobals.d_select_mode == sel_curvepoint) + { + SelectCurvePointByRay (origin, dir, buttons); + + if(g_qeglobals.d_select_mode == sel_area) + { + drag_ok = true; + + if(g_nPatchClickedView == W_CAMERA ) { + VectorSet( g_qeglobals.d_vAreaTL, x, y, 0 ); + VectorSet( g_qeglobals.d_vAreaBR, x, y, 0 ); + } + } + else if (g_qeglobals.d_num_move_points) // don't add an undo if there are no points selected + { + drag_ok = true; + Sys_UpdateWindows(W_ALL); + Undo_Start("drag curve point"); + Undo_AddBrushList(&selected_brushes); + } + return; + } + else + { + g_qeglobals.d_num_move_points = 0; + } + + if (g_qeglobals.d_select_mode == sel_areatall) + { + VectorCopy(origin, g_qeglobals.d_vAreaTL); + VectorCopy(origin, g_qeglobals.d_vAreaBR); + + Sys_UpdateWindows(W_ALL); + + drag_ok = true; + return; + } + + if (selected_brushes.next == &selected_brushes) + { + //in this case a new brush is created when the dragging + //takes place in the XYWnd, An useless undo is created + //when the dragging takes place in the CamWnd + Undo_Start("create brush"); + + Sys_Status("No selection to drag", 0); + return; + } + + if (g_qeglobals.d_select_mode == sel_vertex) + { + SelectVertexByRay (origin, dir); + if (g_qeglobals.d_num_move_points) + { + drag_ok = true; + Undo_Start("drag vertex"); + Undo_AddBrushList(&selected_brushes); + // Need an update here for highlighting selected vertices + Sys_UpdateWindows(W_XY | W_CAMERA); + return; + } + } + + if (g_qeglobals.d_select_mode == sel_edge) + { + SelectEdgeByRay (origin, dir); + if (g_qeglobals.d_num_move_points) + { + drag_ok = true; + Undo_Start("drag edge"); + Undo_AddBrushList(&selected_brushes); + return; + } + } + + // + // check for direct hit first + // + t = Test_Ray (origin, dir, true); + if (t.selected) + { + drag_ok = true; + + Undo_Start("drag selection"); + Undo_AddBrushList(&selected_brushes); + + if (buttons == (MK_LBUTTON|MK_CONTROL) ) + { + Sys_Printf ("Shear dragging face\n"); + Brush_SelectFaceForDragging (t.brush, t.face, true); + } + else if (buttons == (MK_LBUTTON|MK_CONTROL|MK_SHIFT) ) + { + Sys_Printf ("Sticky dragging brush\n"); + for (f=t.brush->brush_faces ; f ; f=f->next) + Brush_SelectFaceForDragging (t.brush, f, false); + } + else + Sys_Printf ("Dragging entire selection\n"); + + return; + } + + if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge) + return; + + // + // check for side hit + // + // multiple brushes selected? + if (selected_brushes.next->next != &selected_brushes) + { + // yes, special handling + bool bOK = (g_PrefsDlg.m_bALTEdge) ? Sys_AltDown() : true; + if (bOK) + { + for (brush_t* pBrush = selected_brushes.next ; pBrush != &selected_brushes ; pBrush = pBrush->next) + { + if (buttons & MK_CONTROL) + Brush_SideSelect (pBrush, origin, dir, true); + else + Brush_SideSelect (pBrush, origin, dir, false); + } + } + else + { + Sys_Printf ("press ALT to drag multiple edges\n"); + return; + } + } + else + { + // single select.. trying to drag fixed entities handle themselves and just move + if (buttons & MK_CONTROL) + Brush_SideSelect (selected_brushes.next, origin, dir, true); + else + Brush_SideSelect (selected_brushes.next, origin, dir, false); + } + + Sys_Printf ("Side stretch\n"); + drag_ok = true; + + Undo_Start("side stretch"); + Undo_AddBrushList(&selected_brushes); +} + +entity_t *peLink; + +void UpdateTarget(vec3_t origin, vec3_t dir) +{ + trace_t t; + entity_t *pe; + int i; + char sz[128]; + + t = Test_Ray (origin, dir, 0); + + if (!t.brush) + return; + + pe = t.brush->owner; + + if (pe == NULL) + return; + + // is this the first? + if (peLink != NULL) + { + + // Get the target id from out current target + // if there is no id, make one + + i = IntForKey(pe, "target"); + if (i <= 0) + { + i = GetUniqueTargetId(1); + sprintf(sz, "%d", i); + + SetKeyValue(pe, "target", sz); + } + + // set the target # into our src + + sprintf(sz, "%d", i); + SetKeyValue(peLink, "targetname", sz); + + Sys_UpdateWindows(W_ENTITY); + + } + + // promote the target to the src + + peLink = pe; + +} + +/* +=========== +Drag_Begin +//++timo test three button mouse and three button emulation here ? +=========== +*/ +void Drag_Begin (int x, int y, int buttons, + vec3_t xaxis, vec3_t yaxis, + vec3_t origin, vec3_t dir, bool sf_camera) +{ + trace_t t; + bool altdown; + int nFlag; + + drag_ok = false; + VectorCopy (vec3_origin, pressdelta); + VectorCopy (vec3_origin, vPressStart); + + drag_first = true; + peLink = NULL; + + altdown = Sys_AltDown(); + + // shift-LBUTTON = select entire brush + // shift-alt-LBUTTON = drill select + if (buttons == (MK_LBUTTON | MK_SHIFT) && g_qeglobals.d_select_mode != sel_curvepoint) + { + nFlag = altdown ? SF_CYCLE : 0; + if (sf_camera) + nFlag |= SF_CAMERA; + else + nFlag |= SF_ENTITIES_FIRST; + Select_Ray(origin, dir, nFlag); + return; + } + + // (shift-)alt-LBUTTON = area select completely tall + if ( !sf_camera && + ( g_PrefsDlg.m_bALTEdge ? buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT) : (buttons == MK_LBUTTON || buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) ) && + altdown && g_qeglobals.d_select_mode != sel_curvepoint) + { + if (g_pParentWnd->ActiveXY()->AreaSelectOK()) + { + g_qeglobals.d_select_mode = sel_areatall; + + Drag_Setup (x, y, buttons, xaxis, yaxis, origin, dir); + return; + } + } + + // ctrl-alt-LBUTTON = multiple brush select without selecting whole entities + if (buttons == (MK_LBUTTON | MK_CONTROL) && altdown && g_qeglobals.d_select_mode != sel_curvepoint) + { + nFlag = 0; + if (sf_camera) + nFlag |= SF_CAMERA; + else + nFlag |= SF_ENTITIES_FIRST; + Select_Ray (origin, dir, nFlag); + UpdateSurfaceDialog(); + + return; + } + + // ctrl-shift LBUTTON = select single face + if (sf_camera && buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT) && g_qeglobals.d_select_mode != sel_curvepoint) + { + if(Sys_AltDown()) + { + brush_t *b; + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + if(b->pPatch) + continue; + + for (face_t* pFace = b->brush_faces; pFace; pFace = pFace->next) + { + g_ptrSelectedFaces.Add(pFace); + g_ptrSelectedFaceBrushes.Add(b); + } + } + + for (b = selected_brushes.next; b != &selected_brushes; ) + { + brush_t *pb = b; + b = b->next; + Brush_RemoveFromList (pb); + Brush_AddToList (pb, &active_brushes); + } + } + else + Select_Deselect (true); + + Select_Ray (origin, dir, (SF_SINGLEFACE|SF_CAMERA)); + return; + } + + + // LBUTTON + all other modifiers = manipulate selection + if (buttons & MK_LBUTTON) + { + Drag_Setup (x, y, buttons, xaxis, yaxis, origin, dir); + return; + } + + int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON; + // middle button = grab texture + if (buttons == nMouseButton) + { + t = Test_Ray (origin, dir, false); + if (t.face) + { + UpdateWorkzone_ForBrush( t.brush ); + // use a local brushprimit_texdef fitted to a default 2x2 texture + brushprimit_texdef_t bp_local; + ConvertTexMatWithQTexture( &t.face->brushprimit_texdef, t.face->d_texture, &bp_local, NULL ); + Texture_SetTexture ( &t.face->texdef, &bp_local, false, NULL); + UpdateSurfaceDialog(); + UpdatePatchInspector(); + } + else + Sys_Printf ("Did not select a texture\n"); + return; + } + + // ctrl-middle button = set entire brush to texture + if (buttons == (nMouseButton|MK_CONTROL) ) + { + t = Test_Ray (origin, dir, false); + if (t.brush) + { + if (t.brush->brush_faces->texdef.GetName()[0] == '(') + Sys_Printf ("Can't change an entity texture\n"); + else + { + Brush_SetTexture (t.brush, &g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef, false, static_cast( g_qeglobals.d_texturewin.pTexdef ) ); + Sys_UpdateWindows (W_ALL); + } + } + else + Sys_Printf ("Didn't hit a btrush\n"); + return; + } + + // ctrl-shift-middle button = set single face to texture + if (buttons == (nMouseButton|MK_SHIFT|MK_CONTROL) ) + { + t = Test_Ray (origin, dir, false); + if (t.brush) + { + if (t.brush->brush_faces->texdef.GetName()[0] == '(') + Sys_Printf ("Can't change an entity texture\n"); + else + { + SetFaceTexdef (t.face, &g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef); + Brush_Build( t.brush ); + + Sys_UpdateWindows (W_ALL); + } + } + else + Sys_Printf ("Didn't hit a btrush\n"); + return; + } + + if (buttons == (nMouseButton | MK_SHIFT)) + { + Sys_Printf("Set brush face texture info\n"); + t = Test_Ray (origin, dir, false); + if (t.brush) + { + if (t.brush->brush_faces->texdef.GetName()[0] == '(') + { + if (t.brush->owner->eclass->nShowFlags & ECLASS_LIGHT) + { + CString strBuff; + qtexture_t* pTex = g_qeglobals.d_texturewin.pShader->getTexture(); + if (pTex) + { + vec3_t vColor; + VectorCopy(pTex->color, vColor); + + float fLargest = 0.0f; + for (int i = 0; i < 3; i++) + { + if (vColor[i] > fLargest) + fLargest = vColor[i]; + } + + if (fLargest == 0.0f) + { + vColor[0] = vColor[1] = vColor[2] = 1.0f; + } + else + { + float fScale = 1.0f / fLargest; + for (int i = 0; i < 3; i++) + { + vColor[i] *= fScale; + } + } + strBuff.Format("%f %f %f",pTex->color[0], pTex->color[1], pTex->color[2]); + SetKeyValue(t.brush->owner, "_color", strBuff.GetBuffer()); + Sys_UpdateWindows (W_ALL); + } + } + else + { + Sys_Printf ("Can't select an entity brush face\n"); + } + } + else + { + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=425 + Face_SetShader(t.face, g_qeglobals.d_texturewin.texdef.GetName()); + Brush_Build(t.brush); + + Sys_UpdateWindows (W_ALL); + } + } + else + Sys_Printf ("Didn't hit a brush\n"); + return; + } + +} + + +// +//=========== +//MoveSelection +//=========== +// +void MoveSelection (vec3_t move) +{ + int i, success; + brush_t *b; + CString strStatus; + vec3_t vTemp, vTemp2, end; + + if (!move[0] && !move[1] && !move[2]) + { + return; + } + + if (!(g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall)) + { + move[0] = (g_nScaleHow & SCALE_X) ? 0 : move[0]; + move[1] = (g_nScaleHow & SCALE_Y) ? 0 : move[1]; + move[2] = (g_nScaleHow & SCALE_Z) ? 0 : move[2]; + } + + if (g_pParentWnd->ActiveXY()->RotateMode() || g_bPatchBendMode) + { + float fDeg = -move[2]; + float fAdj = move[2]; + int nAxis = 0; + if (g_pParentWnd->ActiveXY()->GetViewType() == XY) + { + fDeg = -move[1]; + fAdj = move[1]; + nAxis = 2; + } + else + if (g_pParentWnd->ActiveXY()->GetViewType() == XZ) + { + fDeg = move[2]; + fAdj = move[2]; + nAxis = 1; + } + else + nAxis = 0; + + g_pParentWnd->ActiveXY()->Rotation()[nAxis] += fAdj; + strStatus.Format("%s x:: %.1f y:: %.1f z:: %.1f", (g_bPatchBendMode) ? "Bend angle" : "Rotation", g_pParentWnd->ActiveXY()->Rotation()[0], g_pParentWnd->ActiveXY()->Rotation()[1], g_pParentWnd->ActiveXY()->Rotation()[2]); + g_pParentWnd->SetStatusText(2, strStatus); + + if (g_bPatchBendMode) + { + Patch_SelectBendNormal(); + Select_RotateAxis(nAxis, fDeg*2, false, true); + Patch_SelectBendAxis(); + Select_RotateAxis(nAxis, fDeg, false, true); + } + else + { + Select_RotateAxis(nAxis, fDeg, false, true); + } + return; + } + + if (g_pParentWnd->ActiveXY()->ScaleMode()) + { + vec3_t v; + v[0] = v[1] = v[2] = 1.0f; + if (move[1] > 0) + { + v[0] = 1.1f; + v[1] = 1.1f; + v[2] = 1.1f; + } + else + if (move[1] < 0) + { + v[0] = 0.9f; + v[1] = 0.9f; + v[2] = 0.9f; + } + + Select_Scale((g_nScaleHow & SCALE_X) ? 1.0f : v[0], + (g_nScaleHow & SCALE_Y) ? 1.0f : v[1], + (g_nScaleHow & SCALE_Z) ? 1.0f : v[2]); + // is that really necessary??? + Sys_UpdateWindows (W_ALL); + return; + } + + + vec3_t vDistance; + VectorSubtract(pressdelta, vPressStart, vDistance); + strStatus.Format("Distance x: %.1f y: %.1f z: %.1f", vDistance[0], vDistance[1], vDistance[2]); + g_pParentWnd->SetStatusText(3, strStatus); + + // + // dragging only a part of the selection + // + + // this is fairly crappy way to deal with curvepoint and area selection + // but it touches the smallest amount of code this way + // + if (g_qeglobals.d_num_move_points || g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall) + { + //area selection + if (g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall) + { + VectorAdd(g_qeglobals.d_vAreaBR, move, g_qeglobals.d_vAreaBR); + return; + } + //curve point selection + if (g_qeglobals.d_select_mode == sel_curvepoint) + { + Patch_UpdateSelected(move); + return; + } + //vertex selection + if (g_qeglobals.d_select_mode == sel_vertex && g_PrefsDlg.m_bVertexSplit) + { + if(g_qeglobals.d_num_move_points) { + success = true; + for (b = selected_brushes.next; b != &selected_brushes; b = b->next) + { + success &= Brush_MoveVertex(b, g_qeglobals.d_move_points[0], move, end, true); + } + if (success) + VectorCopy(end, g_qeglobals.d_move_points[0]); + } + return; + } + //all other selection types + for (i=0 ; inext) + { + bool bMoved = false; + for(face_t *f = b->brush_faces; !bMoved && f!=NULL; f=f->next) + for(int p=0; !bMoved && p<3; p++) + for (i=0 ; !bMoved && iplanepts[p] == g_qeglobals.d_move_points[i]) + bMoved = true; + if(!bMoved) continue; + + VectorCopy(b->maxs, vTemp); + VectorSubtract(vTemp, b->mins, vTemp); + Brush_Build(b,true,true,false,false); // don't filter + for (i=0 ; i<3 ; i++) + { + if (b->mins[i] > b->maxs[i] + || b->maxs[i] - b->mins[i] > g_MaxBrushSize) + break; // dragged backwards or fucked up + } + if (i != 3) + break; + if (b->patchBrush) + { + VectorCopy(b->maxs, vTemp2); + VectorSubtract(vTemp2, b->mins, vTemp2); + VectorSubtract(vTemp2, vTemp, vTemp2); + //if (!Patch_DragScale(b->nPatchID, vTemp2, move)) + if (!Patch_DragScale(b->pPatch, vTemp2, move)) + { + b = NULL; + break; + } + } + } + // if any of the brushes were crushed out of existance + // calcel the entire move + if (b != &selected_brushes) + { + Sys_Printf ("Brush dragged backwards, move canceled\n"); + for (i=0 ; inext) + Brush_Build(b,true,true,false,false); // don't filter + } + + } + else + { + // reset face originals from vertex edit mode + // this is dirty, but unfortunately necessary because Brush_Build + // can remove windings + for (b = selected_brushes.next; b != &selected_brushes; b = b->next) + { + Brush_ResetFaceOriginals(b); + } + // + // if there are lots of brushes selected, just translate instead + // of rebuilding the brushes + // NOTE: this is not actually done, but would be a good idea + // + Select_Move (move); + } +} + +/* +=========== +Drag_MouseMoved +=========== +*/ +void Drag_MouseMoved (int x, int y, int buttons) +{ + vec3_t move, delta; + int i; + + if (!buttons) + { + drag_ok = false; + return; + } + if (!drag_ok) + return; + + // clear along one axis + if (buttons & MK_SHIFT && (g_PrefsDlg.m_bALTEdge && g_qeglobals.d_select_mode != sel_areatall)) + { + drag_first = false; + if (abs(x-pressx) > abs(y-pressy)) + y = pressy; + else + x = pressx; + } + + if (g_qeglobals.d_select_mode == sel_area && g_nPatchClickedView == W_CAMERA) + { + camera_t *m_pCamera = g_pParentWnd->GetCamWnd()->Camera(); + + // snap to window + if( y > m_pCamera->height ) y = m_pCamera->height - 1; else if( y < 0 ) y = 0; + if( x > m_pCamera->width ) x = m_pCamera->width - 1; else if( x < 0 ) x = 0; + + VectorSet (move, x - pressx, y - pressy, 0); + } else + { + for (i=0 ; i<3 ; i++) + { + move[i] = drag_xvec[i]*(x - pressx) + drag_yvec[i]*(y - pressy); + if (!g_PrefsDlg.m_bNoClamp) + { + move[i] = floor(move[i]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; + } + } + } + + VectorSubtract (move, pressdelta, delta); + VectorCopy (move, pressdelta); + + MoveSelection (delta); +} + +/* +=========== +Drag_MouseUp +=========== +*/ +void Drag_MouseUp (int nButtons) +{ + Sys_Status ("Drag completed.", 0); + + if (g_qeglobals.d_select_mode == sel_area) + { + Patch_SelectAreaPoints(nButtons & MK_CONTROL); // adds to selection and/or deselects selected points if ctrl is held + g_qeglobals.d_select_mode = sel_curvepoint; + Sys_UpdateWindows (W_ALL); + } + + if (g_qeglobals.d_select_mode == sel_areatall) + { + vec3_t mins, maxs; + + int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0; + int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2; + + // get our rectangle + mins[nDim1] = MIN( g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1] ); + mins[nDim2] = MIN( g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2] ); + maxs[nDim1] = MAX( g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1] ); + maxs[nDim2] = MAX( g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2] ); + + // deselect current selection + if( !(nButtons & (MK_CONTROL|MK_SHIFT)) ) + Select_Deselect(); + + // select new selection + Select_RealCompleteTall( mins, maxs ); + + Sys_UpdateWindows (W_ALL); + } + + if (g_qeglobals.d_select_translate[0] || g_qeglobals.d_select_translate[1] || g_qeglobals.d_select_translate[2]) + { + Select_Move (g_qeglobals.d_select_translate); + VectorCopy (vec3_origin, g_qeglobals.d_select_translate); + Sys_UpdateWindows (W_CAMERA); + } + + /* note: added cleanup here, since an edge drag will leave selected vertices + in g_qeglobals.d_num_move_points + */ + if ( g_qeglobals.d_select_mode != sel_vertex && + g_qeglobals.d_select_mode != sel_curvepoint && + g_qeglobals.d_select_mode != sel_edge) + g_qeglobals.d_num_move_points = 0; + + g_pParentWnd->SetStatusText(3, ""); + Undo_EndBrushList(&selected_brushes); + Undo_End(); + UpdateSurfaceDialog(); +} diff --git a/radiant/eclass.cpp b/radiant/eclass.cpp index 991e9b87..cd6cd485 100644 --- a/radiant/eclass.cpp +++ b/radiant/eclass.cpp @@ -1,497 +1,497 @@ -/* -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 -*/ - -#include "stdafx.h" -#include -#if defined (__linux__) || defined (__APPLE__) -#include -#endif -#include "assert.h" - -eclass_t *eclass = NULL; -eclass_t *eclass_bad = NULL; -const vec3_t smallbox[2] = {{-8,-8,-8},{8,8,8}}; -char eclass_directory[1024]; - -qboolean parsing_single = false; -eclass_t *eclass_e; - -/*! -implementation of the EClass manager API -*/ -eclass_t** Get_EClass_E() -{ - return &eclass_e; -} - -void Set_Eclass_Found(qboolean b) -{ - eclass_found = b; -} - -qboolean Get_Parsing_Single() -{ - return parsing_single; -} - - -// md3 cache for misc_models -//eclass_t *g_md3Cache = NULL; - -/* - -the classname, color triple, and bounding box are parsed out of comments -A ? size means take the exact brush size. - -/ *QUAKED (0 0 0) ? -/ *QUAKED (0 0 0) (-8 -8 -8) (8 8 8) - -Flag names can follow the size description: - -/ *QUAKED func_door (0 .5 .8) ? START_OPEN STONE_SOUND DOOR_DONT_LINK GOLD_KEY SILVER_KEY - -*/ - -void CleanEntityList(eclass_t *&pList) -{ - while (pList) - { - eclass_t* pTemp = pList->next; - - entitymodel *model = pList->model; - while (model != NULL) - { - delete []model->pTriList; - if (model->strSkin) - g_string_free( (GString *)model->strSkin, TRUE ); - model->strSkin = NULL; - model = model->pNext; - } - - if (pList->modelpath) { - free(pList->modelpath); - pList->modelpath = NULL; - } - if (pList->skinpath) { - free(pList->skinpath); - pList->skinpath = NULL; - } - - free(pList->name); - free(pList->comments); - free(pList); - pList = pTemp; - } - - pList = NULL; - -} - - -void CleanUpEntities() -{ - // NOTE: maybe some leak checks needed .. older versions of Radiant looked like they were freezing more stuff - CleanEntityList(eclass); - //CleanEntityList(g_md3Cache); - if (eclass_bad) - { - free(eclass_bad->name); - free(eclass_bad->comments); - free(eclass_bad); - eclass_bad = NULL; - } -} - -void EClass_InsertSortedList(eclass_t *&pList, eclass_t *e) -{ - eclass_t *s; - - if (!pList) - { - pList = e; - return; - } - - - s = pList; - if (stricmp (e->name, s->name) < 0) - { - e->next = s; - pList = e; - return; - } - - do - { - if (!s->next || stricmp (e->name, s->next->name) < 0) - { - e->next = s->next; - s->next = e; - return; - } - s=s->next; - } while (1); -} - -/* -================= -Eclass_InsertAlphabetized -================= -*/ -void Eclass_InsertAlphabetized (eclass_t *e) -{ -#if 1 - EClass_InsertSortedList(eclass, e); -#else - eclass_t *s; - - if (!eclass) - { - eclass = e; - return; - } - - - s = eclass; - if (stricmp (e->name, s->name) < 0) - { - e->next = s; - eclass = e; - return; - } - - do - { - if (!s->next || stricmp (e->name, s->next->name) < 0) - { - e->next = s->next; - s->next = e; - return; - } - s=s->next; - } while (1); -#endif -} - -/*! -This looks at each eclass_t, if it has a "modelpath" set then it leaves it alone -if it's not set it checks to see if a file called "sprites/.*" exists, and -if it does exist then it sets the "modelpath" to "sprites/.spr" -*/ -void Eclass_CreateSpriteModelPaths() -{ - int Counts[4] = { 0, 0, 0, 0 }; - char filename[512]; // should be big enough, ExtractFileBase doesn't take a buffer size... - eclass_t *e; - - // get a list of all sprite/*>* files in all sprite/ directories - Sys_Printf("Searching VFS for files in sprites/*.* that match entity names...\n"); - GSList *pFiles = vfsGetFileList("sprites", NULL); - GSList *pFile; - - if (pFiles) - { - - // find an eclass without a modelpath. - for (e=eclass ; e ; e=e->next) - { - Counts[0]++; - if (e->modelpath) - { -#ifdef _DEBUG - Sys_Printf("Ignoring sprite for entity %s (modelpath: \"%s\")\n",e->name,e->modelpath); -#endif - Counts[1]++; - continue; // ignore this eclass, it's already got a model - } - - // TODO: remove this check when we can have sprites for non-fixed size entities. - if (!e->fixedsize) - { -#ifdef _DEBUG - Sys_Printf("Ignoring sprite for non-fixed-size entity %s\n",e->name); -#endif - Counts[2]++; - continue; // can't have sprites for non-fixed size entities (yet!) - } - - - Sys_Printf("Searching for sprite for fixed-size entity %s...",e->name); - - pFile = pFiles; // point to start of list - - // look for a file that has the same name, with any extension. - bool Found = FALSE; - while (pFile) - { - - // strip the path/ and the .extension. - ExtractFileBase((char *)pFile->data,filename); - - // does the eclass name match the filename? - if (stricmp(e->name,filename) == 0) - { - // yes, so generate a sprite filename using the all-encompasing .spr extension - // so that the model wrapper knows the sprite model plugin will be the model - // plugin used to render it. - CString strSpriteName; - strSpriteName.Format("sprites/%s.spr",e->name); - e->modelpath = strdup(strSpriteName.GetBuffer()); - Sys_Printf("Found! (\"%s\")\n",(char *)pFile->data); - Counts[3]++; - Found = TRUE; - } - pFile = pFile->next; - } - - if (!Found) - Sys_Printf("not found\n"); - - } - - vfsClearFileDirList(&pFiles); - } - Sys_Printf("%d entities were scanned\n" - "%d entities that already had models/sprites were ignored\n" - "%d non-fixed-size entities were ignored\n" - "%d entities did not have matching sprite files\n" - "%d entities had sprite files and have been attached\n", - Counts[0],Counts[1],Counts[2],Counts[0]-Counts[3],Counts[3]); - -} - -void EClass_InitForFileList(GSList *pFiles, _EClassTable *pTable) -{ - GSList *pFile = pFiles; - while (pFile) - { - // for a given name, we grab the first .def in the vfs - // this allows to override baseq3/scripts/entities.def for instance - char relPath[PATH_MAX]; - strcpy(relPath, "scripts/"); - strcat(relPath, (char*)pFile->data); - // FIXME TTimo http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 - if (!vfsGetFullPath(relPath, 0, 0)) - { - Sys_FPrintf(SYS_ERR, "Failed to find the full path for '%s' in the VFS\n", relPath); - Sys_FPrintf(SYS_ERR, "did you hit bug http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 ?\n"); - } - else - pTable->m_pfnScanFile(vfsGetFullPath(relPath, 0, 0)); - pFile = pFile->next; - } -} - -/*! -Manually create an eclass_t, for when no modules exist. -this replaces and centralizes the eclass_t allocation -*/ -eclass_t * EClass_Create( const char *name, float col1, float col2, float col3, const vec3_t *mins, const vec3_t *maxs, const char *comments ) -{ - eclass_t *e; - char color[128]; - - e = (eclass_t*)malloc(sizeof(*e)); - memset (e, 0, sizeof(*e)); - - e->name = strdup(name); - - // grab the color, reformat as texture name - e->color[0] = col1; - e->color[1] = col2; - e->color[2] = col3; - sprintf (color, "(%f %f %f)", e->color[0], e->color[1], e->color[2]); - e->texdef.SetName(color); - - // supplied size ? - if (mins && maxs) - { - // Hydra: - // If we set worldspawn to be a fixed-size all the textures are - // displayed as flat-shaded. This is a KLUDGE now that we have - // multiple game support as the worldspawn entity is game specific. - // Note that this is only ever fixed for the user if a definition - // for the worldspawn entity was not loaded, this can happen for - // several reasons: - // a) no entity definition plugin exists - // b) no entity definition files were found - // c) no entity definition file contained an entry for worldspawn. - - if (stricmp(name,"worldspawn") != 0) e->fixedsize = true; - - // copy the sizes.. - memcpy(e->mins,mins,sizeof(vec3_t)); - memcpy(e->maxs,maxs,sizeof(vec3_t)); - } - - if (comments) - e->comments = strdup(comments); - else - { - e->comments = (char*)malloc(1); - e->comments[0] = '\0'; - } - - return e; -} - -void Eclass_Init () -{ - GSList *pFiles; - - // start by creating the default unknown eclass - eclass_bad = EClass_Create("UNKNOWN_CLASS" , 0, 0.5, 0,NULL,NULL,NULL); - - // now scan the definitions - _EClassTable *pTable = &g_EClassDefTable; - while (pTable) - { - // read in all scripts/*. - pFiles = vfsGetFileList("scripts", pTable->m_pfnGetExtension()); - if (pFiles) - { - GSList *pFile = pFiles; - while (pFile) - { - /*! - \todo the MP/SP filtering rules need to be CLEANED UP and SANITIZED - */ - // HACK - // JKII SP/MP mapping mode - if (g_pGameDescription->mGameFile == "jk2.game" || g_pGameDescription->mGameFile == "ja.game") - { - if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"), "sp")) - { - // SP mapping, ignore mp_*.def - char *name = (char *)pFile->data; - if (name[0]=='m' && name[1]=='p' && name[2]=='_') - { - Sys_Printf("Single Player mapping mode. Ignoring '%s'\n", name); - pFile = pFile->next; - continue; - } - } - else - { - // MP mapping, ignore sp_*.def - char *name = (char *)pFile->data; - if (name[0]=='s' && name[1]=='p' && name[2]=='_') - { - Sys_Printf("Multiplayer mapping mode. Ignoring '%s'\n", name); - pFile = pFile->next; - continue; - } - } - } - // RIANT - // STVEF SP/MP mapping mode - else if (g_pGameDescription->mGameFile == "stvef.game") - { - if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"), "sp")) - { - // SP mapping, ignore mp_*.def - char *name = (char *)pFile->data; - if (name[0]=='m' && name[1]=='p' && name[2]=='_') - { - Sys_Printf("Single Player mapping mode. Ignoring '%s'\n", name); - pFile = pFile->next; - continue; - } - } - else - { - // HM mapping, ignore sp_*.def - char *name = (char *)pFile->data; - if (name[0]=='h' && name[1]=='m' && name[2]=='_') - { - Sys_Printf("HoloMatch mapping mode. Ignoring '%s'\n", name); - pFile = pFile->next; - continue; - } - } - } - // for a given name, we grab the first .def in the vfs - // this allows to override baseq3/scripts/entities.def for instance - char relPath[PATH_MAX]; - strcpy(relPath, "scripts/"); - strcat(relPath, (char*)pFile->data); - // FIXME TTimo http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 - char *fullpath = vfsGetFullPath(relPath, 0, 0); - if (!fullpath) - { - Sys_FPrintf(SYS_ERR, "Failed to find the full path for \"%s\" in the VFS\n", relPath); - Sys_FPrintf(SYS_ERR, "did you hit bug http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 ?\n"); - } - else - pTable->m_pfnScanFile(fullpath); - if (g_pGameDescription->mEClassSingleLoad) - break; - pFile = pFile->next; - } - vfsClearFileDirList(&pFiles); - pFiles = NULL; - } - else - Sys_FPrintf(SYS_ERR, "Didn't find any scripts/*.%s files to load EClass information\n", pTable->m_pfnGetExtension()); - - // we deal with two formats max, if the other table exists, loop again - if (g_bHaveEClassExt && pTable == &g_EClassDefTable) - pTable = &g_EClassExtTable; - else - pTable = NULL; // done, exit - } - Eclass_CreateSpriteModelPaths(); -} - -eclass_t *Eclass_ForName (const char *name, qboolean has_brushes) -{ - eclass_t *e; - - if (!name || *name == '\0') - return eclass_bad; - -#ifdef _DEBUG - // grouping stuff, not an eclass - if (strcmp(name, "group_info")==0) - Sys_Printf("WARNING: unexpected group_info entity in Eclass_ForName\n"); -#endif - - if (!name) - return eclass_bad; - - for (e=eclass ; e ; e=e->next) - if (!strcmp (name, e->name)) - return e; - - // create a new class for it - if (has_brushes) - { - e = EClass_Create(name , 0, 0.5, 0,NULL,NULL,"Not found in source."); - } - else - { - e = EClass_Create(name , 0, 0.5, 0,&smallbox[0],&smallbox[1],"Not found in source."); - } - - Eclass_InsertAlphabetized (e); - - return e; -} +/* +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 +*/ + +#include "stdafx.h" +#include +#if defined (__linux__) || defined (__APPLE__) +#include +#endif +#include "assert.h" + +eclass_t *eclass = NULL; +eclass_t *eclass_bad = NULL; +const vec3_t smallbox[2] = {{-8,-8,-8},{8,8,8}}; +char eclass_directory[1024]; + +qboolean parsing_single = false; +eclass_t *eclass_e; + +/*! +implementation of the EClass manager API +*/ +eclass_t** Get_EClass_E() +{ + return &eclass_e; +} + +void Set_Eclass_Found(qboolean b) +{ + eclass_found = b; +} + +qboolean Get_Parsing_Single() +{ + return parsing_single; +} + + +// md3 cache for misc_models +//eclass_t *g_md3Cache = NULL; + +/* + +the classname, color triple, and bounding box are parsed out of comments +A ? size means take the exact brush size. + +/ *QUAKED (0 0 0) ? +/ *QUAKED (0 0 0) (-8 -8 -8) (8 8 8) + +Flag names can follow the size description: + +/ *QUAKED func_door (0 .5 .8) ? START_OPEN STONE_SOUND DOOR_DONT_LINK GOLD_KEY SILVER_KEY + +*/ + +void CleanEntityList(eclass_t *&pList) +{ + while (pList) + { + eclass_t* pTemp = pList->next; + + entitymodel *model = pList->model; + while (model != NULL) + { + delete []model->pTriList; + if (model->strSkin) + g_string_free( (GString *)model->strSkin, TRUE ); + model->strSkin = NULL; + model = model->pNext; + } + + if (pList->modelpath) { + free(pList->modelpath); + pList->modelpath = NULL; + } + if (pList->skinpath) { + free(pList->skinpath); + pList->skinpath = NULL; + } + + free(pList->name); + free(pList->comments); + free(pList); + pList = pTemp; + } + + pList = NULL; + +} + + +void CleanUpEntities() +{ + // NOTE: maybe some leak checks needed .. older versions of Radiant looked like they were freezing more stuff + CleanEntityList(eclass); + //CleanEntityList(g_md3Cache); + if (eclass_bad) + { + free(eclass_bad->name); + free(eclass_bad->comments); + free(eclass_bad); + eclass_bad = NULL; + } +} + +void EClass_InsertSortedList(eclass_t *&pList, eclass_t *e) +{ + eclass_t *s; + + if (!pList) + { + pList = e; + return; + } + + + s = pList; + if (stricmp (e->name, s->name) < 0) + { + e->next = s; + pList = e; + return; + } + + do + { + if (!s->next || stricmp (e->name, s->next->name) < 0) + { + e->next = s->next; + s->next = e; + return; + } + s=s->next; + } while (1); +} + +/* +================= +Eclass_InsertAlphabetized +================= +*/ +void Eclass_InsertAlphabetized (eclass_t *e) +{ +#if 1 + EClass_InsertSortedList(eclass, e); +#else + eclass_t *s; + + if (!eclass) + { + eclass = e; + return; + } + + + s = eclass; + if (stricmp (e->name, s->name) < 0) + { + e->next = s; + eclass = e; + return; + } + + do + { + if (!s->next || stricmp (e->name, s->next->name) < 0) + { + e->next = s->next; + s->next = e; + return; + } + s=s->next; + } while (1); +#endif +} + +/*! +This looks at each eclass_t, if it has a "modelpath" set then it leaves it alone +if it's not set it checks to see if a file called "sprites/.*" exists, and +if it does exist then it sets the "modelpath" to "sprites/.spr" +*/ +void Eclass_CreateSpriteModelPaths() +{ + int Counts[4] = { 0, 0, 0, 0 }; + char filename[512]; // should be big enough, ExtractFileBase doesn't take a buffer size... + eclass_t *e; + + // get a list of all sprite/*>* files in all sprite/ directories + Sys_Printf("Searching VFS for files in sprites/*.* that match entity names...\n"); + GSList *pFiles = vfsGetFileList("sprites", NULL); + GSList *pFile; + + if (pFiles) + { + + // find an eclass without a modelpath. + for (e=eclass ; e ; e=e->next) + { + Counts[0]++; + if (e->modelpath) + { +#ifdef _DEBUG + Sys_Printf("Ignoring sprite for entity %s (modelpath: \"%s\")\n",e->name,e->modelpath); +#endif + Counts[1]++; + continue; // ignore this eclass, it's already got a model + } + + // TODO: remove this check when we can have sprites for non-fixed size entities. + if (!e->fixedsize) + { +#ifdef _DEBUG + Sys_Printf("Ignoring sprite for non-fixed-size entity %s\n",e->name); +#endif + Counts[2]++; + continue; // can't have sprites for non-fixed size entities (yet!) + } + + + Sys_Printf("Searching for sprite for fixed-size entity %s...",e->name); + + pFile = pFiles; // point to start of list + + // look for a file that has the same name, with any extension. + bool Found = FALSE; + while (pFile) + { + + // strip the path/ and the .extension. + ExtractFileBase((char *)pFile->data,filename); + + // does the eclass name match the filename? + if (stricmp(e->name,filename) == 0) + { + // yes, so generate a sprite filename using the all-encompasing .spr extension + // so that the model wrapper knows the sprite model plugin will be the model + // plugin used to render it. + CString strSpriteName; + strSpriteName.Format("sprites/%s.spr",e->name); + e->modelpath = strdup(strSpriteName.GetBuffer()); + Sys_Printf("Found! (\"%s\")\n",(char *)pFile->data); + Counts[3]++; + Found = TRUE; + } + pFile = pFile->next; + } + + if (!Found) + Sys_Printf("not found\n"); + + } + + vfsClearFileDirList(&pFiles); + } + Sys_Printf("%d entities were scanned\n" + "%d entities that already had models/sprites were ignored\n" + "%d non-fixed-size entities were ignored\n" + "%d entities did not have matching sprite files\n" + "%d entities had sprite files and have been attached\n", + Counts[0],Counts[1],Counts[2],Counts[0]-Counts[3],Counts[3]); + +} + +void EClass_InitForFileList(GSList *pFiles, _EClassTable *pTable) +{ + GSList *pFile = pFiles; + while (pFile) + { + // for a given name, we grab the first .def in the vfs + // this allows to override baseq3/scripts/entities.def for instance + char relPath[PATH_MAX]; + strcpy(relPath, "scripts/"); + strcat(relPath, (char*)pFile->data); + // FIXME TTimo http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 + if (!vfsGetFullPath(relPath, 0, 0)) + { + Sys_FPrintf(SYS_ERR, "Failed to find the full path for '%s' in the VFS\n", relPath); + Sys_FPrintf(SYS_ERR, "did you hit bug http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 ?\n"); + } + else + pTable->m_pfnScanFile(vfsGetFullPath(relPath, 0, 0)); + pFile = pFile->next; + } +} + +/*! +Manually create an eclass_t, for when no modules exist. +this replaces and centralizes the eclass_t allocation +*/ +eclass_t * EClass_Create( const char *name, float col1, float col2, float col3, const vec3_t *mins, const vec3_t *maxs, const char *comments ) +{ + eclass_t *e; + char color[128]; + + e = (eclass_t*)malloc(sizeof(*e)); + memset (e, 0, sizeof(*e)); + + e->name = strdup(name); + + // grab the color, reformat as texture name + e->color[0] = col1; + e->color[1] = col2; + e->color[2] = col3; + sprintf (color, "(%f %f %f)", e->color[0], e->color[1], e->color[2]); + e->texdef.SetName(color); + + // supplied size ? + if (mins && maxs) + { + // Hydra: + // If we set worldspawn to be a fixed-size all the textures are + // displayed as flat-shaded. This is a KLUDGE now that we have + // multiple game support as the worldspawn entity is game specific. + // Note that this is only ever fixed for the user if a definition + // for the worldspawn entity was not loaded, this can happen for + // several reasons: + // a) no entity definition plugin exists + // b) no entity definition files were found + // c) no entity definition file contained an entry for worldspawn. + + if (stricmp(name,"worldspawn") != 0) e->fixedsize = true; + + // copy the sizes.. + memcpy(e->mins,mins,sizeof(vec3_t)); + memcpy(e->maxs,maxs,sizeof(vec3_t)); + } + + if (comments) + e->comments = strdup(comments); + else + { + e->comments = (char*)malloc(1); + e->comments[0] = '\0'; + } + + return e; +} + +void Eclass_Init () +{ + GSList *pFiles; + + // start by creating the default unknown eclass + eclass_bad = EClass_Create("UNKNOWN_CLASS" , 0, 0.5, 0,NULL,NULL,NULL); + + // now scan the definitions + _EClassTable *pTable = &g_EClassDefTable; + while (pTable) + { + // read in all scripts/*. + pFiles = vfsGetFileList("scripts", pTable->m_pfnGetExtension()); + if (pFiles) + { + GSList *pFile = pFiles; + while (pFile) + { + /*! + \todo the MP/SP filtering rules need to be CLEANED UP and SANITIZED + */ + // HACK + // JKII SP/MP mapping mode + if (g_pGameDescription->mGameFile == "jk2.game" || g_pGameDescription->mGameFile == "ja.game") + { + if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"), "sp")) + { + // SP mapping, ignore mp_*.def + char *name = (char *)pFile->data; + if (name[0]=='m' && name[1]=='p' && name[2]=='_') + { + Sys_Printf("Single Player mapping mode. Ignoring '%s'\n", name); + pFile = pFile->next; + continue; + } + } + else + { + // MP mapping, ignore sp_*.def + char *name = (char *)pFile->data; + if (name[0]=='s' && name[1]=='p' && name[2]=='_') + { + Sys_Printf("Multiplayer mapping mode. Ignoring '%s'\n", name); + pFile = pFile->next; + continue; + } + } + } + // RIANT + // STVEF SP/MP mapping mode + else if (g_pGameDescription->mGameFile == "stvef.game") + { + if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"), "sp")) + { + // SP mapping, ignore mp_*.def + char *name = (char *)pFile->data; + if (name[0]=='m' && name[1]=='p' && name[2]=='_') + { + Sys_Printf("Single Player mapping mode. Ignoring '%s'\n", name); + pFile = pFile->next; + continue; + } + } + else + { + // HM mapping, ignore sp_*.def + char *name = (char *)pFile->data; + if (name[0]=='h' && name[1]=='m' && name[2]=='_') + { + Sys_Printf("HoloMatch mapping mode. Ignoring '%s'\n", name); + pFile = pFile->next; + continue; + } + } + } + // for a given name, we grab the first .def in the vfs + // this allows to override baseq3/scripts/entities.def for instance + char relPath[PATH_MAX]; + strcpy(relPath, "scripts/"); + strcat(relPath, (char*)pFile->data); + // FIXME TTimo http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 + char *fullpath = vfsGetFullPath(relPath, 0, 0); + if (!fullpath) + { + Sys_FPrintf(SYS_ERR, "Failed to find the full path for \"%s\" in the VFS\n", relPath); + Sys_FPrintf(SYS_ERR, "did you hit bug http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 ?\n"); + } + else + pTable->m_pfnScanFile(fullpath); + if (g_pGameDescription->mEClassSingleLoad) + break; + pFile = pFile->next; + } + vfsClearFileDirList(&pFiles); + pFiles = NULL; + } + else + Sys_FPrintf(SYS_ERR, "Didn't find any scripts/*.%s files to load EClass information\n", pTable->m_pfnGetExtension()); + + // we deal with two formats max, if the other table exists, loop again + if (g_bHaveEClassExt && pTable == &g_EClassDefTable) + pTable = &g_EClassExtTable; + else + pTable = NULL; // done, exit + } + Eclass_CreateSpriteModelPaths(); +} + +eclass_t *Eclass_ForName (const char *name, qboolean has_brushes) +{ + eclass_t *e; + + if (!name || *name == '\0') + return eclass_bad; + +#ifdef _DEBUG + // grouping stuff, not an eclass + if (strcmp(name, "group_info")==0) + Sys_Printf("WARNING: unexpected group_info entity in Eclass_ForName\n"); +#endif + + if (!name) + return eclass_bad; + + for (e=eclass ; e ; e=e->next) + if (!strcmp (name, e->name)) + return e; + + // create a new class for it + if (has_brushes) + { + e = EClass_Create(name , 0, 0.5, 0,NULL,NULL,"Not found in source."); + } + else + { + e = EClass_Create(name , 0, 0.5, 0,&smallbox[0],&smallbox[1],"Not found in source."); + } + + Eclass_InsertAlphabetized (e); + + return e; +} diff --git a/radiant/eclass_def.cpp b/radiant/eclass_def.cpp index 6c22dbf4..d5988860 100644 --- a/radiant/eclass_def.cpp +++ b/radiant/eclass_def.cpp @@ -1,306 +1,306 @@ -/* -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 -*/ - -#include "cmdlib.h" - -#include "synapse.h" -#define USE_QERTABLE_DEFINE -#include "qerplugin.h" -#define USE_ECLASSMANAGER_DEFINE -#include "ieclass.h" -#define USE_SCRIPLIBTABLE_DEFINE -#include "iscriplib.h" - -#define __VFSTABLENAME g_FileSystemTable_def -#define USE_VFSTABLE_DEFINE -#include "ifilesystem.h" - - -#include "eclass_def.h" - -/*! \file eclass_def.cpp - \brief .def entity description format - implements parsing for .def entity format - this is statically linked into the radiant core as we always need it, but really considered - as an idependant module by the rest of the core. "ECLASS_MAJOR" "def" -*/ - -_QERScripLibTable g_ScripLibTable; -_EClassManagerTable g_EClassManagerTable; -_QERFuncTable_1 g_FuncTable; -_QERFileSystemTable g_FileSystemTable_def; - -CSynapseBuiltinClientDef eclass_def; - -// forward declare, I'm cheap -void Eclass_ScanFile (char *filename); - -const char* EClass_GetExtension() -{ - return "def"; -} - -void CSynapseBuiltinClientDef::EnumerateInterfaces(CSynapseServer *server) -{ - AddAPI(SCRIPLIB_MAJOR, NULL, sizeof(g_ScripLibTable), SYN_REQUIRE, &g_ScripLibTable); - AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable); - AddAPI(ECLASSMANAGER_MAJOR, NULL, sizeof(g_EClassManagerTable), SYN_REQUIRE, &g_EClassManagerTable); - // hardcode the minor for now, we can still add it to the synapse.config at some point - AddAPI(VFS_MAJOR, "pk3", sizeof(g_FileSystemTable_def), SYN_REQUIRE, &g_FileSystemTable_def); - - AddAPI(ECLASS_MAJOR, "def", sizeof(_EClassTable)); -} - -bool CSynapseBuiltinClientDef::RequestAPI(APIDescriptor_t *pAPI) -{ - if (!strcmp(pAPI->major_name, ECLASS_MAJOR)) - { - _EClassTable* pTable= static_cast<_EClassTable*>(pAPI->mpTable); - pTable->m_pfnScanFile = &Eclass_ScanFile; - pTable->m_pfnGetExtension = &EClass_GetExtension; - - return true; - } - - Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); - return false; -} - -#include "version.h" - -const char* CSynapseBuiltinClientDef::GetInfo() -{ - return "Builtin .def module built " __DATE__ " " RADIANT_VERSION; -} - -// ------------------------------------------------------------------------------------------------ - -qboolean eclass_found; -char *debugname; - -void setSpecialLoad(eclass_t *e, const char* pWhat, char*& p) -{ - // Hydra: removed some amazingly bad cstring usage, whoever wrote that - // needs to be taken out and shot. - - char *pText = NULL; - char *where = NULL; - - p = NULL; // incase we don't find what we're looking for. - where = strstr(e->comments,pWhat); - if (!where) - return; - - pText = where + strlen(pWhat); - if (*pText == '\"') - pText++; - - where = strchr(pText,'\"'); - if (where) - { - int len = (where-pText); - p = new char[len + 1]; - strncpy(p,pText,len); - p[len]=0; // just to make sure, as most implementations of strncpy don't null terminate - } - else - p = strdup(pText); -} - -eclass_t *Eclass_InitFromText (char *text) -{ - char *t; - int len; - int r, i; - char parms[256], *p; - eclass_t *e; - char color[128]; - - e = (eclass_t*)malloc(sizeof(*e)); - memset (e, 0, sizeof(*e)); - - text += strlen("/*QUAKED "); - - // grab the name - text = COM_Parse (text); - e->name = (char*)malloc (strlen(Get_COM_Token())+1); - strcpy (e->name, Get_COM_Token()); - debugname = e->name; - - // grab the color, reformat as texture name - r = sscanf (text," (%f %f %f)", &e->color[0], &e->color[1], &e->color[2]); - if (r != 3) { - return e; - } - sprintf (color, "(%f %f %f)", e->color[0], e->color[1], e->color[2]); - //strcpy (e->texdef.name, color); - e->texdef.SetName(color); - - while (*text != ')') - { - if (!*text) { - return e; - } - text++; - } - text++; - - // get the size - text = COM_Parse (text); - if (Get_COM_Token()[0] == '(') - { // parse the size as two vectors - e->fixedsize = true; - r = sscanf (text,"%f %f %f) (%f %f %f)", &e->mins[0], &e->mins[1], &e->mins[2], - &e->maxs[0], &e->maxs[1], &e->maxs[2]); - if (r != 6) { - return e; - } - - for (i=0 ; i<2 ; i++) - { - while (*text != ')') - { - if (!*text) { - return e; - } - text++; - } - text++; - } - } - - // get the flags - - // copy to the first /n - p = parms; - while (*text && *text != '\n') - *p++ = *text++; - *p = 0; - text++; - - // any remaining words are parm flags - p = parms; - for (i=0 ; iflagnames[i], Get_COM_Token()); - } - - // find the length until close comment - for (t=text ; t[0] && !(t[0]=='*' && t[1]=='/') ; t++) - ; - - // copy the comment block out - len = t-text; - e->comments = (char*)malloc (len+1); - memcpy (e->comments, text, len); -#ifdef _WIN32 - // the win32 Gtk widgets are expecting text stuff to be in unix format (that is CR only instead of DOS's CR/LF) - // we convert on the fly by replacing the LF with a ' ' (yeah I'm cheap) - for (i=0 ; icomments[i] = ' '; - else - e->comments[i] = text[i]; -#endif - e->comments[len] = 0; - - setSpecialLoad(e, "model=", e->modelpath); - setSpecialLoad(e, "skin=", e->skinpath); - char *pFrame = NULL; - setSpecialLoad(e, "frame=", pFrame); - if (pFrame != NULL) - { - e->nFrame = atoi(pFrame); - delete pFrame; //Hydra - Fixed memory leak! - } - - if(!e->skinpath) - setSpecialLoad(e, "texture=", e->skinpath); - - // setup show flags - e->nShowFlags = 0; - if (strcmpi(e->name, "light") == 0 || strcmpi(e->name, "dlight") == 0 || strcmpi(e->name, "lightjunior") == 0) - { - e->nShowFlags |= ECLASS_LIGHT; - } - - if ( (strnicmp(e->name, "info_player", strlen("info_player")) == 0) - ||(strnicmp(e->name, "path_corner", strlen("path_corner")) == 0) - ||(strnicmp(e->name, "team_ctf", strlen("team_ctf")) == 0) - ||(strnicmp(e->name, "misc_teleporter_dest", strlen("misc_teleporter_dest")) == 0) - ) - { - e->nShowFlags |= ECLASS_ANGLE; - } - if (strcmpi(e->name, "path") == 0) - { - e->nShowFlags |= ECLASS_PATH; - } - if (strcmpi(e->name, "misc_model") == 0) - { - e->nShowFlags |= ECLASS_MISCMODEL; - } - - - return e; -} - -void Eclass_ScanFile (char *filename) -{ - int size; - char *data; - eclass_t *e; - int i; - char temp[1024]; - - QE_ConvertDOSToUnixName( temp, filename ); - - size = vfsLoadFullPathFile(filename, (void**)&data); - if (size <= 0) - { - Sys_FPrintf (SYS_ERR, "Eclass_ScanFile: %s not found\n", filename); - return; - } - Sys_Printf ("ScanFile: %s\n", temp); - eclass_found = false; - for (i=0 ; imajor_name, ECLASS_MAJOR)) + { + _EClassTable* pTable= static_cast<_EClassTable*>(pAPI->mpTable); + pTable->m_pfnScanFile = &Eclass_ScanFile; + pTable->m_pfnGetExtension = &EClass_GetExtension; + + return true; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseBuiltinClientDef::GetInfo() +{ + return "Builtin .def module built " __DATE__ " " RADIANT_VERSION; +} + +// ------------------------------------------------------------------------------------------------ + +qboolean eclass_found; +char *debugname; + +void setSpecialLoad(eclass_t *e, const char* pWhat, char*& p) +{ + // Hydra: removed some amazingly bad cstring usage, whoever wrote that + // needs to be taken out and shot. + + char *pText = NULL; + char *where = NULL; + + p = NULL; // incase we don't find what we're looking for. + where = strstr(e->comments,pWhat); + if (!where) + return; + + pText = where + strlen(pWhat); + if (*pText == '\"') + pText++; + + where = strchr(pText,'\"'); + if (where) + { + int len = (where-pText); + p = new char[len + 1]; + strncpy(p,pText,len); + p[len]=0; // just to make sure, as most implementations of strncpy don't null terminate + } + else + p = strdup(pText); +} + +eclass_t *Eclass_InitFromText (char *text) +{ + char *t; + int len; + int r, i; + char parms[256], *p; + eclass_t *e; + char color[128]; + + e = (eclass_t*)malloc(sizeof(*e)); + memset (e, 0, sizeof(*e)); + + text += strlen("/*QUAKED "); + + // grab the name + text = COM_Parse (text); + e->name = (char*)malloc (strlen(Get_COM_Token())+1); + strcpy (e->name, Get_COM_Token()); + debugname = e->name; + + // grab the color, reformat as texture name + r = sscanf (text," (%f %f %f)", &e->color[0], &e->color[1], &e->color[2]); + if (r != 3) { + return e; + } + sprintf (color, "(%f %f %f)", e->color[0], e->color[1], e->color[2]); + //strcpy (e->texdef.name, color); + e->texdef.SetName(color); + + while (*text != ')') + { + if (!*text) { + return e; + } + text++; + } + text++; + + // get the size + text = COM_Parse (text); + if (Get_COM_Token()[0] == '(') + { // parse the size as two vectors + e->fixedsize = true; + r = sscanf (text,"%f %f %f) (%f %f %f)", &e->mins[0], &e->mins[1], &e->mins[2], + &e->maxs[0], &e->maxs[1], &e->maxs[2]); + if (r != 6) { + return e; + } + + for (i=0 ; i<2 ; i++) + { + while (*text != ')') + { + if (!*text) { + return e; + } + text++; + } + text++; + } + } + + // get the flags + + // copy to the first /n + p = parms; + while (*text && *text != '\n') + *p++ = *text++; + *p = 0; + text++; + + // any remaining words are parm flags + p = parms; + for (i=0 ; iflagnames[i], Get_COM_Token()); + } + + // find the length until close comment + for (t=text ; t[0] && !(t[0]=='*' && t[1]=='/') ; t++) + ; + + // copy the comment block out + len = t-text; + e->comments = (char*)malloc (len+1); + memcpy (e->comments, text, len); +#ifdef _WIN32 + // the win32 Gtk widgets are expecting text stuff to be in unix format (that is CR only instead of DOS's CR/LF) + // we convert on the fly by replacing the LF with a ' ' (yeah I'm cheap) + for (i=0 ; icomments[i] = ' '; + else + e->comments[i] = text[i]; +#endif + e->comments[len] = 0; + + setSpecialLoad(e, "model=", e->modelpath); + setSpecialLoad(e, "skin=", e->skinpath); + char *pFrame = NULL; + setSpecialLoad(e, "frame=", pFrame); + if (pFrame != NULL) + { + e->nFrame = atoi(pFrame); + delete pFrame; //Hydra - Fixed memory leak! + } + + if(!e->skinpath) + setSpecialLoad(e, "texture=", e->skinpath); + + // setup show flags + e->nShowFlags = 0; + if (strcmpi(e->name, "light") == 0 || strcmpi(e->name, "dlight") == 0 || strcmpi(e->name, "lightjunior") == 0) + { + e->nShowFlags |= ECLASS_LIGHT; + } + + if ( (strnicmp(e->name, "info_player", strlen("info_player")) == 0) + ||(strnicmp(e->name, "path_corner", strlen("path_corner")) == 0) + ||(strnicmp(e->name, "team_ctf", strlen("team_ctf")) == 0) + ||(strnicmp(e->name, "misc_teleporter_dest", strlen("misc_teleporter_dest")) == 0) + ) + { + e->nShowFlags |= ECLASS_ANGLE; + } + if (strcmpi(e->name, "path") == 0) + { + e->nShowFlags |= ECLASS_PATH; + } + if (strcmpi(e->name, "misc_model") == 0) + { + e->nShowFlags |= ECLASS_MISCMODEL; + } + + + return e; +} + +void Eclass_ScanFile (char *filename) +{ + int size; + char *data; + eclass_t *e; + int i; + char temp[1024]; + + QE_ConvertDOSToUnixName( temp, filename ); + + size = vfsLoadFullPathFile(filename, (void**)&data); + if (size <= 0) + { + Sys_FPrintf (SYS_ERR, "Eclass_ScanFile: %s not found\n", filename); + return; + } + Sys_Printf ("ScanFile: %s\n", temp); + eclass_found = false; + for (i=0 ; i -#endif - -/* -================= -Error - -For abnormal program terminations -================= -*/ - -/*! -\todo -FIXME the prompt wether to do prefs dialog, may not even be possible -if the crash happens before the game is loaded -*/ - -void Error (const char *error, ...) -{ - va_list argptr; - char text[4096]; - - va_start (argptr,error); - vsprintf (text, error,argptr); - va_end (argptr); - - strcat( text, "\n" ); - -#if defined (__linux__) || defined (__APPLE__) - if (errno != 0) - { - strcat( text, "errno: " ); - strcat( text, strerror (errno)); - strcat( text, "\n"); - } -#endif - -#ifdef _WIN32 - if (GetLastError() != 0) - { - LPVOID lpMsgBuf; - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPTSTR) &lpMsgBuf, - 0, - NULL - ); - strcat( text, "GetLastError: " ); - /* - Gtk will only crunch 0<=char<=127 - this is a bit hackish, but I didn't find useful functions in win32 API for this - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=516 - */ - TCHAR *scan, *next = (TCHAR*)lpMsgBuf; - do - { - scan = next; - text[strlen(text)+1] = '\0'; - if ((scan[0] >= 0) && (scan[0] <= 127)) - text[strlen(text)] = scan[0]; - else - text[strlen(text)] = '?'; - next = CharNext(scan); - } while (next != scan); - strcat( text, "\n"); - LocalFree( lpMsgBuf ); - } -#endif - - // we need to have a current context to call glError() - if (g_qeglobals_gui.d_glBase != NULL) - { - // qglGetError .. can record several errors, clears after calling - //++timo TODO: be able to deal with several errors if necessary, for now I'm just warning about pending error messages - // NOTE: forget that, most boards don't seem to follow the OpenGL standard - GLenum iGLError = qglGetError(); - if (iGLError != GL_NO_ERROR) - { - // use our own gluErrorString - strcat( text, "qgluErrorString: " ); - strcat( text, (char*)qgluErrorString( iGLError ) ); - strcat( text, "\n" ); - } - } - - strcat (text, "An unrecoverable error has occured.\n" - "Would you like to edit Preferences before exiting Radiant?"); - - Sys_Printf(text); - - if (gtk_MessageBox(NULL, text, "Error", MB_YESNO) == IDYES) - { - Sys_Printf("Doing prefs..\n"); - g_PrefsDlg.LoadPrefs (); - g_PrefsDlg.DoModal(); - } - - QGL_Shutdown(); - - g_PrefsDlg.Destroy (); - g_dlgSurface.Destroy (); - g_dlgFind.Destroy (); - - // force close logging if necessary - g_PrefsDlg.mGamesDialog.m_bLogConsole = false; - Sys_LogFile(); - - _exit (1); -} - -void WINAPI Error (char *error, ...) -{ - va_list argptr; - char text[1024]; - - va_start (argptr,error); - vsprintf (text, error,argptr); - va_end (argptr); - - Error((const char *)text); -} +/* +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 +*/ + +#define UNICODE +#include "stdafx.h" + +#if defined (__linux__) || defined (__APPLE__) +#include +#endif + +/* +================= +Error + +For abnormal program terminations +================= +*/ + +/*! +\todo +FIXME the prompt wether to do prefs dialog, may not even be possible +if the crash happens before the game is loaded +*/ + +void Error (const char *error, ...) +{ + va_list argptr; + char text[4096]; + + va_start (argptr,error); + vsprintf (text, error,argptr); + va_end (argptr); + + strcat( text, "\n" ); + +#if defined (__linux__) || defined (__APPLE__) + if (errno != 0) + { + strcat( text, "errno: " ); + strcat( text, strerror (errno)); + strcat( text, "\n"); + } +#endif + +#ifdef _WIN32 + if (GetLastError() != 0) + { + LPVOID lpMsgBuf; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + strcat( text, "GetLastError: " ); + /* + Gtk will only crunch 0<=char<=127 + this is a bit hackish, but I didn't find useful functions in win32 API for this + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=516 + */ + TCHAR *scan, *next = (TCHAR*)lpMsgBuf; + do + { + scan = next; + text[strlen(text)+1] = '\0'; + if ((scan[0] >= 0) && (scan[0] <= 127)) + text[strlen(text)] = scan[0]; + else + text[strlen(text)] = '?'; + next = CharNext(scan); + } while (next != scan); + strcat( text, "\n"); + LocalFree( lpMsgBuf ); + } +#endif + + // we need to have a current context to call glError() + if (g_qeglobals_gui.d_glBase != NULL) + { + // qglGetError .. can record several errors, clears after calling + //++timo TODO: be able to deal with several errors if necessary, for now I'm just warning about pending error messages + // NOTE: forget that, most boards don't seem to follow the OpenGL standard + GLenum iGLError = qglGetError(); + if (iGLError != GL_NO_ERROR) + { + // use our own gluErrorString + strcat( text, "qgluErrorString: " ); + strcat( text, (char*)qgluErrorString( iGLError ) ); + strcat( text, "\n" ); + } + } + + strcat (text, "An unrecoverable error has occured.\n" + "Would you like to edit Preferences before exiting Radiant?"); + + Sys_Printf(text); + + if (gtk_MessageBox(NULL, text, "Error", MB_YESNO) == IDYES) + { + Sys_Printf("Doing prefs..\n"); + g_PrefsDlg.LoadPrefs (); + g_PrefsDlg.DoModal(); + } + + QGL_Shutdown(); + + g_PrefsDlg.Destroy (); + g_dlgSurface.Destroy (); + g_dlgFind.Destroy (); + + // force close logging if necessary + g_PrefsDlg.mGamesDialog.m_bLogConsole = false; + Sys_LogFile(); + + _exit (1); +} + +void WINAPI Error (char *error, ...) +{ + va_list argptr; + char text[1024]; + + va_start (argptr,error); + vsprintf (text, error,argptr); + va_end (argptr); + + Error((const char *)text); +} diff --git a/radiant/feedback.cpp b/radiant/feedback.cpp index 26e283da..91e62ae0 100644 --- a/radiant/feedback.cpp +++ b/radiant/feedback.cpp @@ -1,368 +1,368 @@ -/* -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 -*/ - -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// classes used for describing geometry information from q3map feedback -// - -#include "stdafx.h" - -#include "feedback.h" -#include "glib.h" -#include - -CDbgDlg g_DbgDlg; - -void CSelectMsg::saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs) -{ - if (strcmp ((char *)name, "select")==0) - { - // read the message - ESelectState = SELECT_MESSAGE; - } - else - { - // read the brush - assert (strcmp ((char *)name, "brush")==0); - assert (ESelectState == SELECT_MESSAGE); - ESelectState = SELECT_BRUSH; - } -} - -void CSelectMsg::saxEndElement (message_info_t *ctx, const xmlChar *name) -{ - if (strcmp ((char *)name, "select")==0) - { - ctx->bGeometry = false; - } -} - -void CSelectMsg::saxCharacters (message_info_t *ctx, const xmlChar *ch, int len) -{ - if (ESelectState == SELECT_MESSAGE) - { - message = g_string_sized_new (len+1); - memcpy (message->str, ch, len); - message->str[len]='\0'; - Sys_Printf ("%s\n", message->str); - } - else - { - assert (ESelectState == SELECT_BRUSH); - sscanf ((char *)ch, "%i %i", &entitynum, &brushnum); - } -} - -void CSelectMsg::Highlight () -{ - Select_Deselect (); - SelectBrush (entitynum, brushnum); -} - -void CPointMsg::saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs) -{ - if (strcmp ((char *)name, "pointmsg")==0) - { - // read the message - EPointState = POINT_MESSAGE; - } - else - { - // read the brush - assert (strcmp ((char *)name, "point")==0); - assert (EPointState == POINT_MESSAGE); - EPointState = POINT_POINT; - } -} - -void CPointMsg::saxEndElement (message_info_t *ctx, const xmlChar *name) -{ - if (strcmp ((char *)name, "pointmsg")==0) - { - ctx->bGeometry = false; - } -} - -void CPointMsg::saxCharacters (message_info_t *ctx, const xmlChar *ch, int len) -{ - if (EPointState == POINT_MESSAGE) - { - message = g_string_sized_new (len+1); - memcpy (message->str, ch, len); - message->str[len]='\0'; - Sys_Printf ("%s\n", message->str); - } - else - { - assert (EPointState == POINT_POINT); - sscanf ((char *)ch, "%g %g %g", &(pt[0]), &(pt[1]), &(pt[2])); - } -} - -void CPointMsg::Highlight () -{ - // use the entity API to push a point - // the API requires a ref count, we do it manually for the current instance - if (refCount == 0) - { - refCount++; - QERApp_HookGL2DWindow (this); - } -} - -void CPointMsg::DropHighlight () -{ - assert (refCount > 0); - QERApp_UnHookGL2DWindow (this); - // do a refCount-- locally (see Highlight) - refCount--; -} - -void CPointMsg::Draw2D( VIEWTYPE vt ) -{ - int nDim1 = (vt == YZ) ? 1 : 0; - int nDim2 = (vt == XY) ? 1 : 2; - qglPointSize(4); - qglColor3f(1.0f,0.0f,0.0f); - qglBegin (GL_POINTS); - qglVertex2f (pt[nDim1], pt[nDim2]); - qglEnd(); - qglBegin (GL_LINE_LOOP); - qglVertex2f (pt[nDim1]-8, pt[nDim2]-8); - qglVertex2f (pt[nDim1]+8, pt[nDim2]-8); - qglVertex2f (pt[nDim1]+8, pt[nDim2]+8); - qglVertex2f (pt[nDim1]-8, pt[nDim2]+8); - qglEnd(); -} - -void CWindingMsg::saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs) -{ - if (strcmp ((char *)name, "windingmsg")==0) - { - // read the message - EPointState = WINDING_MESSAGE; - } - else - { - // read the brush - assert (strcmp ((char *)name, "winding")==0); - assert (EPointState == WINDING_MESSAGE); - EPointState = WINDING_WINDING; - } -} - -void CWindingMsg::saxEndElement (message_info_t *ctx, const xmlChar *name) -{ - if (strcmp ((char *)name, "windingmsg")==0) - { - ctx->bGeometry = false; - } -} - -void CWindingMsg::saxCharacters (message_info_t *ctx, const xmlChar *ch, int len) -{ - if (EPointState == WINDING_MESSAGE) - { - message = g_string_sized_new (len+1); - memcpy (message->str, ch, len); - message->str[len]='\0'; - Sys_Printf ("%s\n", message->str); - } - else - { - char* c; - int i; - - assert (EPointState == WINDING_WINDING); - - - c = (char*)ch; - sscanf (c, "%i ", &numpoints); - - for(i = 0; i < numpoints; i++) - { - c = strchr(++c, '('); - if (c) // even if we are given the number of points when the cycle begins .. don't trust it too much - sscanf(c, "(%g %g %g)", &wt[i][0], &wt[i][1], &wt[i][2]); - else - break; - } - numpoints = i; - } -} - -void CWindingMsg::Highlight () -{ - // use the entity API to push a point - // the API requires a ref count, we do it manually for the current instance - if (refCount == 0) - { - refCount++; - QERApp_HookGL2DWindow (this); - } -} - -void CWindingMsg::DropHighlight () -{ - assert (refCount > 0); - QERApp_UnHookGL2DWindow (this); - // do a refCount-- locally (see Highlight) - refCount--; -} - -void CWindingMsg::Draw2D( VIEWTYPE vt ) -{ - int i; - - int nDim1 = (vt == YZ) ? 1 : 0; - int nDim2 = (vt == XY) ? 1 : 2; - qglColor3f(1.0f,0.f,0.0f); - - qglPointSize(4); - qglBegin (GL_POINTS); - for(i = 0; i < numpoints; i++) - qglVertex2f (wt[i][nDim1], wt[i][nDim2]); - qglEnd(); - qglPointSize(1); - - qglEnable (GL_BLEND); - qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); - qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - qglColor4f(0.133f,0.4f,1.0f,0.5f); - qglBegin (GL_POLYGON); - for(i = 0; i < numpoints; i++) - qglVertex2f (wt[i][nDim1], wt[i][nDim2]); - qglEnd(); - qglDisable (GL_BLEND); -} - -// triggered when the user selects an entry in the feedback box -static void feedback_selection_changed(GtkTreeSelection* selection, gpointer data) -{ - g_DbgDlg.DropHighlight(); - - GtkTreeModel* model; - GtkTreeIter selected; - if(gtk_tree_selection_get_selected(selection, &model, &selected)) - { - GtkTreePath* path = gtk_tree_model_get_path(model, &selected); - g_DbgDlg.SetHighlight(gtk_tree_path_get_indices(path)[0]); - gtk_tree_path_free(path); - } -} - -void CDbgDlg::DropHighlight() -{ - if (m_pHighlight) - { - m_pHighlight->DropHighlight(); - m_pHighlight = NULL; - } -} - -void CDbgDlg::SetHighlight(gint row) -{ - ISAXHandler *h = GetElement(row); - if (h != NULL) - { - h->Highlight(); - m_pHighlight = h; - } -} - -ISAXHandler *CDbgDlg::GetElement (gint row) -{ - return static_cast(g_ptr_array_index(m_pFeedbackElements, row)); -} - -void CDbgDlg::Init () -{ - DropHighlight(); - - // free all the ISAXHandler*, clean it - while (m_pFeedbackElements->len) - { - delete static_cast(g_ptr_array_index (m_pFeedbackElements, 0)); - g_ptr_array_remove_index (m_pFeedbackElements, 0); - } - - if (m_clist != NULL) - gtk_list_store_clear (m_clist); -} - -void CDbgDlg::Push (ISAXHandler *pHandler) -{ - // push in the list - g_ptr_array_add (m_pFeedbackElements, (void *)pHandler); - - if (m_pWidget == NULL) - Create(); - // put stuff in the list - gtk_list_store_clear (m_clist); - for(unsigned int i = 0; i < m_pFeedbackElements->len; ++i) - { - GtkTreeIter iter; - gtk_list_store_append(m_clist, &iter); - gtk_list_store_set(m_clist, &iter, 0, GetElement(i)->getName(), -1); - } - - ShowDlg(); -} - -void CDbgDlg::BuildDialog () -{ - gtk_window_set_title (GTK_WINDOW (m_pWidget), "Q3Map debug window"); - - GtkWidget* scr = gtk_scrolled_window_new (NULL, NULL); - gtk_widget_show (scr); - gtk_container_add (GTK_CONTAINER (m_pWidget), GTK_WIDGET (scr)); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); - - { - GtkListStore* store = gtk_list_store_new(1, G_TYPE_STRING); - - GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); - - { - GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); - GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); - } - - { - GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); - gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE); - g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(feedback_selection_changed), NULL); - } - - gtk_widget_show(view); - - gtk_container_add(GTK_CONTAINER (scr), view); - - g_object_unref(G_OBJECT(store)); - - m_clist = store; - } -} +/* +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 +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// classes used for describing geometry information from q3map feedback +// + +#include "stdafx.h" + +#include "feedback.h" +#include "glib.h" +#include + +CDbgDlg g_DbgDlg; + +void CSelectMsg::saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs) +{ + if (strcmp ((char *)name, "select")==0) + { + // read the message + ESelectState = SELECT_MESSAGE; + } + else + { + // read the brush + assert (strcmp ((char *)name, "brush")==0); + assert (ESelectState == SELECT_MESSAGE); + ESelectState = SELECT_BRUSH; + } +} + +void CSelectMsg::saxEndElement (message_info_t *ctx, const xmlChar *name) +{ + if (strcmp ((char *)name, "select")==0) + { + ctx->bGeometry = false; + } +} + +void CSelectMsg::saxCharacters (message_info_t *ctx, const xmlChar *ch, int len) +{ + if (ESelectState == SELECT_MESSAGE) + { + message = g_string_sized_new (len+1); + memcpy (message->str, ch, len); + message->str[len]='\0'; + Sys_Printf ("%s\n", message->str); + } + else + { + assert (ESelectState == SELECT_BRUSH); + sscanf ((char *)ch, "%i %i", &entitynum, &brushnum); + } +} + +void CSelectMsg::Highlight () +{ + Select_Deselect (); + SelectBrush (entitynum, brushnum); +} + +void CPointMsg::saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs) +{ + if (strcmp ((char *)name, "pointmsg")==0) + { + // read the message + EPointState = POINT_MESSAGE; + } + else + { + // read the brush + assert (strcmp ((char *)name, "point")==0); + assert (EPointState == POINT_MESSAGE); + EPointState = POINT_POINT; + } +} + +void CPointMsg::saxEndElement (message_info_t *ctx, const xmlChar *name) +{ + if (strcmp ((char *)name, "pointmsg")==0) + { + ctx->bGeometry = false; + } +} + +void CPointMsg::saxCharacters (message_info_t *ctx, const xmlChar *ch, int len) +{ + if (EPointState == POINT_MESSAGE) + { + message = g_string_sized_new (len+1); + memcpy (message->str, ch, len); + message->str[len]='\0'; + Sys_Printf ("%s\n", message->str); + } + else + { + assert (EPointState == POINT_POINT); + sscanf ((char *)ch, "%g %g %g", &(pt[0]), &(pt[1]), &(pt[2])); + } +} + +void CPointMsg::Highlight () +{ + // use the entity API to push a point + // the API requires a ref count, we do it manually for the current instance + if (refCount == 0) + { + refCount++; + QERApp_HookGL2DWindow (this); + } +} + +void CPointMsg::DropHighlight () +{ + assert (refCount > 0); + QERApp_UnHookGL2DWindow (this); + // do a refCount-- locally (see Highlight) + refCount--; +} + +void CPointMsg::Draw2D( VIEWTYPE vt ) +{ + int nDim1 = (vt == YZ) ? 1 : 0; + int nDim2 = (vt == XY) ? 1 : 2; + qglPointSize(4); + qglColor3f(1.0f,0.0f,0.0f); + qglBegin (GL_POINTS); + qglVertex2f (pt[nDim1], pt[nDim2]); + qglEnd(); + qglBegin (GL_LINE_LOOP); + qglVertex2f (pt[nDim1]-8, pt[nDim2]-8); + qglVertex2f (pt[nDim1]+8, pt[nDim2]-8); + qglVertex2f (pt[nDim1]+8, pt[nDim2]+8); + qglVertex2f (pt[nDim1]-8, pt[nDim2]+8); + qglEnd(); +} + +void CWindingMsg::saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs) +{ + if (strcmp ((char *)name, "windingmsg")==0) + { + // read the message + EPointState = WINDING_MESSAGE; + } + else + { + // read the brush + assert (strcmp ((char *)name, "winding")==0); + assert (EPointState == WINDING_MESSAGE); + EPointState = WINDING_WINDING; + } +} + +void CWindingMsg::saxEndElement (message_info_t *ctx, const xmlChar *name) +{ + if (strcmp ((char *)name, "windingmsg")==0) + { + ctx->bGeometry = false; + } +} + +void CWindingMsg::saxCharacters (message_info_t *ctx, const xmlChar *ch, int len) +{ + if (EPointState == WINDING_MESSAGE) + { + message = g_string_sized_new (len+1); + memcpy (message->str, ch, len); + message->str[len]='\0'; + Sys_Printf ("%s\n", message->str); + } + else + { + char* c; + int i; + + assert (EPointState == WINDING_WINDING); + + + c = (char*)ch; + sscanf (c, "%i ", &numpoints); + + for(i = 0; i < numpoints; i++) + { + c = strchr(++c, '('); + if (c) // even if we are given the number of points when the cycle begins .. don't trust it too much + sscanf(c, "(%g %g %g)", &wt[i][0], &wt[i][1], &wt[i][2]); + else + break; + } + numpoints = i; + } +} + +void CWindingMsg::Highlight () +{ + // use the entity API to push a point + // the API requires a ref count, we do it manually for the current instance + if (refCount == 0) + { + refCount++; + QERApp_HookGL2DWindow (this); + } +} + +void CWindingMsg::DropHighlight () +{ + assert (refCount > 0); + QERApp_UnHookGL2DWindow (this); + // do a refCount-- locally (see Highlight) + refCount--; +} + +void CWindingMsg::Draw2D( VIEWTYPE vt ) +{ + int i; + + int nDim1 = (vt == YZ) ? 1 : 0; + int nDim2 = (vt == XY) ? 1 : 2; + qglColor3f(1.0f,0.f,0.0f); + + qglPointSize(4); + qglBegin (GL_POINTS); + for(i = 0; i < numpoints; i++) + qglVertex2f (wt[i][nDim1], wt[i][nDim2]); + qglEnd(); + qglPointSize(1); + + qglEnable (GL_BLEND); + qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + qglColor4f(0.133f,0.4f,1.0f,0.5f); + qglBegin (GL_POLYGON); + for(i = 0; i < numpoints; i++) + qglVertex2f (wt[i][nDim1], wt[i][nDim2]); + qglEnd(); + qglDisable (GL_BLEND); +} + +// triggered when the user selects an entry in the feedback box +static void feedback_selection_changed(GtkTreeSelection* selection, gpointer data) +{ + g_DbgDlg.DropHighlight(); + + GtkTreeModel* model; + GtkTreeIter selected; + if(gtk_tree_selection_get_selected(selection, &model, &selected)) + { + GtkTreePath* path = gtk_tree_model_get_path(model, &selected); + g_DbgDlg.SetHighlight(gtk_tree_path_get_indices(path)[0]); + gtk_tree_path_free(path); + } +} + +void CDbgDlg::DropHighlight() +{ + if (m_pHighlight) + { + m_pHighlight->DropHighlight(); + m_pHighlight = NULL; + } +} + +void CDbgDlg::SetHighlight(gint row) +{ + ISAXHandler *h = GetElement(row); + if (h != NULL) + { + h->Highlight(); + m_pHighlight = h; + } +} + +ISAXHandler *CDbgDlg::GetElement (gint row) +{ + return static_cast(g_ptr_array_index(m_pFeedbackElements, row)); +} + +void CDbgDlg::Init () +{ + DropHighlight(); + + // free all the ISAXHandler*, clean it + while (m_pFeedbackElements->len) + { + delete static_cast(g_ptr_array_index (m_pFeedbackElements, 0)); + g_ptr_array_remove_index (m_pFeedbackElements, 0); + } + + if (m_clist != NULL) + gtk_list_store_clear (m_clist); +} + +void CDbgDlg::Push (ISAXHandler *pHandler) +{ + // push in the list + g_ptr_array_add (m_pFeedbackElements, (void *)pHandler); + + if (m_pWidget == NULL) + Create(); + // put stuff in the list + gtk_list_store_clear (m_clist); + for(unsigned int i = 0; i < m_pFeedbackElements->len; ++i) + { + GtkTreeIter iter; + gtk_list_store_append(m_clist, &iter); + gtk_list_store_set(m_clist, &iter, 0, GetElement(i)->getName(), -1); + } + + ShowDlg(); +} + +void CDbgDlg::BuildDialog () +{ + gtk_window_set_title (GTK_WINDOW (m_pWidget), "Q3Map debug window"); + + GtkWidget* scr = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scr); + gtk_container_add (GTK_CONTAINER (m_pWidget), GTK_WIDGET (scr)); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); + + { + GtkListStore* store = gtk_list_store_new(1, G_TYPE_STRING); + + GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + { + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); + gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE); + g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(feedback_selection_changed), NULL); + } + + gtk_widget_show(view); + + gtk_container_add(GTK_CONTAINER (scr), view); + + g_object_unref(G_OBJECT(store)); + + m_clist = store; + } +} diff --git a/radiant/file.cpp b/radiant/file.cpp index 0f3c8555..5d051ca1 100644 --- a/radiant/file.cpp +++ b/radiant/file.cpp @@ -1,390 +1,390 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -// -// File class, can be a memory file or a regular disk file. -// Originally from LeoCAD, used with permission from the author. :) -// -// Leonardo Zide (leo@lokigames.com) -// - -#include "stdafx.h" - -#include -#include -#include -#include - - -IDataStream::IDataStream() -{ } - -IDataStream::~IDataStream() -{ } - -///////////////////////////////////////////////////////////////////////////// -// File construction/destruction - -MemStream::MemStream() -{ - m_nGrowBytes = 1024; - m_nPosition = 0; - m_nBufferSize = 0; - m_nFileSize = 0; - m_pBuffer = NULL; - m_bAutoDelete = true; -} - -MemStream::MemStream(unsigned long nLen) -{ - m_nGrowBytes = 1024; - m_nPosition = 0; - m_nBufferSize = 0; - m_nFileSize = 0; - m_pBuffer = NULL; - m_bAutoDelete = true; - - GrowFile (nLen); -} - -FileStream::FileStream() -{ - m_hFile = NULL; - m_bCloseOnDelete = false; -} - -MemStream::~MemStream() -{ - if (m_pBuffer) - Close(); - - m_nGrowBytes = 0; - m_nPosition = 0; - m_nBufferSize = 0; - m_nFileSize = 0; -} - -FileStream::~FileStream() -{ - if (m_hFile != NULL && m_bCloseOnDelete) - Close(); -} - -///////////////////////////////////////////////////////////////////////////// -// File operations - -char* MemStream::ReadString(char* pBuf, unsigned long nMax) -{ - int nRead = 0; - unsigned char ch; - - if (nMax <= 0) - return NULL; - if (m_nPosition >= m_nFileSize) - return NULL; - - while ((--nMax)) - { - if (m_nPosition == m_nFileSize) - break; - - ch = m_pBuffer[m_nPosition]; - m_nPosition++; - pBuf[nRead++] = ch; - - if (ch == '\n') - break; - } - - pBuf[nRead] = '\0'; - return pBuf; -} - -char* FileStream::ReadString(char* pBuf, unsigned long nMax) -{ - return fgets(pBuf, nMax, m_hFile); -} - -unsigned long MemStream::Read(void* pBuf, unsigned long nCount) -{ - if (nCount == 0) - return 0; - - if (m_nPosition > m_nFileSize) - return 0; - - unsigned long nRead; - if (m_nPosition + nCount > m_nFileSize) - nRead = (unsigned long)(m_nFileSize - m_nPosition); - else - nRead = nCount; - - memcpy((unsigned char*)pBuf, (unsigned char*)m_pBuffer + m_nPosition, nRead); - m_nPosition += nRead; - - return nRead; -} - -unsigned long FileStream::Read(void* pBuf, unsigned long nCount) -{ - return fread(pBuf, 1, nCount, m_hFile); -} - -int MemStream::GetChar() -{ - if (m_nPosition > m_nFileSize) - return 0; - - unsigned char* ret = (unsigned char*)m_pBuffer + m_nPosition; - m_nPosition++; - - return *ret; -} - -int FileStream::GetChar() -{ - return fgetc(m_hFile); -} - -unsigned long MemStream::Write(const void* pBuf, unsigned long nCount) -{ - if (nCount == 0) - return 0; - - if (m_nPosition + nCount > m_nBufferSize) - GrowFile(m_nPosition + nCount); - - memcpy((unsigned char*)m_pBuffer + m_nPosition, (unsigned char*)pBuf, nCount); - - m_nPosition += nCount; - - if (m_nPosition > m_nFileSize) - m_nFileSize = m_nPosition; - - return nCount; -} - -unsigned long FileStream::Write(const void* pBuf, unsigned long nCount) -{ - return fwrite(pBuf, 1, nCount, m_hFile); -} - -int MemStream::PutChar(int c) -{ - if (m_nPosition + 1 > m_nBufferSize) - GrowFile(m_nPosition + 1); - - unsigned char* bt = (unsigned char*)m_pBuffer + m_nPosition; - *bt = c; - - m_nPosition++; - - if (m_nPosition > m_nFileSize) - m_nFileSize = m_nPosition; - - return 1; -} - -/*!\todo SPoG suggestion: replace printf with operator >> using c++ iostream and strstream */ -void FileStream::printf(const char* s, ...) -{ - va_list args; - - va_start (args, s); - vfprintf(m_hFile, s, args); - va_end (args); -} - -/*!\todo SPoG suggestion: replace printf with operator >> using c++ iostream and strstream */ -void MemStream::printf(const char* s, ...) -{ - va_list args; - - char buffer[4096]; - va_start (args, s); - vsprintf(buffer, s, args); - va_end (args); - Write(buffer, strlen(buffer)); -} - -int FileStream::PutChar(int c) -{ - return fputc(c, m_hFile); -} - -bool FileStream::Open(const char *filename, const char *mode) -{ - m_hFile = fopen(filename, mode); - m_bCloseOnDelete = true; - - return (m_hFile != NULL); -} - -void MemStream::Close() -{ - m_nGrowBytes = 0; - m_nPosition = 0; - m_nBufferSize = 0; - m_nFileSize = 0; - if (m_pBuffer && m_bAutoDelete) - free(m_pBuffer); - m_pBuffer = NULL; -} - -void FileStream::Close() -{ - if (m_hFile != NULL) - fclose(m_hFile); - - m_hFile = NULL; - m_bCloseOnDelete = false; -} - -unsigned long MemStream::Seek(long lOff, int nFrom) -{ - unsigned long lNewPos = m_nPosition; - - if (nFrom == SEEK_SET) - lNewPos = lOff; - else if (nFrom == SEEK_CUR) - lNewPos += lOff; - else if (nFrom == SEEK_END) - lNewPos = m_nFileSize + lOff; - else - return (unsigned long)-1; - - m_nPosition = lNewPos; - - return m_nPosition; -} - -unsigned long FileStream::Seek(long lOff, int nFrom) -{ - fseek (m_hFile, lOff, nFrom); - - return ftell(m_hFile); -} - -unsigned long MemStream::GetPosition() const -{ - return m_nPosition; -} - -unsigned long FileStream::GetPosition() const -{ - return ftell(m_hFile); -} - -void MemStream::GrowFile(unsigned long nNewLen) -{ - if (nNewLen > m_nBufferSize) - { - // grow the buffer - unsigned long nNewBufferSize = m_nBufferSize; - - // determine new buffer size - while (nNewBufferSize < nNewLen) - nNewBufferSize += m_nGrowBytes; - - // allocate new buffer - unsigned char* lpNew; - if (m_pBuffer == NULL) - lpNew = static_cast(malloc(nNewBufferSize)); - else - lpNew = static_cast(realloc(m_pBuffer, nNewBufferSize)); - - m_pBuffer = lpNew; - m_nBufferSize = nNewBufferSize; - } -} - -void MemStream::Flush() -{ - // Nothing to be done -} - -void FileStream::Flush() -{ - if (m_hFile == NULL) - return; - - fflush(m_hFile); -} - -void MemStream::Abort() -{ - Close(); -} - -void FileStream::Abort() -{ - if (m_hFile != NULL) - { - // close but ignore errors - if (m_bCloseOnDelete) - fclose(m_hFile); - m_hFile = NULL; - m_bCloseOnDelete = false; - } -} - -void MemStream::SetLength(unsigned long nNewLen) -{ - if (nNewLen > m_nBufferSize) - GrowFile(nNewLen); - - if (nNewLen < m_nPosition) - m_nPosition = nNewLen; - - m_nFileSize = nNewLen; -} - -void FileStream::SetLength(unsigned long nNewLen) -{ - fseek(m_hFile, nNewLen, SEEK_SET); -} - -unsigned long MemStream::GetLength() const -{ - return m_nFileSize; -} - -unsigned long FileStream::GetLength() const -{ - unsigned long nLen, nCur; - - // Seek is a non const operation - nCur = ftell(m_hFile); - fseek(m_hFile, 0, SEEK_END); - nLen = ftell(m_hFile); - fseek(m_hFile, nCur, SEEK_SET); - - return nLen; -} +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// +// File class, can be a memory file or a regular disk file. +// Originally from LeoCAD, used with permission from the author. :) +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" + +#include +#include +#include +#include + + +IDataStream::IDataStream() +{ } + +IDataStream::~IDataStream() +{ } + +///////////////////////////////////////////////////////////////////////////// +// File construction/destruction + +MemStream::MemStream() +{ + m_nGrowBytes = 1024; + m_nPosition = 0; + m_nBufferSize = 0; + m_nFileSize = 0; + m_pBuffer = NULL; + m_bAutoDelete = true; +} + +MemStream::MemStream(unsigned long nLen) +{ + m_nGrowBytes = 1024; + m_nPosition = 0; + m_nBufferSize = 0; + m_nFileSize = 0; + m_pBuffer = NULL; + m_bAutoDelete = true; + + GrowFile (nLen); +} + +FileStream::FileStream() +{ + m_hFile = NULL; + m_bCloseOnDelete = false; +} + +MemStream::~MemStream() +{ + if (m_pBuffer) + Close(); + + m_nGrowBytes = 0; + m_nPosition = 0; + m_nBufferSize = 0; + m_nFileSize = 0; +} + +FileStream::~FileStream() +{ + if (m_hFile != NULL && m_bCloseOnDelete) + Close(); +} + +///////////////////////////////////////////////////////////////////////////// +// File operations + +char* MemStream::ReadString(char* pBuf, unsigned long nMax) +{ + int nRead = 0; + unsigned char ch; + + if (nMax <= 0) + return NULL; + if (m_nPosition >= m_nFileSize) + return NULL; + + while ((--nMax)) + { + if (m_nPosition == m_nFileSize) + break; + + ch = m_pBuffer[m_nPosition]; + m_nPosition++; + pBuf[nRead++] = ch; + + if (ch == '\n') + break; + } + + pBuf[nRead] = '\0'; + return pBuf; +} + +char* FileStream::ReadString(char* pBuf, unsigned long nMax) +{ + return fgets(pBuf, nMax, m_hFile); +} + +unsigned long MemStream::Read(void* pBuf, unsigned long nCount) +{ + if (nCount == 0) + return 0; + + if (m_nPosition > m_nFileSize) + return 0; + + unsigned long nRead; + if (m_nPosition + nCount > m_nFileSize) + nRead = (unsigned long)(m_nFileSize - m_nPosition); + else + nRead = nCount; + + memcpy((unsigned char*)pBuf, (unsigned char*)m_pBuffer + m_nPosition, nRead); + m_nPosition += nRead; + + return nRead; +} + +unsigned long FileStream::Read(void* pBuf, unsigned long nCount) +{ + return fread(pBuf, 1, nCount, m_hFile); +} + +int MemStream::GetChar() +{ + if (m_nPosition > m_nFileSize) + return 0; + + unsigned char* ret = (unsigned char*)m_pBuffer + m_nPosition; + m_nPosition++; + + return *ret; +} + +int FileStream::GetChar() +{ + return fgetc(m_hFile); +} + +unsigned long MemStream::Write(const void* pBuf, unsigned long nCount) +{ + if (nCount == 0) + return 0; + + if (m_nPosition + nCount > m_nBufferSize) + GrowFile(m_nPosition + nCount); + + memcpy((unsigned char*)m_pBuffer + m_nPosition, (unsigned char*)pBuf, nCount); + + m_nPosition += nCount; + + if (m_nPosition > m_nFileSize) + m_nFileSize = m_nPosition; + + return nCount; +} + +unsigned long FileStream::Write(const void* pBuf, unsigned long nCount) +{ + return fwrite(pBuf, 1, nCount, m_hFile); +} + +int MemStream::PutChar(int c) +{ + if (m_nPosition + 1 > m_nBufferSize) + GrowFile(m_nPosition + 1); + + unsigned char* bt = (unsigned char*)m_pBuffer + m_nPosition; + *bt = c; + + m_nPosition++; + + if (m_nPosition > m_nFileSize) + m_nFileSize = m_nPosition; + + return 1; +} + +/*!\todo SPoG suggestion: replace printf with operator >> using c++ iostream and strstream */ +void FileStream::printf(const char* s, ...) +{ + va_list args; + + va_start (args, s); + vfprintf(m_hFile, s, args); + va_end (args); +} + +/*!\todo SPoG suggestion: replace printf with operator >> using c++ iostream and strstream */ +void MemStream::printf(const char* s, ...) +{ + va_list args; + + char buffer[4096]; + va_start (args, s); + vsprintf(buffer, s, args); + va_end (args); + Write(buffer, strlen(buffer)); +} + +int FileStream::PutChar(int c) +{ + return fputc(c, m_hFile); +} + +bool FileStream::Open(const char *filename, const char *mode) +{ + m_hFile = fopen(filename, mode); + m_bCloseOnDelete = true; + + return (m_hFile != NULL); +} + +void MemStream::Close() +{ + m_nGrowBytes = 0; + m_nPosition = 0; + m_nBufferSize = 0; + m_nFileSize = 0; + if (m_pBuffer && m_bAutoDelete) + free(m_pBuffer); + m_pBuffer = NULL; +} + +void FileStream::Close() +{ + if (m_hFile != NULL) + fclose(m_hFile); + + m_hFile = NULL; + m_bCloseOnDelete = false; +} + +unsigned long MemStream::Seek(long lOff, int nFrom) +{ + unsigned long lNewPos = m_nPosition; + + if (nFrom == SEEK_SET) + lNewPos = lOff; + else if (nFrom == SEEK_CUR) + lNewPos += lOff; + else if (nFrom == SEEK_END) + lNewPos = m_nFileSize + lOff; + else + return (unsigned long)-1; + + m_nPosition = lNewPos; + + return m_nPosition; +} + +unsigned long FileStream::Seek(long lOff, int nFrom) +{ + fseek (m_hFile, lOff, nFrom); + + return ftell(m_hFile); +} + +unsigned long MemStream::GetPosition() const +{ + return m_nPosition; +} + +unsigned long FileStream::GetPosition() const +{ + return ftell(m_hFile); +} + +void MemStream::GrowFile(unsigned long nNewLen) +{ + if (nNewLen > m_nBufferSize) + { + // grow the buffer + unsigned long nNewBufferSize = m_nBufferSize; + + // determine new buffer size + while (nNewBufferSize < nNewLen) + nNewBufferSize += m_nGrowBytes; + + // allocate new buffer + unsigned char* lpNew; + if (m_pBuffer == NULL) + lpNew = static_cast(malloc(nNewBufferSize)); + else + lpNew = static_cast(realloc(m_pBuffer, nNewBufferSize)); + + m_pBuffer = lpNew; + m_nBufferSize = nNewBufferSize; + } +} + +void MemStream::Flush() +{ + // Nothing to be done +} + +void FileStream::Flush() +{ + if (m_hFile == NULL) + return; + + fflush(m_hFile); +} + +void MemStream::Abort() +{ + Close(); +} + +void FileStream::Abort() +{ + if (m_hFile != NULL) + { + // close but ignore errors + if (m_bCloseOnDelete) + fclose(m_hFile); + m_hFile = NULL; + m_bCloseOnDelete = false; + } +} + +void MemStream::SetLength(unsigned long nNewLen) +{ + if (nNewLen > m_nBufferSize) + GrowFile(nNewLen); + + if (nNewLen < m_nPosition) + m_nPosition = nNewLen; + + m_nFileSize = nNewLen; +} + +void FileStream::SetLength(unsigned long nNewLen) +{ + fseek(m_hFile, nNewLen, SEEK_SET); +} + +unsigned long MemStream::GetLength() const +{ + return m_nFileSize; +} + +unsigned long FileStream::GetLength() const +{ + unsigned long nLen, nCur; + + // Seek is a non const operation + nCur = ftell(m_hFile); + fseek(m_hFile, 0, SEEK_END); + nLen = ftell(m_hFile); + fseek(m_hFile, nCur, SEEK_SET); + + return nLen; +} diff --git a/radiant/filters.cpp b/radiant/filters.cpp index 6d6c9129..9bd85035 100644 --- a/radiant/filters.cpp +++ b/radiant/filters.cpp @@ -1,242 +1,242 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "stdafx.h" - -bfilter_t *FilterAdd(bfilter_t *pFilter, int type, int bmask, char *str, int exclude) -{ - bfilter_t *pNew = new bfilter_t; - pNew->next = pFilter; - pNew->attribute = type; - if (type == 1 || type == 3) pNew->string = str; - if (type == 2 || type == 4) pNew->mask = bmask; - if (g_qeglobals.d_savedinfo.exclude & exclude) - pNew->active = true; - else - pNew->active = false; - return pNew; -} - - // removes the filter list at *pFilter, returns NULL pointer -bfilter_t *FilterListDelete(bfilter_t *pFilter) -{ - if (pFilter != NULL) - { - FilterListDelete(pFilter->next); - delete pFilter; - } - return NULL; -} - - - //spog - FilterUpdate is called each time the filters are changed by menu or shortcuts -bfilter_t *FilterUpdate(bfilter_t *pFilter) -{ - pFilter = FilterAdd(pFilter,1,0,"clip",EXCLUDE_CLIP); - pFilter = FilterAdd(pFilter,1,0,"caulk",EXCLUDE_CAULK); - pFilter = FilterAdd(pFilter,1,0,"liquids",EXCLUDE_LIQUIDS); - pFilter = FilterAdd(pFilter,1,0,"hint",EXCLUDE_HINTSSKIPS); - pFilter = FilterAdd(pFilter,1,0,"clusterportal",EXCLUDE_CLUSTERPORTALS); - pFilter = FilterAdd(pFilter,1,0,"areaportal",EXCLUDE_AREAPORTALS); - pFilter = FilterAdd(pFilter,2,QER_TRANS,NULL,EXCLUDE_TRANSLUCENT); - pFilter = FilterAdd(pFilter,3,0,"trigger",EXCLUDE_TRIGGERS); - pFilter = FilterAdd(pFilter,3,0,"misc_model",EXCLUDE_MODELS); - pFilter = FilterAdd(pFilter,3,0,"misc_gamemodel",EXCLUDE_MODELS); - pFilter = FilterAdd(pFilter,4,ECLASS_LIGHT,NULL,EXCLUDE_LIGHTS); - pFilter = FilterAdd(pFilter,4,ECLASS_PATH,NULL,EXCLUDE_PATHS); - pFilter = FilterAdd(pFilter,1,0,"lightgrid",EXCLUDE_LIGHTGRID); - pFilter = FilterAdd(pFilter,1,0,"botclip",EXCLUDE_BOTCLIP); - pFilter = FilterAdd(pFilter,1,0,"clipmonster",EXCLUDE_BOTCLIP); - return pFilter; -} - -/* -================== -FilterBrush -================== -*/ - -bool FilterBrush(brush_t *pb) -{ - - if (!pb->owner) - return FALSE; // during construction - - if (pb->hiddenBrush) - return TRUE; - - if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_WORLD) - { - if (strcmp(pb->owner->eclass->name, "worldspawn") == 0 || !strcmp(pb->owner->eclass->name,"func_group")) // hack, treating func_group as world - { - return TRUE; - } - } - - if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_ENT) - { - if (strcmp(pb->owner->eclass->name, "worldspawn") != 0 && strcmp(pb->owner->eclass->name,"func_group")) // hack, treating func_group as world - { - return TRUE; - } - } - - if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_CURVES ) - { - if (pb->patchBrush) - { - return TRUE; - } - } - - - if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_DETAILS ) - { - if (!pb->patchBrush && pb->brush_faces->texdef.contents & CONTENTS_DETAIL ) - { - return TRUE; - } - } - if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_STRUCTURAL ) - { - if (!pb->patchBrush && !( pb->brush_faces->texdef.contents & CONTENTS_DETAIL )) - { - return TRUE; - } - } - - // if brush belongs to world entity or a brushmodel entity and is not a patch - if ( ( strcmp(pb->owner->eclass->name, "worldspawn") == 0 - || !strncmp( pb->owner->eclass->name, "func", 4) - || !strncmp( pb->owner->eclass->name, "trigger", 7) ) && !pb->patchBrush ) - { - bool filterbrush; - for (face_t *f=pb->brush_faces;f!=NULL;f = f->next) - { - filterbrush=false; - for (bfilter_t *filters = g_qeglobals.d_savedinfo.filters; - filters != NULL; - filters = filters->next) - { - // exclude by attribute 1 brush->face->pShader->getName() - if (filters->active && filters->attribute == 1) - { - if (strstr(f->pShader->getName(),filters->string)) - { - filterbrush=true; - break; - } - } - // exclude by attribute 2 brush->face->pShader->getFlags() - else if (filters->active - && filters->attribute == 2) - { - if (f->pShader->getFlags() & filters->mask) - { - filterbrush=true; - break; - } - } - } - if (!filterbrush) - break; - } - if (filterbrush)// if no face is found that should not be excluded - return true; // exclude this brush - } - - // if brush is a patch - if ( pb->patchBrush ) - { - bool drawpatch=true; - for (bfilter_t *filters = g_qeglobals.d_savedinfo.filters; - filters != NULL; - filters = filters->next) - { - // exclude by attribute 1 (for patch) brush->pPatch->pShader->getName() - if (filters->active - && filters->attribute == 1) - { - if (strstr(pb->pPatch->pShader->getName(),filters->string)) - { - drawpatch=false; - break; - } - } - - // exclude by attribute 2 (for patch) brush->pPatch->pShader->getFlags() - if (filters->active - && filters->attribute == 2) - { - if (pb->pPatch->pShader->getFlags() & filters->mask) - { - drawpatch=false; - break; - } - } - } - if (!drawpatch) // if a shader is found that should be excluded - return TRUE; // exclude this patch - } - - if (strcmp(pb->owner->eclass->name, "worldspawn") != 0) // if brush does not belong to world entity - { - bool drawentity=true; - for (bfilter_t *filters = g_qeglobals.d_savedinfo.filters; - filters != NULL; - filters = filters->next) - { - // exclude by attribute 3 brush->owner->eclass->name - if (filters->active - && filters->attribute == 3) - { - if (strstr(pb->owner->eclass->name,filters->string)) - { - drawentity=false; - break; - } - } - - // exclude by attribute 4 brush->owner->eclass->nShowFlags - else if (filters->active - && filters->attribute == 4) - { - if ( pb->owner->eclass->nShowFlags & filters->mask ) - { - drawentity=false; - break; - } - } - } - if (!drawentity) // if an eclass property is found that should be excluded - return TRUE; // exclude this brush - } - return FALSE; -} +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "stdafx.h" + +bfilter_t *FilterAdd(bfilter_t *pFilter, int type, int bmask, char *str, int exclude) +{ + bfilter_t *pNew = new bfilter_t; + pNew->next = pFilter; + pNew->attribute = type; + if (type == 1 || type == 3) pNew->string = str; + if (type == 2 || type == 4) pNew->mask = bmask; + if (g_qeglobals.d_savedinfo.exclude & exclude) + pNew->active = true; + else + pNew->active = false; + return pNew; +} + + // removes the filter list at *pFilter, returns NULL pointer +bfilter_t *FilterListDelete(bfilter_t *pFilter) +{ + if (pFilter != NULL) + { + FilterListDelete(pFilter->next); + delete pFilter; + } + return NULL; +} + + + //spog - FilterUpdate is called each time the filters are changed by menu or shortcuts +bfilter_t *FilterUpdate(bfilter_t *pFilter) +{ + pFilter = FilterAdd(pFilter,1,0,"clip",EXCLUDE_CLIP); + pFilter = FilterAdd(pFilter,1,0,"caulk",EXCLUDE_CAULK); + pFilter = FilterAdd(pFilter,1,0,"liquids",EXCLUDE_LIQUIDS); + pFilter = FilterAdd(pFilter,1,0,"hint",EXCLUDE_HINTSSKIPS); + pFilter = FilterAdd(pFilter,1,0,"clusterportal",EXCLUDE_CLUSTERPORTALS); + pFilter = FilterAdd(pFilter,1,0,"areaportal",EXCLUDE_AREAPORTALS); + pFilter = FilterAdd(pFilter,2,QER_TRANS,NULL,EXCLUDE_TRANSLUCENT); + pFilter = FilterAdd(pFilter,3,0,"trigger",EXCLUDE_TRIGGERS); + pFilter = FilterAdd(pFilter,3,0,"misc_model",EXCLUDE_MODELS); + pFilter = FilterAdd(pFilter,3,0,"misc_gamemodel",EXCLUDE_MODELS); + pFilter = FilterAdd(pFilter,4,ECLASS_LIGHT,NULL,EXCLUDE_LIGHTS); + pFilter = FilterAdd(pFilter,4,ECLASS_PATH,NULL,EXCLUDE_PATHS); + pFilter = FilterAdd(pFilter,1,0,"lightgrid",EXCLUDE_LIGHTGRID); + pFilter = FilterAdd(pFilter,1,0,"botclip",EXCLUDE_BOTCLIP); + pFilter = FilterAdd(pFilter,1,0,"clipmonster",EXCLUDE_BOTCLIP); + return pFilter; +} + +/* +================== +FilterBrush +================== +*/ + +bool FilterBrush(brush_t *pb) +{ + + if (!pb->owner) + return FALSE; // during construction + + if (pb->hiddenBrush) + return TRUE; + + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_WORLD) + { + if (strcmp(pb->owner->eclass->name, "worldspawn") == 0 || !strcmp(pb->owner->eclass->name,"func_group")) // hack, treating func_group as world + { + return TRUE; + } + } + + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_ENT) + { + if (strcmp(pb->owner->eclass->name, "worldspawn") != 0 && strcmp(pb->owner->eclass->name,"func_group")) // hack, treating func_group as world + { + return TRUE; + } + } + + if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_CURVES ) + { + if (pb->patchBrush) + { + return TRUE; + } + } + + + if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_DETAILS ) + { + if (!pb->patchBrush && pb->brush_faces->texdef.contents & CONTENTS_DETAIL ) + { + return TRUE; + } + } + if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_STRUCTURAL ) + { + if (!pb->patchBrush && !( pb->brush_faces->texdef.contents & CONTENTS_DETAIL )) + { + return TRUE; + } + } + + // if brush belongs to world entity or a brushmodel entity and is not a patch + if ( ( strcmp(pb->owner->eclass->name, "worldspawn") == 0 + || !strncmp( pb->owner->eclass->name, "func", 4) + || !strncmp( pb->owner->eclass->name, "trigger", 7) ) && !pb->patchBrush ) + { + bool filterbrush; + for (face_t *f=pb->brush_faces;f!=NULL;f = f->next) + { + filterbrush=false; + for (bfilter_t *filters = g_qeglobals.d_savedinfo.filters; + filters != NULL; + filters = filters->next) + { + // exclude by attribute 1 brush->face->pShader->getName() + if (filters->active && filters->attribute == 1) + { + if (strstr(f->pShader->getName(),filters->string)) + { + filterbrush=true; + break; + } + } + // exclude by attribute 2 brush->face->pShader->getFlags() + else if (filters->active + && filters->attribute == 2) + { + if (f->pShader->getFlags() & filters->mask) + { + filterbrush=true; + break; + } + } + } + if (!filterbrush) + break; + } + if (filterbrush)// if no face is found that should not be excluded + return true; // exclude this brush + } + + // if brush is a patch + if ( pb->patchBrush ) + { + bool drawpatch=true; + for (bfilter_t *filters = g_qeglobals.d_savedinfo.filters; + filters != NULL; + filters = filters->next) + { + // exclude by attribute 1 (for patch) brush->pPatch->pShader->getName() + if (filters->active + && filters->attribute == 1) + { + if (strstr(pb->pPatch->pShader->getName(),filters->string)) + { + drawpatch=false; + break; + } + } + + // exclude by attribute 2 (for patch) brush->pPatch->pShader->getFlags() + if (filters->active + && filters->attribute == 2) + { + if (pb->pPatch->pShader->getFlags() & filters->mask) + { + drawpatch=false; + break; + } + } + } + if (!drawpatch) // if a shader is found that should be excluded + return TRUE; // exclude this patch + } + + if (strcmp(pb->owner->eclass->name, "worldspawn") != 0) // if brush does not belong to world entity + { + bool drawentity=true; + for (bfilter_t *filters = g_qeglobals.d_savedinfo.filters; + filters != NULL; + filters = filters->next) + { + // exclude by attribute 3 brush->owner->eclass->name + if (filters->active + && filters->attribute == 3) + { + if (strstr(pb->owner->eclass->name,filters->string)) + { + drawentity=false; + break; + } + } + + // exclude by attribute 4 brush->owner->eclass->nShowFlags + else if (filters->active + && filters->attribute == 4) + { + if ( pb->owner->eclass->nShowFlags & filters->mask ) + { + drawentity=false; + break; + } + } + } + if (!drawentity) // if an eclass property is found that should be excluded + return TRUE; // exclude this brush + } + return FALSE; +} diff --git a/radiant/findtexturedialog.cpp b/radiant/findtexturedialog.cpp index 9cbe68d8..012208c2 100644 --- a/radiant/findtexturedialog.cpp +++ b/radiant/findtexturedialog.cpp @@ -1,289 +1,289 @@ -/* -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 -*/ - -// -// Find/Replace textures dialogs -// -// Leonardo Zide (leo@lokigames.com) -// - -#include "stdafx.h" -#include "findtexturedialog.h" - -FindTextureDialog g_TexFindDlg; -FindTextureDialog& g_dlgFind = g_TexFindDlg; -static bool g_bFindActive = true; - -static void OnApply(GtkWidget *widget, gpointer data) -{ - g_dlgFind.UpdateData(TRUE); - FindReplaceTextures(g_dlgFind.m_strFind, g_dlgFind.m_strReplace, - g_dlgFind.m_bSelectedOnly, g_dlgFind.m_bForce, FALSE); -} - -static void OnFind(GtkWidget *widget, gpointer data) -{ - g_dlgFind.UpdateData(TRUE); - FindReplaceTextures(g_dlgFind.m_strFind, g_dlgFind.m_strReplace, - g_dlgFind.m_bSelectedOnly, FALSE, TRUE); -} - -static void OnOK(GtkWidget *widget, gpointer data) -{ - g_dlgFind.UpdateData(TRUE); - FindReplaceTextures(g_dlgFind.m_strFind, g_dlgFind.m_strReplace, - g_dlgFind.m_bSelectedOnly, g_dlgFind.m_bForce, FALSE); - g_dlgFind.HideDlg (); -} - -static void OnClose(GtkWidget *widget, gpointer data) -{ - g_dlgFind.HideDlg (); -} - -static void popup_selected (GtkWidget *widget, gpointer data) -{ - gchar *str; - - gtk_label_get (GTK_LABEL (GTK_BIN (widget)->child), &str); - gtk_entry_set_text (GTK_ENTRY (data), str); -} - -static void find_clicked (GtkWidget *widget, gpointer data) -{ - GtkWidget *menu, *item; - menu = gtk_menu_new (); - - for (int i = 0; i < QERApp_GetActiveShaderCount (); i++) - { - IShader *pShader = QERApp_ActiveShader_ForIndex (i); - - item = gtk_menu_item_new_with_label (pShader->getName ()); - gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (popup_selected), data); - gtk_widget_show (item); - gtk_menu_append (GTK_MENU (menu), item); - } - - gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME); -} - -static gint find_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer data) -{ - g_bFindActive = true; - return FALSE; -} - -static gint replace_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer data) -{ - g_bFindActive = false; - return FALSE; -} - -// ============================================================================= -// FindTextureDialog class - -FindTextureDialog::FindTextureDialog () -{ - m_bSelectedOnly = FALSE; - m_strFind = ""; - m_strReplace = ""; - m_bForce = FALSE; - m_bLive = TRUE; -} - -FindTextureDialog::~FindTextureDialog () -{ -} - -void FindTextureDialog::BuildDialog () -{ - GtkWidget *dlg, *vbox, *hbox, *table, *label; - GtkWidget *button, *check, *entry, *arrow; - - dlg = m_pWidget; - gtk_window_set_title (GTK_WINDOW (dlg), "Find / Replace Texture(s)"); - gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pParentWnd->m_pWidget)); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_container_add (GTK_CONTAINER (dlg), hbox); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); - - table = gtk_table_new (2, 3, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("Find:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - label = gtk_label_new ("Replace:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_signal_connect (GTK_OBJECT (entry), "focus_in_event", - GTK_SIGNAL_FUNC (find_focus_in), NULL); - AddDialogData (entry, &m_strFind, DLG_ENTRY_TEXT); - - button = gtk_button_new (); - gtk_widget_show (button); - gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (find_clicked), entry); - - arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT); - gtk_widget_show (arrow); - gtk_container_add (GTK_CONTAINER (button), arrow); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_signal_connect (GTK_OBJECT (entry), "focus_in_event", - GTK_SIGNAL_FUNC (replace_focus_in), NULL); - AddDialogData (entry, &m_strReplace, DLG_ENTRY_TEXT); - - button = gtk_button_new (); - gtk_widget_show (button); - gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (find_clicked), entry); - - arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT); - gtk_widget_show (arrow); - gtk_container_add (GTK_CONTAINER (button), arrow); - - check = gtk_check_button_new_with_label ("Use selected brushes only"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, TRUE, TRUE, 0); - AddDialogData (check, &m_bSelectedOnly, DLG_CHECK_BOOL); - - check = gtk_check_button_new_with_label ("Replace everywhere (selected/active), don't test against Find"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, TRUE, TRUE, 0); - AddDialogData (check, &m_bForce, DLG_CHECK_BOOL); - - check = gtk_check_button_new_with_label ("Live updates from Texture/Camera windows"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, TRUE, TRUE, 0); - AddDialogData (check, &m_bLive, DLG_CHECK_BOOL); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); - - button = gtk_button_new_with_label( "Find" ); - gtk_widget_show( button ); - gtk_box_pack_start( GTK_BOX( vbox ), button, FALSE, FALSE, 0 ); - gtk_signal_connect( GTK_OBJECT( button ), "clicked", - GTK_SIGNAL_FUNC( OnFind ), NULL ); - gtk_widget_set_usize( button, 60, -2 ); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (OnOK), NULL); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Apply"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (OnApply), NULL); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Close"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (OnClose), NULL); - gtk_widget_set_usize (button, 60, -2); - - gtk_widget_show (dlg); -} - -void FindTextureDialog::updateTextures(const char *p) -{ - if (isOpen()) - { - if (g_bFindActive) - { - setFindStr(p); - } - else - { - setReplaceStr(p); - } - } -} - -bool FindTextureDialog::isOpen() -{ - return (g_dlgFind.m_pWidget == NULL || GTK_WIDGET_VISIBLE (g_dlgFind.m_pWidget) == FALSE) ? false : true; -} - -void FindTextureDialog::setFindStr(const char * p) -{ - g_dlgFind.UpdateData(TRUE); - if (g_dlgFind.m_bLive) - { - g_dlgFind.m_strFind = p; - g_dlgFind.UpdateData(FALSE); - } -} - -void FindTextureDialog::setReplaceStr(const char * p) -{ - g_dlgFind.UpdateData(TRUE); - if (g_dlgFind.m_bLive) - { - g_dlgFind.m_strReplace = p; - g_dlgFind.UpdateData(FALSE); - } -} - -void FindTextureDialog::show() -{ - g_dlgFind.ShowDlg (); -} +/* +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 +*/ + +// +// Find/Replace textures dialogs +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" +#include "findtexturedialog.h" + +FindTextureDialog g_TexFindDlg; +FindTextureDialog& g_dlgFind = g_TexFindDlg; +static bool g_bFindActive = true; + +static void OnApply(GtkWidget *widget, gpointer data) +{ + g_dlgFind.UpdateData(TRUE); + FindReplaceTextures(g_dlgFind.m_strFind, g_dlgFind.m_strReplace, + g_dlgFind.m_bSelectedOnly, g_dlgFind.m_bForce, FALSE); +} + +static void OnFind(GtkWidget *widget, gpointer data) +{ + g_dlgFind.UpdateData(TRUE); + FindReplaceTextures(g_dlgFind.m_strFind, g_dlgFind.m_strReplace, + g_dlgFind.m_bSelectedOnly, FALSE, TRUE); +} + +static void OnOK(GtkWidget *widget, gpointer data) +{ + g_dlgFind.UpdateData(TRUE); + FindReplaceTextures(g_dlgFind.m_strFind, g_dlgFind.m_strReplace, + g_dlgFind.m_bSelectedOnly, g_dlgFind.m_bForce, FALSE); + g_dlgFind.HideDlg (); +} + +static void OnClose(GtkWidget *widget, gpointer data) +{ + g_dlgFind.HideDlg (); +} + +static void popup_selected (GtkWidget *widget, gpointer data) +{ + gchar *str; + + gtk_label_get (GTK_LABEL (GTK_BIN (widget)->child), &str); + gtk_entry_set_text (GTK_ENTRY (data), str); +} + +static void find_clicked (GtkWidget *widget, gpointer data) +{ + GtkWidget *menu, *item; + menu = gtk_menu_new (); + + for (int i = 0; i < QERApp_GetActiveShaderCount (); i++) + { + IShader *pShader = QERApp_ActiveShader_ForIndex (i); + + item = gtk_menu_item_new_with_label (pShader->getName ()); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (popup_selected), data); + gtk_widget_show (item); + gtk_menu_append (GTK_MENU (menu), item); + } + + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME); +} + +static gint find_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer data) +{ + g_bFindActive = true; + return FALSE; +} + +static gint replace_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer data) +{ + g_bFindActive = false; + return FALSE; +} + +// ============================================================================= +// FindTextureDialog class + +FindTextureDialog::FindTextureDialog () +{ + m_bSelectedOnly = FALSE; + m_strFind = ""; + m_strReplace = ""; + m_bForce = FALSE; + m_bLive = TRUE; +} + +FindTextureDialog::~FindTextureDialog () +{ +} + +void FindTextureDialog::BuildDialog () +{ + GtkWidget *dlg, *vbox, *hbox, *table, *label; + GtkWidget *button, *check, *entry, *arrow; + + dlg = m_pWidget; + gtk_window_set_title (GTK_WINDOW (dlg), "Find / Replace Texture(s)"); + gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pParentWnd->m_pWidget)); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + table = gtk_table_new (2, 3, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Find:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Replace:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (entry), "focus_in_event", + GTK_SIGNAL_FUNC (find_focus_in), NULL); + AddDialogData (entry, &m_strFind, DLG_ENTRY_TEXT); + + button = gtk_button_new (); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (find_clicked), entry); + + arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT); + gtk_widget_show (arrow); + gtk_container_add (GTK_CONTAINER (button), arrow); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (entry), "focus_in_event", + GTK_SIGNAL_FUNC (replace_focus_in), NULL); + AddDialogData (entry, &m_strReplace, DLG_ENTRY_TEXT); + + button = gtk_button_new (); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (find_clicked), entry); + + arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT); + gtk_widget_show (arrow); + gtk_container_add (GTK_CONTAINER (button), arrow); + + check = gtk_check_button_new_with_label ("Use selected brushes only"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, TRUE, TRUE, 0); + AddDialogData (check, &m_bSelectedOnly, DLG_CHECK_BOOL); + + check = gtk_check_button_new_with_label ("Replace everywhere (selected/active), don't test against Find"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, TRUE, TRUE, 0); + AddDialogData (check, &m_bForce, DLG_CHECK_BOOL); + + check = gtk_check_button_new_with_label ("Live updates from Texture/Camera windows"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, TRUE, TRUE, 0); + AddDialogData (check, &m_bLive, DLG_CHECK_BOOL); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + button = gtk_button_new_with_label( "Find" ); + gtk_widget_show( button ); + gtk_box_pack_start( GTK_BOX( vbox ), button, FALSE, FALSE, 0 ); + gtk_signal_connect( GTK_OBJECT( button ), "clicked", + GTK_SIGNAL_FUNC( OnFind ), NULL ); + gtk_widget_set_usize( button, 60, -2 ); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnOK), NULL); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Apply"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnApply), NULL); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Close"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnClose), NULL); + gtk_widget_set_usize (button, 60, -2); + + gtk_widget_show (dlg); +} + +void FindTextureDialog::updateTextures(const char *p) +{ + if (isOpen()) + { + if (g_bFindActive) + { + setFindStr(p); + } + else + { + setReplaceStr(p); + } + } +} + +bool FindTextureDialog::isOpen() +{ + return (g_dlgFind.m_pWidget == NULL || GTK_WIDGET_VISIBLE (g_dlgFind.m_pWidget) == FALSE) ? false : true; +} + +void FindTextureDialog::setFindStr(const char * p) +{ + g_dlgFind.UpdateData(TRUE); + if (g_dlgFind.m_bLive) + { + g_dlgFind.m_strFind = p; + g_dlgFind.UpdateData(FALSE); + } +} + +void FindTextureDialog::setReplaceStr(const char * p) +{ + g_dlgFind.UpdateData(TRUE); + if (g_dlgFind.m_bLive) + { + g_dlgFind.m_strReplace = p; + g_dlgFind.UpdateData(FALSE); + } +} + +void FindTextureDialog::show() +{ + g_dlgFind.ShowDlg (); +} diff --git a/radiant/glinterface.cpp b/radiant/glinterface.cpp index 254c368e..13e7e6c9 100644 --- a/radiant/glinterface.cpp +++ b/radiant/glinterface.cpp @@ -1,91 +1,91 @@ -/* -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 -*/ - -//----------------------------------------------------------------------------- -// -// -// DESCRIPTION: -// Quick interface hack for selected face interface -// this one really needs more work, but I'm in a hurry with TexTool - -#include "stdafx.h" -//#include "qe3.h" - -// stores objects that want to be hooked into drawing in the XY window or Camera view -//++timo TODO: add support for Z view ... (texture view?) -CPtrArray l_GL2DWindows; -CPtrArray l_GL3DWindows; - -void WINAPI QERApp_HookGL2DWindow(IGL2DWindow* pGLW) -{ - l_GL2DWindows.Add( pGLW ); - pGLW->IncRef(); -} - -void WINAPI QERApp_UnHookGL2DWindow(IGL2DWindow* pGLW) -{ - for( int i = 0; i < l_GL2DWindows.GetSize(); i++ ) - { - if (l_GL2DWindows.GetAt(i) == pGLW) - { - l_GL2DWindows.RemoveAt(i); - pGLW->DecRef(); - return; - } - } -#ifdef _DEBUG - Sys_Printf("ERROR: IGL2DWindow* not found in QERApp_UnHookGL2DWindow\n"); -#endif -} - -void Draw2DPluginEntities( VIEWTYPE vt ) -{ - for(int i = 0; i(l_GL2DWindows.GetAt(i))->Draw2D( vt ); -} - -void WINAPI QERApp_HookGL3DWindow(IGL3DWindow* pGLW) -{ - l_GL3DWindows.Add( pGLW ); - pGLW->IncRef(); -} - -void WINAPI QERApp_UnHookGL3DWindow(IGL3DWindow* pGLW) -{ - for( int i = 0; i < l_GL3DWindows.GetSize(); i++ ) - { - if (l_GL3DWindows.GetAt(i) == pGLW) - { - l_GL3DWindows.RemoveAt(i); - pGLW->DecRef(); - return; - } - } -#ifdef _DEBUG - Sys_Printf("ERROR: IGL3DWindow* not found in QERApp_UnHookGL3DWindow\n"); -#endif -} - -void Draw3DPluginEntities() -{ - for(int i = 0; i(l_GL3DWindows.GetAt(i))->Draw3D(); -} +/* +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 +*/ + +//----------------------------------------------------------------------------- +// +// +// DESCRIPTION: +// Quick interface hack for selected face interface +// this one really needs more work, but I'm in a hurry with TexTool + +#include "stdafx.h" +//#include "qe3.h" + +// stores objects that want to be hooked into drawing in the XY window or Camera view +//++timo TODO: add support for Z view ... (texture view?) +CPtrArray l_GL2DWindows; +CPtrArray l_GL3DWindows; + +void WINAPI QERApp_HookGL2DWindow(IGL2DWindow* pGLW) +{ + l_GL2DWindows.Add( pGLW ); + pGLW->IncRef(); +} + +void WINAPI QERApp_UnHookGL2DWindow(IGL2DWindow* pGLW) +{ + for( int i = 0; i < l_GL2DWindows.GetSize(); i++ ) + { + if (l_GL2DWindows.GetAt(i) == pGLW) + { + l_GL2DWindows.RemoveAt(i); + pGLW->DecRef(); + return; + } + } +#ifdef _DEBUG + Sys_Printf("ERROR: IGL2DWindow* not found in QERApp_UnHookGL2DWindow\n"); +#endif +} + +void Draw2DPluginEntities( VIEWTYPE vt ) +{ + for(int i = 0; i(l_GL2DWindows.GetAt(i))->Draw2D( vt ); +} + +void WINAPI QERApp_HookGL3DWindow(IGL3DWindow* pGLW) +{ + l_GL3DWindows.Add( pGLW ); + pGLW->IncRef(); +} + +void WINAPI QERApp_UnHookGL3DWindow(IGL3DWindow* pGLW) +{ + for( int i = 0; i < l_GL3DWindows.GetSize(); i++ ) + { + if (l_GL3DWindows.GetAt(i) == pGLW) + { + l_GL3DWindows.RemoveAt(i); + pGLW->DecRef(); + return; + } + } +#ifdef _DEBUG + Sys_Printf("ERROR: IGL3DWindow* not found in QERApp_UnHookGL3DWindow\n"); +#endif +} + +void Draw3DPluginEntities() +{ + for(int i = 0; i(l_GL3DWindows.GetAt(i))->Draw3D(); +} diff --git a/radiant/glwidget.cpp b/radiant/glwidget.cpp index ca8a11b0..4498107f 100644 --- a/radiant/glwidget.cpp +++ b/radiant/glwidget.cpp @@ -1,254 +1,254 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -// OpenGL widget based on GtkGLExt - -#include "stdafx.h" - -#include -#include "glwidget.h" -#include "qgl.h" - -typedef int* attribs_t; -typedef const attribs_t* configs_iterator; - -int config_rgba32[] = { - GDK_GL_RGBA, - GDK_GL_DOUBLEBUFFER, - GDK_GL_RED_SIZE, 8, - GDK_GL_BLUE_SIZE, 8, - GDK_GL_GREEN_SIZE, 8, - GDK_GL_ALPHA_SIZE, 8, - GDK_GL_ATTRIB_LIST_NONE, -}; - -int config_rgba[] = { - GDK_GL_RGBA, - GDK_GL_DOUBLEBUFFER, - GDK_GL_RED_SIZE, 1, - GDK_GL_BLUE_SIZE, 1, - GDK_GL_GREEN_SIZE, 1, - GDK_GL_ALPHA_SIZE, 1, - GDK_GL_ATTRIB_LIST_NONE, -}; - -const attribs_t configs[] = { - config_rgba32, - config_rgba, -}; - -GdkGLConfig* glconfig_new() -{ - GdkGLConfig* glconfig = NULL; - - for(configs_iterator i = configs, end = configs + 2; i != end && glconfig == NULL; ++i) - { - glconfig = gdk_gl_config_new(*i); - } - - if(glconfig == NULL) - { - return gdk_gl_config_new_by_mode((GdkGLConfigMode)(GDK_GL_MODE_RGBA | GDK_GL_MODE_DOUBLE)); - } - - return glconfig; -} - -int config_rgba32_depth32[] = { - GDK_GL_RGBA, - GDK_GL_DOUBLEBUFFER, - GDK_GL_RED_SIZE, 8, - GDK_GL_BLUE_SIZE, 8, - GDK_GL_GREEN_SIZE, 8, - GDK_GL_ALPHA_SIZE, 8, - GDK_GL_DEPTH_SIZE, 32, - GDK_GL_ATTRIB_LIST_NONE, -}; - -int config_rgba32_depth24[] = { - GDK_GL_RGBA, - GDK_GL_DOUBLEBUFFER, - GDK_GL_RED_SIZE, 8, - GDK_GL_BLUE_SIZE, 8, - GDK_GL_GREEN_SIZE, 8, - GDK_GL_ALPHA_SIZE, 8, - GDK_GL_DEPTH_SIZE, 24, - GDK_GL_ATTRIB_LIST_NONE, -}; - -int config_rgba32_depth16[] = { - GDK_GL_RGBA, - GDK_GL_DOUBLEBUFFER, - GDK_GL_RED_SIZE, 8, - GDK_GL_BLUE_SIZE, 8, - GDK_GL_GREEN_SIZE, 8, - GDK_GL_ALPHA_SIZE, 8, - GDK_GL_DEPTH_SIZE, 16, - GDK_GL_ATTRIB_LIST_NONE, -}; - -int config_rgba32_depth[] = { - GDK_GL_RGBA, - GDK_GL_DOUBLEBUFFER, - GDK_GL_RED_SIZE, 8, - GDK_GL_BLUE_SIZE, 8, - GDK_GL_GREEN_SIZE, 8, - GDK_GL_ALPHA_SIZE, 8, - GDK_GL_DEPTH_SIZE, 1, - GDK_GL_ATTRIB_LIST_NONE, -}; - -int config_rgba_depth16[] = { - GDK_GL_RGBA, - GDK_GL_DOUBLEBUFFER, - GDK_GL_RED_SIZE, 1, - GDK_GL_BLUE_SIZE, 1, - GDK_GL_GREEN_SIZE, 1, - GDK_GL_ALPHA_SIZE, 1, - GDK_GL_DEPTH_SIZE, 16, - GDK_GL_ATTRIB_LIST_NONE, -}; - -int config_rgba_depth[] = { - GDK_GL_RGBA, - GDK_GL_DOUBLEBUFFER, - GDK_GL_RED_SIZE, 1, - GDK_GL_BLUE_SIZE, 1, - GDK_GL_GREEN_SIZE, 1, - GDK_GL_ALPHA_SIZE, 1, - GDK_GL_DEPTH_SIZE, 1, - GDK_GL_ATTRIB_LIST_NONE, -}; - -const attribs_t configs_with_depth[] = -{ - config_rgba32_depth32, - config_rgba32_depth24, - config_rgba32_depth16, - config_rgba32_depth, - config_rgba_depth16, - config_rgba_depth, -}; - -GdkGLConfig* glconfig_new_with_depth() -{ - GdkGLConfig* glconfig = NULL; - - for(configs_iterator i = configs_with_depth, end = configs_with_depth + 6; i != end && glconfig == NULL; ++i) - { - glconfig = gdk_gl_config_new(*i); - } - - if(glconfig == NULL) - { - return gdk_gl_config_new_by_mode((GdkGLConfigMode)(GDK_GL_MODE_RGBA | GDK_GL_MODE_DOUBLE | GDK_GL_MODE_DEPTH)); - } - - return glconfig; -} - -GtkWidget* WINAPI gtk_glwidget_new (gboolean zbuffer, GtkWidget* share) -{ - GtkWidget* drawing_area = gtk_drawing_area_new(); - GdkGLConfig* glconfig = (zbuffer) ? glconfig_new_with_depth() : glconfig_new(); - GdkGLContext* shared_context = (share) ? gtk_widget_get_gl_context(share) : NULL; - - gtk_widget_set_gl_capability (drawing_area, glconfig, shared_context, TRUE, GDK_GL_RGBA_TYPE); - - return drawing_area; -} - -void WINAPI gtk_glwidget_destroy_context (GtkWidget *widget) -{ -} - -void WINAPI gtk_glwidget_create_context (GtkWidget *widget) -{ -} - -void WINAPI gtk_glwidget_swap_buffers (GtkWidget *widget) -{ - GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget); - gdk_gl_drawable_swap_buffers (gldrawable); -} - -gboolean WINAPI gtk_glwidget_make_current (GtkWidget *widget) -{ - GdkGLContext *glcontext = gtk_widget_get_gl_context (widget); - GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget); - return gdk_gl_drawable_gl_begin (gldrawable, glcontext); -} - -GLuint font_list_base; -static gchar font_string[] = "courier 8"; -static gint font_height; - -void gtk_glwidget_create_font (GtkWidget *widget) -{ - GdkGLContext *glcontext = gtk_widget_get_gl_context (widget); - GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget); - - PangoFontDescription *font_desc; - PangoFont *font; - PangoFontMetrics *font_metrics; - - font_list_base = qglGenLists (256); - - font_desc = pango_font_description_from_string (font_string); - - font = gdk_gl_font_use_pango_font (font_desc, 0, 256, font_list_base); - - if(font != NULL) - { - font_metrics = pango_font_get_metrics (font, NULL); - - font_height = pango_font_metrics_get_ascent (font_metrics) + - pango_font_metrics_get_descent (font_metrics); - font_height = PANGO_PIXELS (font_height); - - pango_font_metrics_unref (font_metrics); - } - - pango_font_description_free (font_desc); -} - - -void gtk_glwidget_print_string(const char *s) -{ - qglListBase(font_list_base); - qglCallLists(strlen(s), GL_UNSIGNED_BYTE, (unsigned char *)s); -} - -void gtk_glwidget_print_char(char s) -{ - qglListBase(font_list_base); - qglCallLists(1, GL_UNSIGNED_BYTE, (unsigned char *) &s); -} - +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// OpenGL widget based on GtkGLExt + +#include "stdafx.h" + +#include +#include "glwidget.h" +#include "qgl.h" + +typedef int* attribs_t; +typedef const attribs_t* configs_iterator; + +int config_rgba32[] = { + GDK_GL_RGBA, + GDK_GL_DOUBLEBUFFER, + GDK_GL_RED_SIZE, 8, + GDK_GL_BLUE_SIZE, 8, + GDK_GL_GREEN_SIZE, 8, + GDK_GL_ALPHA_SIZE, 8, + GDK_GL_ATTRIB_LIST_NONE, +}; + +int config_rgba[] = { + GDK_GL_RGBA, + GDK_GL_DOUBLEBUFFER, + GDK_GL_RED_SIZE, 1, + GDK_GL_BLUE_SIZE, 1, + GDK_GL_GREEN_SIZE, 1, + GDK_GL_ALPHA_SIZE, 1, + GDK_GL_ATTRIB_LIST_NONE, +}; + +const attribs_t configs[] = { + config_rgba32, + config_rgba, +}; + +GdkGLConfig* glconfig_new() +{ + GdkGLConfig* glconfig = NULL; + + for(configs_iterator i = configs, end = configs + 2; i != end && glconfig == NULL; ++i) + { + glconfig = gdk_gl_config_new(*i); + } + + if(glconfig == NULL) + { + return gdk_gl_config_new_by_mode((GdkGLConfigMode)(GDK_GL_MODE_RGBA | GDK_GL_MODE_DOUBLE)); + } + + return glconfig; +} + +int config_rgba32_depth32[] = { + GDK_GL_RGBA, + GDK_GL_DOUBLEBUFFER, + GDK_GL_RED_SIZE, 8, + GDK_GL_BLUE_SIZE, 8, + GDK_GL_GREEN_SIZE, 8, + GDK_GL_ALPHA_SIZE, 8, + GDK_GL_DEPTH_SIZE, 32, + GDK_GL_ATTRIB_LIST_NONE, +}; + +int config_rgba32_depth24[] = { + GDK_GL_RGBA, + GDK_GL_DOUBLEBUFFER, + GDK_GL_RED_SIZE, 8, + GDK_GL_BLUE_SIZE, 8, + GDK_GL_GREEN_SIZE, 8, + GDK_GL_ALPHA_SIZE, 8, + GDK_GL_DEPTH_SIZE, 24, + GDK_GL_ATTRIB_LIST_NONE, +}; + +int config_rgba32_depth16[] = { + GDK_GL_RGBA, + GDK_GL_DOUBLEBUFFER, + GDK_GL_RED_SIZE, 8, + GDK_GL_BLUE_SIZE, 8, + GDK_GL_GREEN_SIZE, 8, + GDK_GL_ALPHA_SIZE, 8, + GDK_GL_DEPTH_SIZE, 16, + GDK_GL_ATTRIB_LIST_NONE, +}; + +int config_rgba32_depth[] = { + GDK_GL_RGBA, + GDK_GL_DOUBLEBUFFER, + GDK_GL_RED_SIZE, 8, + GDK_GL_BLUE_SIZE, 8, + GDK_GL_GREEN_SIZE, 8, + GDK_GL_ALPHA_SIZE, 8, + GDK_GL_DEPTH_SIZE, 1, + GDK_GL_ATTRIB_LIST_NONE, +}; + +int config_rgba_depth16[] = { + GDK_GL_RGBA, + GDK_GL_DOUBLEBUFFER, + GDK_GL_RED_SIZE, 1, + GDK_GL_BLUE_SIZE, 1, + GDK_GL_GREEN_SIZE, 1, + GDK_GL_ALPHA_SIZE, 1, + GDK_GL_DEPTH_SIZE, 16, + GDK_GL_ATTRIB_LIST_NONE, +}; + +int config_rgba_depth[] = { + GDK_GL_RGBA, + GDK_GL_DOUBLEBUFFER, + GDK_GL_RED_SIZE, 1, + GDK_GL_BLUE_SIZE, 1, + GDK_GL_GREEN_SIZE, 1, + GDK_GL_ALPHA_SIZE, 1, + GDK_GL_DEPTH_SIZE, 1, + GDK_GL_ATTRIB_LIST_NONE, +}; + +const attribs_t configs_with_depth[] = +{ + config_rgba32_depth32, + config_rgba32_depth24, + config_rgba32_depth16, + config_rgba32_depth, + config_rgba_depth16, + config_rgba_depth, +}; + +GdkGLConfig* glconfig_new_with_depth() +{ + GdkGLConfig* glconfig = NULL; + + for(configs_iterator i = configs_with_depth, end = configs_with_depth + 6; i != end && glconfig == NULL; ++i) + { + glconfig = gdk_gl_config_new(*i); + } + + if(glconfig == NULL) + { + return gdk_gl_config_new_by_mode((GdkGLConfigMode)(GDK_GL_MODE_RGBA | GDK_GL_MODE_DOUBLE | GDK_GL_MODE_DEPTH)); + } + + return glconfig; +} + +GtkWidget* WINAPI gtk_glwidget_new (gboolean zbuffer, GtkWidget* share) +{ + GtkWidget* drawing_area = gtk_drawing_area_new(); + GdkGLConfig* glconfig = (zbuffer) ? glconfig_new_with_depth() : glconfig_new(); + GdkGLContext* shared_context = (share) ? gtk_widget_get_gl_context(share) : NULL; + + gtk_widget_set_gl_capability (drawing_area, glconfig, shared_context, TRUE, GDK_GL_RGBA_TYPE); + + return drawing_area; +} + +void WINAPI gtk_glwidget_destroy_context (GtkWidget *widget) +{ +} + +void WINAPI gtk_glwidget_create_context (GtkWidget *widget) +{ +} + +void WINAPI gtk_glwidget_swap_buffers (GtkWidget *widget) +{ + GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget); + gdk_gl_drawable_swap_buffers (gldrawable); +} + +gboolean WINAPI gtk_glwidget_make_current (GtkWidget *widget) +{ + GdkGLContext *glcontext = gtk_widget_get_gl_context (widget); + GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget); + return gdk_gl_drawable_gl_begin (gldrawable, glcontext); +} + +GLuint font_list_base; +static gchar font_string[] = "courier 8"; +static gint font_height; + +void gtk_glwidget_create_font (GtkWidget *widget) +{ + GdkGLContext *glcontext = gtk_widget_get_gl_context (widget); + GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget); + + PangoFontDescription *font_desc; + PangoFont *font; + PangoFontMetrics *font_metrics; + + font_list_base = qglGenLists (256); + + font_desc = pango_font_description_from_string (font_string); + + font = gdk_gl_font_use_pango_font (font_desc, 0, 256, font_list_base); + + if(font != NULL) + { + font_metrics = pango_font_get_metrics (font, NULL); + + font_height = pango_font_metrics_get_ascent (font_metrics) + + pango_font_metrics_get_descent (font_metrics); + font_height = PANGO_PIXELS (font_height); + + pango_font_metrics_unref (font_metrics); + } + + pango_font_description_free (font_desc); +} + + +void gtk_glwidget_print_string(const char *s) +{ + qglListBase(font_list_base); + qglCallLists(strlen(s), GL_UNSIGNED_BYTE, (unsigned char *)s); +} + +void gtk_glwidget_print_char(char s) +{ + qglListBase(font_list_base); + qglCallLists(1, GL_UNSIGNED_BYTE, (unsigned char *) &s); +} + diff --git a/radiant/glwindow.cpp b/radiant/glwindow.cpp index 72dbd621..df6b0cf7 100644 --- a/radiant/glwindow.cpp +++ b/radiant/glwindow.cpp @@ -1,287 +1,287 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -// -// GLWindow - Base class for the small views used by Radiant -// -// Leonardo Zide (leo@lokigames.com -// - -#include "stdafx.h" -#include "glwidget.h" -#include "glwindow.h" - -// ============================================================================= -// static functions - -static void realize (GtkWidget *widget, gpointer data) -{ - GLWindow *wnd = (GLWindow*)data; - - wnd->OnCreate (); -} - -static gint expose (GtkWidget *widget, GdkEventExpose *event, gpointer data) -{ - GLWindow *wnd = (GLWindow*)data; - -#ifndef _WIN32 - if (event->count > 0) - return TRUE; -#endif - - if (!g_pParentWnd->IsSleeping ()) - wnd->OnExpose (); - - return TRUE; -} - -static void button_press (GtkWidget *widget, GdkEventButton *event, gpointer data) -{ - GLWindow *wnd = (GLWindow*)data; - guint32 flags = 0; - - gdk_pointer_grab (widget->window, FALSE, - (GdkEventMask)(GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK), - NULL, NULL, GDK_CURRENT_TIME); - - gtk_window_set_focus (GTK_WINDOW (g_pParentWnd->m_pWidget), widget); - - switch (event->button) - { - case 1: flags |= MK_LBUTTON; break; - case 2: flags |= MK_MBUTTON; break; - case 3: flags |= MK_RBUTTON; break; -#if !GTK_CHECK_VERSION (1,3,0) - case 4: wnd->OnMouseWheel(true); break; - case 5: wnd->OnMouseWheel(false); break; -#endif - } - - if ((event->state & GDK_CONTROL_MASK) != 0) - flags |= MK_CONTROL; - - if ((event->state & GDK_SHIFT_MASK) != 0) - flags |= MK_SHIFT; - - if (event->type == GDK_BUTTON_PRESS) - { - switch (event->button) - { - case 1: - wnd->OnLButtonDown (flags, (int)event->x, (int)event->y); break; - case 2: - wnd->OnMButtonDown (flags, (int)event->x, (int)event->y); break; - case 3: - wnd->OnRButtonDown (flags, (int)event->x, (int)event->y); break; - } - } - else if (event->type == GDK_2BUTTON_PRESS) - { - // do nothing - } -} - -static void button_release (GtkWidget *widget, GdkEventButton *event, gpointer data) -{ - GLWindow *wnd = (GLWindow*)data; - guint32 flags = 0; - - gdk_pointer_ungrab (GDK_CURRENT_TIME); - - if ((event->state & GDK_CONTROL_MASK) != 0) - flags |= MK_CONTROL; - - if ((event->state & GDK_SHIFT_MASK) != 0) - flags |= MK_SHIFT; - - switch (event->button) - { - case 1: - wnd->OnLButtonUp (flags, (int)event->x, (int)event->y); break; - case 2: - wnd->OnMButtonUp (flags, (int)event->x, (int)event->y); break; - case 3: - wnd->OnRButtonUp (flags, (int)event->x, (int)event->y); break; - } -} - -static void motion (GtkWidget *widget, GdkEventMotion *event, gpointer data) -{ - GLWindow *wnd = (GLWindow*)data; - guint32 flags = 0; - - if ((event->state & GDK_BUTTON1_MASK) != 0) - flags |= MK_LBUTTON; - - if ((event->state & GDK_BUTTON2_MASK) != 0) - flags |= MK_MBUTTON; - - if ((event->state & GDK_BUTTON3_MASK) != 0) - flags |= MK_RBUTTON; - - if ((event->state & GDK_CONTROL_MASK) != 0) - flags |= MK_CONTROL; - - if ((event->state & GDK_SHIFT_MASK) != 0) - flags |= MK_SHIFT; - - wnd->OnMouseMove (flags, (int)event->x, (int)event->y); -} - -static void resize (GtkWidget *widget, GtkAllocation *allocation, gpointer data) -{ - GLWindow *wnd = (GLWindow*)data; - wnd->OnSize (allocation->width, allocation->height); -} - -static gint timer (gpointer data) -{ - GLWindow *wnd = (GLWindow*)data; - wnd->OnTimer (); - - return TRUE; -} - -//! GtkGLExt port. -/* -static void create_context (GtkWidget *widget, gpointer data) -{ - if (g_qeglobals_gui.d_glBase == NULL) - g_qeglobals_gui.d_glBase = widget; -} - -static void destroy_context (GtkWidget *widget, gpointer data) -{ - if (g_qeglobals_gui.d_glBase == widget) - g_qeglobals_gui.d_glBase = NULL; -} -*/ - -#if GTK_CHECK_VERSION (1,3,0) -static gint scroll_event( GtkWidget *widget, - GdkEventScroll *event, - gpointer data ) -{ - GLWindow *wnd = (GLWindow*)data; - wnd->OnMouseWheel((event->direction == GDK_SCROLL_UP) ? true : false); - return TRUE; -} -#endif - -// ============================================================================= -// GLWindow class - -#ifdef _DEBUG -//#define DBG_GLWINDOW -#endif - -GLWindow::GLWindow (bool zbuffer) -{ - m_nTimer = 0; - m_bMouseCapture = FALSE; - m_pParent = NULL; - - m_pWidget = gtk_glwidget_new (zbuffer, g_qeglobals_gui.d_glBase); - GTK_WIDGET_SET_FLAGS (m_pWidget, GTK_CAN_FOCUS); - -#ifdef DBG_GLWINDOW - Sys_Printf("GLWindow::GLWindow m_pWidget = %p\n", m_pWidget); -#endif - -//! GtkGLExt port. -//#if defined (__linux__) || defined (__APPLE__) - if (g_qeglobals_gui.d_glBase == NULL) - g_qeglobals_gui.d_glBase = m_pWidget; -//#endif - -#if GTK_CHECK_VERSION (1,3,0) - gtk_widget_set_events (m_pWidget, GDK_DESTROY | GDK_EXPOSURE_MASK | - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK); -#else - gtk_widget_set_events (m_pWidget, GDK_DESTROY | GDK_EXPOSURE_MASK | - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK); -#endif - - // Connect signal handlers - gtk_signal_connect (GTK_OBJECT (m_pWidget), "realize", GTK_SIGNAL_FUNC (realize), this); - gtk_signal_connect (GTK_OBJECT (m_pWidget), "expose_event", GTK_SIGNAL_FUNC (expose), this); - gtk_signal_connect (GTK_OBJECT (m_pWidget), "motion_notify_event", GTK_SIGNAL_FUNC (motion), this); - gtk_signal_connect (GTK_OBJECT (m_pWidget), "button_press_event", GTK_SIGNAL_FUNC (button_press), this); - gtk_signal_connect (GTK_OBJECT (m_pWidget), "button_release_event",GTK_SIGNAL_FUNC (button_release), this); - gtk_signal_connect (GTK_OBJECT (m_pWidget), "size_allocate", GTK_SIGNAL_FUNC (resize), this); -//! GtkGLExt port. -// gtk_signal_connect (GTK_OBJECT (m_pWidget), "create_context", GTK_SIGNAL_FUNC (create_context), this); -// gtk_signal_connect (GTK_OBJECT (m_pWidget), "destroy_context", GTK_SIGNAL_FUNC (destroy_context), this); -#if GTK_CHECK_VERSION (1,3,0) - gtk_signal_connect (GTK_OBJECT (m_pWidget), "scroll_event", GTK_SIGNAL_FUNC (scroll_event), this); -#endif -} - -GLWindow::~GLWindow () -{ -#ifdef DBG_GLWINDOW - Sys_Printf("GLWindow::~GLWindow m_pWidget = %p\n", m_pWidget); -#endif - - if (m_pWidget && GTK_IS_WIDGET (m_pWidget)) - gtk_widget_destroy (m_pWidget); -} - -void GLWindow::DestroyContext () -{ - gtk_glwidget_destroy_context (m_pWidget); -} - -void GLWindow::CreateContext () -{ - gtk_glwidget_create_context (m_pWidget); -} - -void GLWindow::SetTimer (guint millisec) -{ - m_nTimer = gtk_timeout_add (millisec, timer, this); -} - -void GLWindow::KillTimer () -{ - gtk_timeout_remove (m_nTimer); - m_nTimer = 0; -} - -bool GLWindow::MakeCurrent () -{ - return gtk_glwidget_make_current (m_pWidget); -} - -void GLWindow::SwapBuffers () -{ - gtk_glwidget_swap_buffers (m_pWidget); -} +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// +// GLWindow - Base class for the small views used by Radiant +// +// Leonardo Zide (leo@lokigames.com +// + +#include "stdafx.h" +#include "glwidget.h" +#include "glwindow.h" + +// ============================================================================= +// static functions + +static void realize (GtkWidget *widget, gpointer data) +{ + GLWindow *wnd = (GLWindow*)data; + + wnd->OnCreate (); +} + +static gint expose (GtkWidget *widget, GdkEventExpose *event, gpointer data) +{ + GLWindow *wnd = (GLWindow*)data; + +#ifndef _WIN32 + if (event->count > 0) + return TRUE; +#endif + + if (!g_pParentWnd->IsSleeping ()) + wnd->OnExpose (); + + return TRUE; +} + +static void button_press (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + GLWindow *wnd = (GLWindow*)data; + guint32 flags = 0; + + gdk_pointer_grab (widget->window, FALSE, + (GdkEventMask)(GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK), + NULL, NULL, GDK_CURRENT_TIME); + + gtk_window_set_focus (GTK_WINDOW (g_pParentWnd->m_pWidget), widget); + + switch (event->button) + { + case 1: flags |= MK_LBUTTON; break; + case 2: flags |= MK_MBUTTON; break; + case 3: flags |= MK_RBUTTON; break; +#if !GTK_CHECK_VERSION (1,3,0) + case 4: wnd->OnMouseWheel(true); break; + case 5: wnd->OnMouseWheel(false); break; +#endif + } + + if ((event->state & GDK_CONTROL_MASK) != 0) + flags |= MK_CONTROL; + + if ((event->state & GDK_SHIFT_MASK) != 0) + flags |= MK_SHIFT; + + if (event->type == GDK_BUTTON_PRESS) + { + switch (event->button) + { + case 1: + wnd->OnLButtonDown (flags, (int)event->x, (int)event->y); break; + case 2: + wnd->OnMButtonDown (flags, (int)event->x, (int)event->y); break; + case 3: + wnd->OnRButtonDown (flags, (int)event->x, (int)event->y); break; + } + } + else if (event->type == GDK_2BUTTON_PRESS) + { + // do nothing + } +} + +static void button_release (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + GLWindow *wnd = (GLWindow*)data; + guint32 flags = 0; + + gdk_pointer_ungrab (GDK_CURRENT_TIME); + + if ((event->state & GDK_CONTROL_MASK) != 0) + flags |= MK_CONTROL; + + if ((event->state & GDK_SHIFT_MASK) != 0) + flags |= MK_SHIFT; + + switch (event->button) + { + case 1: + wnd->OnLButtonUp (flags, (int)event->x, (int)event->y); break; + case 2: + wnd->OnMButtonUp (flags, (int)event->x, (int)event->y); break; + case 3: + wnd->OnRButtonUp (flags, (int)event->x, (int)event->y); break; + } +} + +static void motion (GtkWidget *widget, GdkEventMotion *event, gpointer data) +{ + GLWindow *wnd = (GLWindow*)data; + guint32 flags = 0; + + if ((event->state & GDK_BUTTON1_MASK) != 0) + flags |= MK_LBUTTON; + + if ((event->state & GDK_BUTTON2_MASK) != 0) + flags |= MK_MBUTTON; + + if ((event->state & GDK_BUTTON3_MASK) != 0) + flags |= MK_RBUTTON; + + if ((event->state & GDK_CONTROL_MASK) != 0) + flags |= MK_CONTROL; + + if ((event->state & GDK_SHIFT_MASK) != 0) + flags |= MK_SHIFT; + + wnd->OnMouseMove (flags, (int)event->x, (int)event->y); +} + +static void resize (GtkWidget *widget, GtkAllocation *allocation, gpointer data) +{ + GLWindow *wnd = (GLWindow*)data; + wnd->OnSize (allocation->width, allocation->height); +} + +static gint timer (gpointer data) +{ + GLWindow *wnd = (GLWindow*)data; + wnd->OnTimer (); + + return TRUE; +} + +//! GtkGLExt port. +/* +static void create_context (GtkWidget *widget, gpointer data) +{ + if (g_qeglobals_gui.d_glBase == NULL) + g_qeglobals_gui.d_glBase = widget; +} + +static void destroy_context (GtkWidget *widget, gpointer data) +{ + if (g_qeglobals_gui.d_glBase == widget) + g_qeglobals_gui.d_glBase = NULL; +} +*/ + +#if GTK_CHECK_VERSION (1,3,0) +static gint scroll_event( GtkWidget *widget, + GdkEventScroll *event, + gpointer data ) +{ + GLWindow *wnd = (GLWindow*)data; + wnd->OnMouseWheel((event->direction == GDK_SCROLL_UP) ? true : false); + return TRUE; +} +#endif + +// ============================================================================= +// GLWindow class + +#ifdef _DEBUG +//#define DBG_GLWINDOW +#endif + +GLWindow::GLWindow (bool zbuffer) +{ + m_nTimer = 0; + m_bMouseCapture = FALSE; + m_pParent = NULL; + + m_pWidget = gtk_glwidget_new (zbuffer, g_qeglobals_gui.d_glBase); + GTK_WIDGET_SET_FLAGS (m_pWidget, GTK_CAN_FOCUS); + +#ifdef DBG_GLWINDOW + Sys_Printf("GLWindow::GLWindow m_pWidget = %p\n", m_pWidget); +#endif + +//! GtkGLExt port. +//#if defined (__linux__) || defined (__APPLE__) + if (g_qeglobals_gui.d_glBase == NULL) + g_qeglobals_gui.d_glBase = m_pWidget; +//#endif + +#if GTK_CHECK_VERSION (1,3,0) + gtk_widget_set_events (m_pWidget, GDK_DESTROY | GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK); +#else + gtk_widget_set_events (m_pWidget, GDK_DESTROY | GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK); +#endif + + // Connect signal handlers + gtk_signal_connect (GTK_OBJECT (m_pWidget), "realize", GTK_SIGNAL_FUNC (realize), this); + gtk_signal_connect (GTK_OBJECT (m_pWidget), "expose_event", GTK_SIGNAL_FUNC (expose), this); + gtk_signal_connect (GTK_OBJECT (m_pWidget), "motion_notify_event", GTK_SIGNAL_FUNC (motion), this); + gtk_signal_connect (GTK_OBJECT (m_pWidget), "button_press_event", GTK_SIGNAL_FUNC (button_press), this); + gtk_signal_connect (GTK_OBJECT (m_pWidget), "button_release_event",GTK_SIGNAL_FUNC (button_release), this); + gtk_signal_connect (GTK_OBJECT (m_pWidget), "size_allocate", GTK_SIGNAL_FUNC (resize), this); +//! GtkGLExt port. +// gtk_signal_connect (GTK_OBJECT (m_pWidget), "create_context", GTK_SIGNAL_FUNC (create_context), this); +// gtk_signal_connect (GTK_OBJECT (m_pWidget), "destroy_context", GTK_SIGNAL_FUNC (destroy_context), this); +#if GTK_CHECK_VERSION (1,3,0) + gtk_signal_connect (GTK_OBJECT (m_pWidget), "scroll_event", GTK_SIGNAL_FUNC (scroll_event), this); +#endif +} + +GLWindow::~GLWindow () +{ +#ifdef DBG_GLWINDOW + Sys_Printf("GLWindow::~GLWindow m_pWidget = %p\n", m_pWidget); +#endif + + if (m_pWidget && GTK_IS_WIDGET (m_pWidget)) + gtk_widget_destroy (m_pWidget); +} + +void GLWindow::DestroyContext () +{ + gtk_glwidget_destroy_context (m_pWidget); +} + +void GLWindow::CreateContext () +{ + gtk_glwidget_create_context (m_pWidget); +} + +void GLWindow::SetTimer (guint millisec) +{ + m_nTimer = gtk_timeout_add (millisec, timer, this); +} + +void GLWindow::KillTimer () +{ + gtk_timeout_remove (m_nTimer); + m_nTimer = 0; +} + +bool GLWindow::MakeCurrent () +{ + return gtk_glwidget_make_current (m_pWidget); +} + +void GLWindow::SwapBuffers () +{ + gtk_glwidget_swap_buffers (m_pWidget); +} diff --git a/radiant/groupdialog.cpp b/radiant/groupdialog.cpp index 7fac4b89..d4570ff0 100644 --- a/radiant/groupdialog.cpp +++ b/radiant/groupdialog.cpp @@ -1,1713 +1,1713 @@ -/* -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 -*/ - -// -// Floating dialog that contains a notebook with at least Entities and Group tabs -// I merged the 2 MS Windows dialogs in a single class -// -// Leonardo Zide (leo@lokigames.com) -// - -#ifndef _WIN32 - #include -#endif -#include -#include "stdafx.h" -#include "groupdialog.h" - -GtkWidget* EntWidgets[EntLast]; -GtkListStore* g_entlist_store; -GtkListStore* g_entprops_store; -int inspector_mode; // W_TEXTURE, W_ENTITY, or W_CONSOLE -qboolean multiple_entities; -// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=17 -qboolean disable_spawn_get = false; -entity_t *edit_entity; -/* -static GdkPixmap *tree_pixmaps[7]; -static GdkBitmap *tree_masks[7]; -*/ -#define IMG_PATCH 0 -#define IMG_BRUSH 1 -#define IMG_GROUP 2 -#define IMG_ENTITY 3 -#define IMG_ENTITYGROUP 4 -#define IMG_MODEL 5 -#define IMG_SCRIPT 6 - -// misc group support -#define MAX_GROUPS 4096 -#define GROUP_DELIMETER '@' -#define GROUPNAME "QER_Group_%i" - -GroupDlg g_wndGroup; -GroupDlg *g_pGroupDlg = &g_wndGroup; - -// group_t are loaded / saved through "group_info" entities -// they hold epairs for group settings and additionnal access info (tree nodes) -group_t *g_pGroups = NULL; - -// the number of active spawnflags -static int spawnflag_count; -// table: index, match spawnflag item to the spawnflag index (i.e. which bit) -static int spawn_table[MAX_FLAGS]; -// we change the layout depending on how many spawn flags we need to display -// the table is a 4x4 in which we need to put the comment box EntWidgets[EntComment] and the spawn flags.. -static GtkWidget *LayoutTable; -// 0: none of them are hooked -// 1: only the text, 2: text and four checks, 3: text and 8 checks -static int widget_state = 0; - -static void entity_check (GtkWidget *widget, gpointer data); - -// ============================================================================= -// Global functions - -/* -=============================================================== - -ENTITY WINDOW - -=============================================================== -*/ - -void FillClassList () -{ - GtkListStore* store = g_entlist_store; - - gtk_list_store_clear(store); - - for (eclass_t* e = eclass ; e ; e = e->next) - { - GtkTreeIter iter; - gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, 0, e->name, 1, e, -1); - } -} - -// SetKeyValuePairs -// -// Reset the key/value (aka property) listbox and fill it with the -// k/v pairs from the entity being edited. -// - -void SetKeyValuePairs (bool bClearMD3) -{ - GtkListStore* store = g_entprops_store; - - gtk_list_store_clear(store); - - if (edit_entity == NULL) - { - // if there's no entity, then display no key/values - return; - } - - // save current key/val pair around filling epair box - // row_select wipes it and sets to first in list - Str strKey = gtk_entry_get_text (GTK_ENTRY (EntWidgets[EntKeyField])); - Str strVal = gtk_entry_get_text (GTK_ENTRY (EntWidgets[EntValueField])); - - - // Walk through list and add pairs - for(epair_t* epair = edit_entity->epairs ; epair ; epair = epair->next) - { - GtkTreeIter iter; - gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, 0, epair->key, 1, epair->value, -1); - } - - gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntKeyField]), strKey.GetBuffer()); - gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntValueField]), strVal.GetBuffer()); - - Sys_UpdateWindows(W_CAMERA | W_XY); -} - -// SetSpawnFlags -// -// Update the checkboxes to reflect the flag state of the entity -// -void SetSpawnFlags(void) -{ - int f, i, v; - - disable_spawn_get = true; - - f = atoi(ValueForKey (edit_entity, "spawnflags")); - for (i=0 ; inext) - DeleteKey (b->owner, "spawnflags"); - } - else - DeleteKey (edit_entity, "spawnflags"); - } - else - { - sprintf (sz, "%i", f); - if (multiple_entities) - { - brush_t *b; - - for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - SetKeyValue(b->owner, "spawnflags", sz); - } - else - SetKeyValue (edit_entity, "spawnflags", sz); - } - SetKeyValuePairs (); -} - -//#define DBG_UPDATESEL - -// UpdateSel -// -// Update the listbox, checkboxes and k/v pairs to reflect the new selection -// iIndex is the index in the list box with the class name, -1 if not found -bool UpdateSel(int iIndex, eclass_t *pec) -{ - int i, next_state; - brush_t *b; - - // syndrom of crappy code, we may get into stack overflowing crap with this function and Gtk - // if we play with the list of entity classes - // using a static flag to prevent recursion - static bool bBlockUpdate = false; - - if (bBlockUpdate) - return FALSE; // NOTE TTimo wtf is the return value for anyway? - -#ifdef DBG_UPDATESEL - Sys_FPrintf(SYS_WRN, "UpdateSel\n"); -#endif - - if (selected_brushes.next == &selected_brushes) - { - edit_entity = world_entity; - multiple_entities = false; - } - else - { - edit_entity = selected_brushes.next->owner; - for (b=selected_brushes.next->next ; b != &selected_brushes ; b=b->next) - { - if (b->owner != edit_entity) - { - multiple_entities = true; - break; - } - } - } - - if (iIndex != -1) - { -#ifdef DBG_UPDATESEL - Sys_FPrintf(SYS_WRN,"Setting focus_row to %d\n", iIndex); -#endif - bBlockUpdate = true; - - GtkTreeView* view = GTK_TREE_VIEW(EntWidgets[EntList]); - GtkTreePath* path = gtk_tree_path_new(); - gtk_tree_path_append_index(path, iIndex); - gtk_tree_selection_select_path(gtk_tree_view_get_selection(view), path); - gtk_tree_view_scroll_to_cell(view, path, NULL, FALSE, 0, 0); - gtk_tree_path_free(path); - - bBlockUpdate = false; - } - - if (pec == NULL) - return TRUE; - - // Set up the description - { - GtkTextBuffer* buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(EntWidgets[EntComment])); - gtk_text_buffer_set_text (buffer, pec->comments, -1); - } - - spawnflag_count = 0; - - // do a first pass to count the spawn flags, don't touch the widgets, we don't know in what state they are - for (i=0 ; iflagnames[i] && pec->flagnames[i][0] != 0 && strcmp(pec->flagnames[i],"-")) - { - spawn_table[spawnflag_count] = i; - spawnflag_count++; - } - } - - // what's new widget state - if (spawnflag_count==0) - next_state = 1; - else if (spawnflag_count<=4) - next_state = 2; - else if (spawnflag_count<=8) - next_state = 3; - else if (spawnflag_count<=12) - next_state = 4; - else - next_state = 5; - widget_state = next_state; - static int last_count = 0; - - // disable all remaining boxes - // NOTE: these boxes might not even be on display - for (i = 0; i < last_count; i++) - { - GtkWidget* widget = EntWidgets[EntCheck1+i]; - gtk_label_set_text (GTK_LABEL (GTK_BIN (widget)->child), " "); - gtk_widget_hide (widget); - gtk_widget_ref (widget); - gtk_container_remove (GTK_CONTAINER (LayoutTable), widget); - } - last_count = spawnflag_count; - - for (i=0 ; iflagnames[spawn_table[i]]; - str.MakeLower (); - -// gtk_table_attach (GTK_TABLE (LayoutTable), widget, i%4, i%4+1, i/4, i/4+1, - gtk_table_attach (GTK_TABLE (LayoutTable), widget, i%4, i%4+1, i/4, i/4+1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - gtk_widget_unref (widget); - - gtk_label_set_text (GTK_LABEL (GTK_BIN (widget)->child), str.GetBuffer ()); - } - - SetSpawnFlags(); - - SetKeyValuePairs(); - - return TRUE; -} - -bool UpdateEntitySel(eclass_t *pec) -{ -#ifdef DBG_UPDATESEL - Sys_FPrintf(SYS_WRN, "UpdateEntitySel\n"); -#endif - - GtkTreeModel* model = GTK_TREE_MODEL(g_entlist_store); - GtkTreeIter iter; - unsigned int i = 0; - for(gboolean good = gtk_tree_model_get_iter_first(model, &iter); good != FALSE; good = gtk_tree_model_iter_next(model, &iter)) - { - char* text; - gtk_tree_model_get(model, &iter, 0, &text, -1); - if (strcmp (text, pec->name) == 0) - { -#ifdef DBG_UPDATESEL - Sys_FPrintf(SYS_WRN, "found a match: %d %s\n", i, pec->name); -#endif - return UpdateSel (i, pec); - } - g_free(text); - ++i; - } - return UpdateSel (-1, pec); -} - -// CreateEntity -// -// Creates a new entity based on the currently selected brush and entity type. -// - -void CreateEntity(void) -{ - GtkTreeView* view = GTK_TREE_VIEW(EntWidgets[EntList]); - - // check to make sure we have a brush - if (selected_brushes.next == &selected_brushes) - { - gtk_MessageBox(g_pParentWnd->m_pWidget, "You must have a selected brush to create an entity", "info"); - return; - } - - // find out what type of entity we are trying to create - GtkTreeModel* model; - GtkTreeIter iter; - if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(view), &model, &iter) == FALSE) - { - gtk_MessageBox (g_pParentWnd->m_pWidget, "You must have a selected class to create an entity", "info"); - return; - } - - char* text; - gtk_tree_model_get(model, &iter, 0, &text, -1); - CreateEntityFromName(text, vec3_origin); - g_free(text); - - if (selected_brushes.next == &selected_brushes) - edit_entity = world_entity; - else - edit_entity = selected_brushes.next->owner; - - SetKeyValuePairs(); - Select_Deselect (); - Select_Brush (edit_entity->brushes.onext); - Sys_UpdateWindows(W_ALL); -} - -/* -=============== -AddProp - -=============== -*/ -void AddProp() -{ - if (edit_entity == NULL) - return; - - // Get current selection text - const char* key = gtk_entry_get_text (GTK_ENTRY (EntWidgets[EntKeyField])); - const char* value = gtk_entry_get_text (GTK_ENTRY (EntWidgets[EntValueField])); - - - // TTimo: if you change the classname to worldspawn you won't merge back in the structural brushes but create a parasite entity - if (!strcmp(key, "classname") && !strcmp(value, "worldspawn")) - { - gtk_MessageBox(g_pParentWnd->m_pWidget, "Cannot change \"classname\" key back to worldspawn.", NULL, MB_OK ); - return; - } - - - // RR2DO2: we don't want spaces in entity keys - if (strstr( key, " " )) - { - gtk_MessageBox(g_pParentWnd->m_pWidget, "No spaces are allowed in entity keys.", NULL, MB_OK ); - return; - } - - if (multiple_entities) - { - brush_t *b; - - for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - SetKeyValue(b->owner, key, value); - } - else - SetKeyValue(edit_entity, key, value); - - // refresh the prop listbox - SetKeyValuePairs(); - - -#ifdef USEPLUGINENTITIES - // if it's a plugin entity, perhaps we need to update some drawing parameters - // NOTE: perhaps moving this code to a seperate func would help if we need it in other places - // TODO: we need to call some update func in the IPluginEntity in case model name changes etc. - // ( for the moment only bounding brush is updated ), see UpdateModelBrush in Ritual's Q3Radiant - if (edit_entity->eclass->nShowFlags & ECLASS_PLUGINENTITY) - { - vec3_t mins, maxs; - edit_entity->pPlugEnt->GetBounds( mins, maxs ); - // replace old bounding brush by newly computed one - // NOTE: this part is similar to Entity_BuildModelBrush in Ritual's Q3Radiant, it can be - // usefull moved into a seperate func - brush_t *b,*oldbrush; - if (edit_entity->brushes.onext != &edit_entity->brushes) - oldbrush = edit_entity->brushes.onext; - b = Brush_Create (mins, maxs, &edit_entity->eclass->texdef); - Entity_LinkBrush (edit_entity, b); - Brush_Build( b, true ); - Select_Deselect(); - Brush_AddToList (edit_entity->brushes.onext, &selected_brushes); - if (oldbrush) - Brush_Free( oldbrush ); - } -#endif // USEPLUGINENTITIES -} - -/* -=============== -DelProp - -=============== -*/ -void DelProp(void) -{ - if (edit_entity == NULL) - return; - - // Get current selection text - const char* key = gtk_entry_get_text (GTK_ENTRY (EntWidgets[EntKeyField])); - - if (multiple_entities) - { - brush_t *b; - - for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - DeleteKey(b->owner, key); - } - else - DeleteKey(edit_entity, key); - - // refresh the prop listbox - SetKeyValuePairs(); -} - -void ResetEntity () -{ - epair_t *pep; - int i; - - if (edit_entity == NULL) - return; - - if (multiple_entities) - { - brush_t *b; - - for (b=selected_brushes.next; b != &selected_brushes; b=b->next) - for (pep = b->owner->epairs; pep; ) - { - if (strcmp (pep->key, "classname") != 0) - { - DeleteKey (b->owner, pep->key); - pep = b->owner->epairs; - } - else - pep = pep->next; - } - } - else - for (pep = edit_entity->epairs; pep; ) - { - if (strcmp (pep->key, "classname") != 0) - { - DeleteKey (edit_entity, pep->key); - pep = edit_entity->epairs; - } - else - pep = pep->next; - } - - // refresh the dialog - SetKeyValuePairs (); - for (i = EntCheck1; i <= EntCheck16; i++) - gtk_signal_handler_block_by_func (GTK_OBJECT (EntWidgets[i]), GTK_SIGNAL_FUNC (entity_check), NULL); - SetSpawnFlags (); - for (i = EntCheck1; i <= EntCheck16; i++) - gtk_signal_handler_unblock_by_func (GTK_OBJECT (EntWidgets[i]), GTK_SIGNAL_FUNC (entity_check), NULL); -} - -bool GetSelectAllCriteria(CString &strKey, CString &strVal) -{ - GtkTreeModel* model; - GtkTreeIter iter; - if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(EntWidgets[EntProps])), &model, &iter) - && (inspector_mode == W_ENTITY) - && GTK_WIDGET_VISIBLE (g_pGroupDlg->m_pWidget)) - { - strKey = gtk_entry_get_text (GTK_ENTRY (EntWidgets[EntKeyField])); - strVal = gtk_entry_get_text (GTK_ENTRY (EntWidgets[EntValueField])); - return TRUE; - } - return FALSE; -} - - -void AssignSound() -{ - char buffer[NAME_MAX]; - - strcpy (buffer, g_qeglobals.m_strHomeMaps.GetBuffer()); - strcat (buffer, "sound/"); - - if( access(buffer, R_OK) != 0 ) - { - // just go to fsmain - strcpy (buffer, g_qeglobals.m_strHomeMaps.GetBuffer()); - strcat (buffer, "/"); - } - - const char *filename = file_dialog (g_pGroupDlg->m_pWidget, TRUE, "Open Wav File", buffer, "sound"); - if (filename != NULL) - { - gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntKeyField]), "noise"); - char *aux = vfsExtractRelativePath (filename); - CString str; - if (aux) - str = aux; - else - { - Sys_FPrintf (SYS_WRN, "WARNING: could not extract the relative path, using full path instead\n"); - str = filename; - } - - gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntValueField]), str.GetBuffer()); - AddProp(); - } -} - -void AssignModel() -{ - char buffer[NAME_MAX]; - - strcpy (buffer, g_qeglobals.m_strHomeMaps.GetBuffer()); - strcat (buffer, "models/"); - - if( access(buffer, R_OK) != 0 ) - { - // just go to fsmain - strcpy (buffer, g_qeglobals.m_strHomeMaps.GetBuffer()); - strcat (buffer, "/"); - } - - const char *filename = file_dialog (g_pGroupDlg->m_pWidget, TRUE, "Open Model", buffer, MODEL_MAJOR); - if (filename != NULL) - { - gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntKeyField]), "model"); - // use VFS to get the correct relative path - char *aux = vfsExtractRelativePath (filename); - CString str; - if (aux) - str = aux; - else - { - Sys_FPrintf (SYS_WRN, "WARNING: could not extract the relative path, using full path instead\n"); - str = filename; - } - - gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntValueField]), str.GetBuffer()); - AddProp(); - edit_entity->brushes.onext->bModelFailed = false; - } -} - -/* -============== -SetInspectorMode -============== -*/ -void SetInspectorMode(int iType) -{ - if (iType == W_GROUP) - gtk_MessageBox(g_pParentWnd->m_pWidget, "Brush grouping is not functional yet", NULL, MB_OK | MB_ICONWARNING ); - - if (!g_pParentWnd->FloatingGroupDialog() && - (iType == W_TEXTURE || iType == W_CONSOLE)) - return; - - // Is the caller asking us to cycle to the next window? - if (iType == -1) - { - if (inspector_mode == W_ENTITY) - iType = W_TEXTURE; - else if (inspector_mode == W_TEXTURE) - iType = W_CONSOLE; - else if (inspector_mode == W_CONSOLE) - iType = W_GROUP; - else - iType = W_ENTITY; - } - - switch(iType) - { - case W_ENTITY: - // entity is always first in the inspector - gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_entity), "Entities"); - gtk_notebook_set_page (GTK_NOTEBOOK (g_pGroupDlg->m_pNotebook), 0); - break; - - case W_TEXTURE: - g_pParentWnd->GetTexWnd()->FocusEdit(); - gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_entity), "Textures"); - if (g_pParentWnd->FloatingGroupDialog()) - gtk_notebook_set_page (GTK_NOTEBOOK (g_pGroupDlg->m_pNotebook), 1); - break; - - case W_CONSOLE: - gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_entity), "Console"); - if (g_pParentWnd->FloatingGroupDialog()) - gtk_notebook_set_page (GTK_NOTEBOOK (g_pGroupDlg->m_pNotebook), 2); - break; - - case W_GROUP: - if (g_pParentWnd->FloatingGroupDialog()) - gtk_notebook_set_page (GTK_NOTEBOOK (g_pGroupDlg->m_pNotebook), 3); - else - gtk_notebook_set_page (GTK_NOTEBOOK (g_pGroupDlg->m_pNotebook), 1); - break; - - default: - break; - } -} - -void Group_Add(entity_t *e) -{ - /* - group_t *g = (group_t*)qmalloc(sizeof(group_t)); - g->epairs = e->epairs; - g->next = NULL; - e->epairs = NULL; - - // create a new group node - char *text = ValueForKey(g->epairs, "group"); - g->itemOwner = gtk_ctree_insert_node (GTK_CTREE (g_wndGroup.m_pTree), g_wndGroup.m_hWorld, NULL, &text, 0, - tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP], - tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP], TRUE, TRUE); - g->next = g_pGroups; - g_pGroups = g; - */ -} -/* -group_t* Group_Alloc(char *name) -{ - group_t *g = (group_t*)qmalloc(sizeof(group_t)); - SetKeyValue( g->epairs, "group", name ); - return g; -} - -group_t* Group_ForName(const char * name) -{ - group_t *g = g_pGroups; - while (g != NULL) - { - if (strcmp( ValueForKey(g->epairs,"group"), name ) == 0) - break; - g = g->next; - } - return g; -} - -void Group_AddToItem(brush_t *b, GtkCTreeNode* item) -{ - int nImage = IMG_BRUSH; - if (!g_qeglobals.m_bBrushPrimitMode) - { - return; - } - const char *pName = NULL; - // const char *pNamed = Brush_GetKeyValue(b, "name"); - - if (!b->owner || (b->owner == world_entity)) - { - if (b->patchBrush) - { - pName = "Generic Patch"; - nImage = IMG_PATCH; - } - else - { - pName = "Generic Brush"; - nImage = IMG_BRUSH; - } - } - else - { - pName = b->owner->eclass->name; - if (b->owner->eclass->fixedsize) - { - nImage = IMG_ENTITY; - } - else - { - nImage = IMG_ENTITYGROUP; - } - } - - GtkCTreeNode *newItem; - int i = (b->patchBrush) ? IMG_PATCH : IMG_BRUSH; - newItem = gtk_ctree_insert_node (GTK_CTREE (g_wndGroup.m_pTree), item, NULL, (gchar**)&pName, 0, - tree_pixmaps[i], tree_masks[i], tree_pixmaps[i], - tree_masks[i], TRUE, TRUE); - gtk_ctree_node_set_row_data (GTK_CTREE (g_wndGroup.m_pTree), newItem, b); - b->itemOwner = newItem; -} -*/ -void Group_RemoveBrush(brush_t *b) -{ - /* - if (!g_qeglobals.m_bBrushPrimitMode) - { - return; - } - if (b->itemOwner) - { - gtk_ctree_remove_node (GTK_CTREE (g_pGroupDlg->m_pTree), b->itemOwner); - b->itemOwner = NULL; - } - DeleteKey(b->epairs, "group"); - */ -} -/* -void Group_AddToWorld(brush_t *b) -{ - if (!g_qeglobals.m_bBrushPrimitMode) - { - return; - } - GtkCTreeNode *parent = gtk_ctree_node_nth (GTK_CTREE (g_pGroupDlg->m_pTree), 0); - Group_AddToItem(b, parent); -} -*/ -void Group_AddToProperGroup(brush_t *b) -{ - /* - if (!g_qeglobals.m_bBrushPrimitMode) - { - return; - } - - // NOTE: we do a local copy of the "group" key because it gets erased by Group_RemoveBrush - const char *pGroup = Brush_GetKeyValue(b, "group"); - // remove the entry in the tree if there's one - if (b->itemOwner) - { - gtk_ctree_remove_node (GTK_CTREE (g_pGroupDlg->m_pTree), b->itemOwner); - b->itemOwner = NULL; - } - - if (*pGroup != 0) - { - // find the item - group_t *g = Group_ForName(pGroup); - if (g) - Group_AddToItem(b, g->itemOwner); -#ifdef _DEBUG - else - Sys_Printf("WARNING: unexpected Group_ForName not found in Group_AddToProperGroup\n"); -#endif - } - else - { - Group_AddToWorld(b); - } - */ -} -/* -void Group_AddToSelected(brush_t *b) -{ - if (!g_qeglobals.m_bBrushPrimitMode) - { - return; - } - GtkCTreeNode *item; - item = gtk_ctree_node_nth (GTK_CTREE (g_pGroupDlg->m_pTree), GTK_CLIST (g_pGroupDlg->m_pTree)->focus_row); - if (item == NULL) - { - item = gtk_ctree_node_nth (GTK_CTREE (g_pGroupDlg->m_pTree), 0); - } - Group_AddToItem(b, item); -} -*/ -/* -void Group_Save(FILE *f) -{ - group_t *g = g_pGroups; - while (g) - { - fprintf(f,"{\n\"classname\" \"group_info\"\n\"group\" \"%s\"\n}\n", ValueForKey( g->epairs, "group" )); - g = g->next; - } -} -*/ - -void Group_Init() -{ - if (!g_qeglobals.m_bBrushPrimitMode) - { - return; - } - // start by cleaning everything - // clean the groups - //++timo FIXME: we leak, delete the groups on the way (I don't have time to do it now) -#ifdef _DEBUG - Sys_Printf("TODO: fix leak in Group_Init\n"); -#endif - group_t *g = g_pGroups; - while (g) - { - epair_t *ep,*enext; - for (ep = g->epairs ; ep ; ep=enext ) - { - enext = ep->next; - free (ep->key); - free (ep->value); - free (ep); - } - g = g->next; - } - /* - GtkCTreeNode *world; - char *text = "World"; - g_pGroups = NULL; - gtk_clist_clear (GTK_CLIST (g_wndGroup.m_pTree)); - world = gtk_ctree_insert_node (GTK_CTREE (g_wndGroup.m_pTree), NULL, NULL, &text, 0, - tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP], tree_pixmaps[IMG_GROUP], - tree_masks[IMG_GROUP], FALSE, TRUE); - */ - // walk through all the brushes, remove the itemOwner key and add them back where they belong - brush_t *b; - for (b = active_brushes.next; b != &active_brushes; b = b->next) - { - b->itemOwner = NULL; - Group_AddToProperGroup(b); - } - for (b = selected_brushes.next ; b != &selected_brushes ; b = b->next) - { - b->itemOwner = NULL; - Group_AddToProperGroup(b); - } -} -/* -// scan through world_entity for groups in this map? -// we use GROUPNAME "QER_group_%i" to look for existing groups and their naming -//++timo FIXME: is this actually needed for anything? -void Group_GetListFromWorld(GSList **pArray) -{ - if (!g_qeglobals.m_bBrushPrimitMode) - { - return; - } - - if (world_entity == NULL) - { - return; - } - - char cBuff[1024]; - for (int i =0; i < MAX_GROUPS; i++) - { - sprintf(cBuff, GROUPNAME, i); - char *pGroup = ValueForKey(world_entity, cBuff); - if (pGroup && strlen(pGroup) > 0) - { - *pArray = g_slist_append (*pArray, g_strdup (pGroup)); - } - else - { - break; - } - } -} - -void Group_RemoveListFromWorld() -{ - if (!g_qeglobals.m_bBrushPrimitMode) - { - return; - } - GSList* array = NULL; - Group_GetListFromWorld(&array); - - while (array) - { - DeleteKey(world_entity, (char*)array->data); - g_free (array->data); - array = g_slist_remove (array, array->data); - } -} - -int CountChar(const char *p, char c) -{ - int nCount = 0; - int nLen = strlen(p)-1; - while (nLen-- >= 0) - { - if (p[nLen] == c) - { - nCount++; - } - } - return nCount; -} -*/ -// ============================================================================= -// callbacks - -static void eclasslist_selection_changed(GtkTreeSelection* selection, gpointer data) -{ - GtkTreeModel* model; - GtkTreeIter selected; - // no world entity, we are not ready yet - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=917 - if( !world_entity ) { - return; - } - if(gtk_tree_selection_get_selected(selection, &model, &selected)) - { - eclass_t* eclass; - gtk_tree_model_get(model, &selected, 1, &eclass, -1); - if(eclass != NULL) - { - GtkTreePath* path = gtk_tree_model_get_path(model, &selected); - UpdateSel(gtk_tree_path_get_indices(path)[0], eclass); - gtk_tree_path_free(path); - } - } -} - -static gint eclasslist_button_press (GtkWidget *widget, GdkEventButton *event, gpointer data) -{ - if (event->type == GDK_2BUTTON_PRESS) - { - CreateEntity (); - return TRUE; - } - return FALSE; -} - -static gint eclasslist_keypress (GtkWidget* widget, GdkEventKey* event, gpointer data) -{ - unsigned int code = gdk_keyval_to_upper (event->keyval); - - if (event->keyval == GDK_Return) - { - CreateEntity (); - return TRUE; - } - - // select the entity that starts with the key pressed - if (code <= 'Z' && code >= 'A') - { - GtkTreeView* view = GTK_TREE_VIEW(EntWidgets[EntList]); - GtkTreeModel* model; - GtkTreeIter iter; - if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(view), &model, &iter) == FALSE - || gtk_tree_model_iter_next(model, &iter) == FALSE) - { - gtk_tree_model_get_iter_first(model, &iter); - } - - for(unsigned int count = gtk_tree_model_iter_n_children(model, NULL); count > 0; --count) - { - char* text; - gtk_tree_model_get(model, &iter, 0, &text, -1); - - if (toupper (text[0]) == (int)code) - { - GtkTreePath* path = gtk_tree_model_get_path(model, &iter); - gtk_tree_selection_select_path(gtk_tree_view_get_selection(view), path); - gtk_tree_view_scroll_to_cell(view, path, NULL, FALSE, 0, 0); - gtk_tree_path_free(path); - count = 1; - } - - g_free(text); - - if(gtk_tree_model_iter_next(model, &iter) == FALSE) - gtk_tree_model_get_iter_first(model, &iter); - } - - return TRUE; - } - return FALSE; -} - - -static void proplist_selection_changed(GtkTreeSelection* selection, gpointer data) -{ - // find out what type of entity we are trying to create - GtkTreeModel* model; - GtkTreeIter iter; - if(gtk_tree_selection_get_selected(selection, &model, &iter) == FALSE) - { - return; - } - - char* key; - char* val; - gtk_tree_model_get(model, &iter, 0, &key, 1, &val, -1); - - gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntKeyField]), key); - gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntValueField]), val); - - g_free(key); - g_free(val); -} - -static void entity_check (GtkWidget *widget, gpointer data) -{ - if( !disable_spawn_get ) - GetSpawnFlags(); -} - -static void entitylist_angle (GtkWidget *widget, gpointer data) -{ - SetKeyValue (edit_entity, "angle", (char*)data); - SetKeyValuePairs (); -} - -static gint entityentry_keypress (GtkWidget* widget, GdkEventKey* event, gpointer data) -{ - if (event->keyval == GDK_Tab) - { - if (widget == EntWidgets[EntKeyField]) - { - //gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntValueField]), ""); - gtk_window_set_focus (GTK_WINDOW (g_pGroupDlg->m_pWidget), EntWidgets[EntValueField]); - } - else - gtk_window_set_focus (GTK_WINDOW (g_pGroupDlg->m_pWidget), EntWidgets[EntKeyField]); - - return TRUE; - } - else if (event->keyval == GDK_Return) - { - if (widget == EntWidgets[EntKeyField]) - { - gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntValueField]), ""); - gtk_window_set_focus (GTK_WINDOW (g_pGroupDlg->m_pWidget), EntWidgets[EntValueField]); - } - else - { - AddProp (); - } - return TRUE; - } - - return FALSE; -} -/* -// add a new group, put all selected brushes into the group -static void groupdlg_add (GtkWidget *widget, gpointer data) -{ - char* name = DoNameDlg ("New Group"); - - if (name != NULL) - { - // create a new group node - GtkCTreeNode *item; - item = gtk_ctree_insert_node (GTK_CTREE (g_wndGroup.m_pTree), g_pGroupDlg->m_hWorld, NULL, &name, 0, - tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP], - tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP], FALSE, TRUE); - - // create a new group - group_t *g = Group_Alloc (name); - g->itemOwner = item; - g->next = g_pGroups; - g_pGroups = g; - - // now add the selected brushes - // NOTE: it would be much faster to give the group_t for adding - // but Select_AddToGroup is the standard way for all other cases - Select_AddToGroup (name); - g_free (name); - } -} -*/ -static void switch_page (GtkNotebook *notebook, GtkNotebookPage *page, guint page_num, gpointer data) -{ - char *text; - gtk_label_get(GTK_LABEL(gtk_notebook_get_tab_label(notebook, gtk_notebook_get_nth_page(notebook, page_num))), &text); - gtk_window_set_title (GTK_WINDOW (data), text); - - gpointer item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_misc_selectentitycolor"); - - if (g_pParentWnd->FloatingGroupDialog()) - { - switch (page_num) - { - case 0: inspector_mode = W_ENTITY; break; - case 1: inspector_mode = W_TEXTURE; break; - case 2: inspector_mode = W_CONSOLE; break; - default: inspector_mode = W_GROUP; break; - } - } - else - { - if (page_num == 0) - inspector_mode = W_ENTITY; - else - inspector_mode = W_GROUP; - } - - if (inspector_mode == W_ENTITY) - gtk_widget_set_sensitive (GTK_WIDGET (item), TRUE); - else - gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE); -} - -// ============================================================================= -// GroupDlg class - -// NOTE: when a key is hit with group window focused, we catch in this handler but it gets propagated to mainframe too -// therefore the message will be intercepted and used as a ID_SELECTION_DESELECT -static gint OnDialogKey (GtkWidget* widget, GdkEventKey* event, gpointer data) -{ -#ifdef DBG_PI - Sys_Printf("OnDialogKey\n"); -#endif - if ((event->keyval == GDK_Escape) && (g_pParentWnd->CurrentStyle() != MainFrame::eFloating)) - { - // toggle off the group view (whatever part of it is currently displayed) - // this used to be done with a g_pParentWnd->OnViewEntity(); but it had bad consequences - // http://fenris.lokigames.com/show_bug.cgi?id=2773 - widget_delete_hide (g_qeglobals_gui.d_entity); - return TRUE; - } - return FALSE; -} - -GroupDlg::GroupDlg () -{ - m_pWidget = NULL; - m_hWorld = NULL; -} - -#ifdef _WIN32 -extern void PositionWindowOnPrimaryScreen(window_position_t& position); -#endif - -void GroupDlg::Create () -{ - if (m_pWidget != NULL) - return; - - GtkWidget* dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - -#ifdef _WIN32 - if( g_PrefsDlg.m_bStartOnPrimMon ) { - PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.posEntityWnd ); - } -#endif - load_window_pos (dlg, g_PrefsDlg.mWindowInfo.posEntityWnd); - - gtk_window_set_title (GTK_WINDOW (dlg), "Entities"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", GTK_SIGNAL_FUNC (widget_delete_hide), NULL); - // catch 'Esc' - gtk_signal_connect (GTK_OBJECT (dlg), "key_press_event", GTK_SIGNAL_FUNC (OnDialogKey), NULL); - gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pParentWnd->m_pWidget)); - g_qeglobals_gui.d_entity = dlg; - - { - GtkWidget* notebook = gtk_notebook_new (); - gtk_widget_show (notebook); - gtk_container_add (GTK_CONTAINER (dlg), notebook); - gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_BOTTOM); - m_pNotebook = notebook; - - { - GtkWidget* vbox = gtk_vbox_new (FALSE, 2); - gtk_widget_show (vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 2); - - { - GtkWidget* label = gtk_label_new ("Entities"); - gtk_widget_show (label); - gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); - } - - { - GtkWidget* split1 = gtk_vpaned_new (); - gtk_box_pack_start (GTK_BOX (vbox), split1, TRUE, TRUE, 0); - gtk_widget_show (split1); - - { - GtkWidget* split2 = gtk_vpaned_new (); - gtk_paned_add1 (GTK_PANED (split1), split2); - gtk_widget_show (split2); - - g_object_set_data (G_OBJECT (dlg), "split1", split1); - g_object_set_data (G_OBJECT (dlg), "split2", split2); - - { - GtkWidget* vbox2 = gtk_vbox_new (FALSE, 2); - gtk_widget_show (vbox2); - gtk_paned_pack2 (GTK_PANED (split1), vbox2, FALSE, FALSE); - - { - GtkWidget* scr = gtk_scrolled_window_new (NULL, NULL); - gtk_widget_show (scr); - gtk_paned_add1 (GTK_PANED (split2), scr); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); - - { - GtkListStore* store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER); - - GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); - g_signal_connect(G_OBJECT(view), "button_press_event", G_CALLBACK(eclasslist_button_press), NULL); - g_signal_connect(G_OBJECT(view), "key_press_event", G_CALLBACK(eclasslist_keypress), this); - - { - GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); - GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Key", renderer, "text", 0, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); - } - - { - GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); - g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(eclasslist_selection_changed), dlg); - } - - gtk_widget_show(view); - - gtk_container_add(GTK_CONTAINER (scr), view); - - g_object_unref(G_OBJECT(store)); - EntWidgets[EntList] = view; - g_entlist_store = store; - } - } - - { - GtkWidget* scr = gtk_scrolled_window_new (NULL, NULL); - gtk_widget_show (scr); - gtk_paned_add2 (GTK_PANED (split2), scr); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); - - { - GtkWidget* text = gtk_text_view_new(); - gtk_widget_set_size_request(text, 0, -1); // allow shrinking - gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD); - gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE); - gtk_widget_show (text); - gtk_container_add (GTK_CONTAINER (scr), text); - EntWidgets[EntComment] = text; - } - } - - { - // Spawnflags (4 colums wide max, or window gets too wide.) - GtkWidget* table = LayoutTable = gtk_table_new (4, 4, FALSE); - gtk_box_pack_start (GTK_BOX (vbox2), LayoutTable, FALSE, TRUE, 0); - gtk_widget_show(LayoutTable); - - for (int i = 0; i < MAX_FLAGS; i++) - { - GtkWidget* check = gtk_check_button_new_with_label (""); - gtk_widget_ref (check); - gtk_signal_connect (GTK_OBJECT (check), "toggled", GTK_SIGNAL_FUNC (entity_check), NULL); - EntWidgets[EntCheck1+i] = check; - } - - //++timo cleanme: these flags where Q2 stuff - /* - check = gtk_check_button_new_with_label ("!Easy"); - gtk_widget_show (check); - gtk_signal_connect (GTK_OBJECT (check), "toggled", GTK_SIGNAL_FUNC (entity_check), NULL); - gtk_table_attach (GTK_TABLE (table), check, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - EntWidgets[EntCheck17] = check; - - check = gtk_check_button_new_with_label ("!Medium"); - gtk_widget_show (check); - gtk_signal_connect (GTK_OBJECT (check), "toggled", GTK_SIGNAL_FUNC (entity_check), NULL); - gtk_table_attach (GTK_TABLE (table), check, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - EntWidgets[EntCheck18] = check; - - check = gtk_check_button_new_with_label ("!Hard"); - gtk_widget_show (check); - gtk_signal_connect (GTK_OBJECT (check), "toggled", GTK_SIGNAL_FUNC (entity_check), NULL); - gtk_table_attach (GTK_TABLE (table), check, 2, 3, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - EntWidgets[EntCheck19] = check; - - check = gtk_check_button_new_with_label ("!DeathMatch"); - gtk_widget_show (check); - gtk_signal_connect (GTK_OBJECT (check), "toggled", GTK_SIGNAL_FUNC (entity_check), NULL); - gtk_table_attach (GTK_TABLE (table), check, 2, 3, 3, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - EntWidgets[EntCheck20] = check; - */ - } - - { - GtkWidget* scr = gtk_scrolled_window_new (NULL, NULL); - gtk_widget_show (scr); - gtk_box_pack_start (GTK_BOX (vbox2), scr, TRUE, TRUE, 0); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); - - { - GtkListStore* store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); - - GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); - - { - GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); - GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); - } - - { - GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); - GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 1, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); - } - - { - GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); - g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(proplist_selection_changed), dlg); - } - - gtk_widget_show(view); - - gtk_container_add(GTK_CONTAINER (scr), view); - - g_object_unref(G_OBJECT(store)); - - EntWidgets[EntProps] = view; - g_entprops_store = store; - } - } - } - - int x = g_PrefsDlg.mWindowInfo.nEntitySplit1; - if (x != -1) - { - gtk_paned_set_position (GTK_PANED (split1), x); - - while (gtk_events_pending ()) gtk_main_iteration (); - x = g_PrefsDlg.mWindowInfo.nEntitySplit2; - - if (x != -1) - gtk_paned_set_position (GTK_PANED (split2), x); - } - } - } - - { - GtkWidget* table = gtk_table_new (2, 2, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 3); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - { - GtkWidget* entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_events (entry, GDK_KEY_PRESS_MASK); - gtk_signal_connect (GTK_OBJECT (entry), "key_press_event", - GTK_SIGNAL_FUNC (entityentry_keypress), this); - EntWidgets[EntKeyField] = entry; - } - - { - GtkWidget* entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_events (entry, GDK_KEY_PRESS_MASK); - gtk_signal_connect (GTK_OBJECT (entry), "key_press_event", - GTK_SIGNAL_FUNC (entityentry_keypress), this); - EntWidgets[EntValueField] = entry; - } - - { - GtkWidget* label = gtk_label_new ("Value"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - } - - { - GtkWidget* label = gtk_label_new ("Key"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - } - } - - { - GtkWidget* hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); - - { - GtkWidget* table = gtk_table_new (3, 3, TRUE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, TRUE, 0); - - { - GtkWidget* button = gtk_button_new_with_label ("360"); - gtk_widget_show (button); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"360"); - gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - } - - { - GtkWidget* button = gtk_button_new_with_label ("45"); - gtk_widget_show (button); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"45"); - gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - } - - { - GtkWidget* button = gtk_button_new_with_label ("90"); - gtk_widget_show (button); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"90"); - gtk_table_attach (GTK_TABLE (table), button, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - } - - - { - GtkWidget* button = gtk_button_new_with_label ("135"); - gtk_widget_show (button); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"135"); - gtk_table_attach (GTK_TABLE (table), button, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - } - - { - GtkWidget* button = gtk_button_new_with_label ("180"); - gtk_widget_show (button); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"180"); - gtk_table_attach (GTK_TABLE (table), button, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - } - - { - GtkWidget* button = gtk_button_new_with_label ("225"); - gtk_widget_show (button); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"225"); - gtk_table_attach (GTK_TABLE (table), button, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - } - - { - GtkWidget* button = gtk_button_new_with_label ("270"); - gtk_widget_show (button); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"270"); - gtk_table_attach (GTK_TABLE (table), button, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - } - - { - GtkWidget* button = gtk_button_new_with_label ("315"); - gtk_widget_show (button); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"315"); - gtk_table_attach (GTK_TABLE (table), button, 2, 3, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - } - } - - { - GtkWidget* vbox2 = gtk_vbox_new (FALSE, 0); - gtk_widget_show (vbox2); - gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 0); - - { - GtkWidget* button = gtk_button_new_with_label ("Reset"); - gtk_widget_show (button); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (ResetEntity), NULL); - gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); - } - - { - GtkWidget* button = gtk_button_new_with_label ("Up"); - gtk_widget_show (button); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"-1"); - gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); - } - - { - GtkWidget* button = gtk_button_new_with_label ("Dn"); - gtk_widget_show (button); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"-2"); - gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); - } - } - - { - GtkWidget* vbox2 = gtk_vbox_new (FALSE, 0); - gtk_widget_show (vbox2); - gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 0); - - { - GtkWidget* button = gtk_button_new_with_label ("Del Key/Pair"); - gtk_widget_show (button); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (DelProp), NULL); - gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); - } - - { - GtkWidget* button = gtk_button_new_with_label ("Sound..."); - gtk_widget_show (button); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (AssignSound), NULL); - gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); - } - - { - GtkWidget* button = gtk_button_new_with_label ("Model..."); - gtk_widget_show (button); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (AssignModel), NULL); - gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); - } - } - } - } - - if (g_pParentWnd->FloatingGroupDialog()) - { - { - GtkWidget* scr = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); - gtk_widget_show (scr); - gtk_container_set_border_width (GTK_CONTAINER (scr), 3); - - { - GtkWidget* text = gtk_text_view_new (); - gtk_widget_set_size_request(text, 0, -1); // allow shrinking - gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD); - gtk_text_view_set_editable (GTK_TEXT_VIEW(text), FALSE); - gtk_container_add (GTK_CONTAINER (scr), text); - gtk_widget_show (text); - g_qeglobals_gui.d_edit = text; - } - - { - GtkWidget* label = gtk_label_new ("Console"); - gtk_widget_show (label); - gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scr, label); - } - } - } - - - //++timo NOTE: this part for grouping code, don't remove! (we'll put it back in sometime soon) - - /* - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 3); - - scr = gtk_scrolled_window_new (NULL, NULL); - gtk_widget_show (scr); - gtk_box_pack_start (GTK_BOX (vbox), scr, TRUE, TRUE, 0); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - - ctree = gtk_ctree_new (1, 0); - gtk_widget_show (ctree); - gtk_container_add (GTK_CONTAINER (scr), ctree); - gtk_clist_column_titles_hide (GTK_CLIST (ctree)); - m_pTree = ctree; - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); - - button = gtk_button_new_with_label ("Add..."); - gtk_widget_show (button); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (groupdlg_add), NULL); - gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Edit..."); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Delete"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); - gtk_widget_set_usize (button, 60, -2); - - label = gtk_label_new ("Groups"); - gtk_widget_show (label); - gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); - */ - inspector_mode = W_ENTITY; - // gtk_window_set_title (GTK_WINDOW (dlg), "Entities"); - m_pWidget = dlg; - /* - load_pixmap ("grouptree1.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[0], &tree_masks[0]); - load_pixmap ("grouptree2.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[1], &tree_masks[1]); - load_pixmap ("grouptree3.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[2], &tree_masks[2]); - load_pixmap ("grouptree4.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[3], &tree_masks[3]); - load_pixmap ("grouptree5.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[4], &tree_masks[4]); - load_pixmap ("grouptree6.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[5], &tree_masks[5]); - load_pixmap ("grouptree7.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[6], &tree_masks[6]); - - Group_Init(); -*/ - g_signal_connect (G_OBJECT (notebook), "switch_page", G_CALLBACK (switch_page), dlg); - } -} - +/* +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 +*/ + +// +// Floating dialog that contains a notebook with at least Entities and Group tabs +// I merged the 2 MS Windows dialogs in a single class +// +// Leonardo Zide (leo@lokigames.com) +// + +#ifndef _WIN32 + #include +#endif +#include +#include "stdafx.h" +#include "groupdialog.h" + +GtkWidget* EntWidgets[EntLast]; +GtkListStore* g_entlist_store; +GtkListStore* g_entprops_store; +int inspector_mode; // W_TEXTURE, W_ENTITY, or W_CONSOLE +qboolean multiple_entities; +// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=17 +qboolean disable_spawn_get = false; +entity_t *edit_entity; +/* +static GdkPixmap *tree_pixmaps[7]; +static GdkBitmap *tree_masks[7]; +*/ +#define IMG_PATCH 0 +#define IMG_BRUSH 1 +#define IMG_GROUP 2 +#define IMG_ENTITY 3 +#define IMG_ENTITYGROUP 4 +#define IMG_MODEL 5 +#define IMG_SCRIPT 6 + +// misc group support +#define MAX_GROUPS 4096 +#define GROUP_DELIMETER '@' +#define GROUPNAME "QER_Group_%i" + +GroupDlg g_wndGroup; +GroupDlg *g_pGroupDlg = &g_wndGroup; + +// group_t are loaded / saved through "group_info" entities +// they hold epairs for group settings and additionnal access info (tree nodes) +group_t *g_pGroups = NULL; + +// the number of active spawnflags +static int spawnflag_count; +// table: index, match spawnflag item to the spawnflag index (i.e. which bit) +static int spawn_table[MAX_FLAGS]; +// we change the layout depending on how many spawn flags we need to display +// the table is a 4x4 in which we need to put the comment box EntWidgets[EntComment] and the spawn flags.. +static GtkWidget *LayoutTable; +// 0: none of them are hooked +// 1: only the text, 2: text and four checks, 3: text and 8 checks +static int widget_state = 0; + +static void entity_check (GtkWidget *widget, gpointer data); + +// ============================================================================= +// Global functions + +/* +=============================================================== + +ENTITY WINDOW + +=============================================================== +*/ + +void FillClassList () +{ + GtkListStore* store = g_entlist_store; + + gtk_list_store_clear(store); + + for (eclass_t* e = eclass ; e ; e = e->next) + { + GtkTreeIter iter; + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, e->name, 1, e, -1); + } +} + +// SetKeyValuePairs +// +// Reset the key/value (aka property) listbox and fill it with the +// k/v pairs from the entity being edited. +// + +void SetKeyValuePairs (bool bClearMD3) +{ + GtkListStore* store = g_entprops_store; + + gtk_list_store_clear(store); + + if (edit_entity == NULL) + { + // if there's no entity, then display no key/values + return; + } + + // save current key/val pair around filling epair box + // row_select wipes it and sets to first in list + Str strKey = gtk_entry_get_text (GTK_ENTRY (EntWidgets[EntKeyField])); + Str strVal = gtk_entry_get_text (GTK_ENTRY (EntWidgets[EntValueField])); + + + // Walk through list and add pairs + for(epair_t* epair = edit_entity->epairs ; epair ; epair = epair->next) + { + GtkTreeIter iter; + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, epair->key, 1, epair->value, -1); + } + + gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntKeyField]), strKey.GetBuffer()); + gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntValueField]), strVal.GetBuffer()); + + Sys_UpdateWindows(W_CAMERA | W_XY); +} + +// SetSpawnFlags +// +// Update the checkboxes to reflect the flag state of the entity +// +void SetSpawnFlags(void) +{ + int f, i, v; + + disable_spawn_get = true; + + f = atoi(ValueForKey (edit_entity, "spawnflags")); + for (i=0 ; inext) + DeleteKey (b->owner, "spawnflags"); + } + else + DeleteKey (edit_entity, "spawnflags"); + } + else + { + sprintf (sz, "%i", f); + if (multiple_entities) + { + brush_t *b; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + SetKeyValue(b->owner, "spawnflags", sz); + } + else + SetKeyValue (edit_entity, "spawnflags", sz); + } + SetKeyValuePairs (); +} + +//#define DBG_UPDATESEL + +// UpdateSel +// +// Update the listbox, checkboxes and k/v pairs to reflect the new selection +// iIndex is the index in the list box with the class name, -1 if not found +bool UpdateSel(int iIndex, eclass_t *pec) +{ + int i, next_state; + brush_t *b; + + // syndrom of crappy code, we may get into stack overflowing crap with this function and Gtk + // if we play with the list of entity classes + // using a static flag to prevent recursion + static bool bBlockUpdate = false; + + if (bBlockUpdate) + return FALSE; // NOTE TTimo wtf is the return value for anyway? + +#ifdef DBG_UPDATESEL + Sys_FPrintf(SYS_WRN, "UpdateSel\n"); +#endif + + if (selected_brushes.next == &selected_brushes) + { + edit_entity = world_entity; + multiple_entities = false; + } + else + { + edit_entity = selected_brushes.next->owner; + for (b=selected_brushes.next->next ; b != &selected_brushes ; b=b->next) + { + if (b->owner != edit_entity) + { + multiple_entities = true; + break; + } + } + } + + if (iIndex != -1) + { +#ifdef DBG_UPDATESEL + Sys_FPrintf(SYS_WRN,"Setting focus_row to %d\n", iIndex); +#endif + bBlockUpdate = true; + + GtkTreeView* view = GTK_TREE_VIEW(EntWidgets[EntList]); + GtkTreePath* path = gtk_tree_path_new(); + gtk_tree_path_append_index(path, iIndex); + gtk_tree_selection_select_path(gtk_tree_view_get_selection(view), path); + gtk_tree_view_scroll_to_cell(view, path, NULL, FALSE, 0, 0); + gtk_tree_path_free(path); + + bBlockUpdate = false; + } + + if (pec == NULL) + return TRUE; + + // Set up the description + { + GtkTextBuffer* buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(EntWidgets[EntComment])); + gtk_text_buffer_set_text (buffer, pec->comments, -1); + } + + spawnflag_count = 0; + + // do a first pass to count the spawn flags, don't touch the widgets, we don't know in what state they are + for (i=0 ; iflagnames[i] && pec->flagnames[i][0] != 0 && strcmp(pec->flagnames[i],"-")) + { + spawn_table[spawnflag_count] = i; + spawnflag_count++; + } + } + + // what's new widget state + if (spawnflag_count==0) + next_state = 1; + else if (spawnflag_count<=4) + next_state = 2; + else if (spawnflag_count<=8) + next_state = 3; + else if (spawnflag_count<=12) + next_state = 4; + else + next_state = 5; + widget_state = next_state; + static int last_count = 0; + + // disable all remaining boxes + // NOTE: these boxes might not even be on display + for (i = 0; i < last_count; i++) + { + GtkWidget* widget = EntWidgets[EntCheck1+i]; + gtk_label_set_text (GTK_LABEL (GTK_BIN (widget)->child), " "); + gtk_widget_hide (widget); + gtk_widget_ref (widget); + gtk_container_remove (GTK_CONTAINER (LayoutTable), widget); + } + last_count = spawnflag_count; + + for (i=0 ; iflagnames[spawn_table[i]]; + str.MakeLower (); + +// gtk_table_attach (GTK_TABLE (LayoutTable), widget, i%4, i%4+1, i/4, i/4+1, + gtk_table_attach (GTK_TABLE (LayoutTable), widget, i%4, i%4+1, i/4, i/4+1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_unref (widget); + + gtk_label_set_text (GTK_LABEL (GTK_BIN (widget)->child), str.GetBuffer ()); + } + + SetSpawnFlags(); + + SetKeyValuePairs(); + + return TRUE; +} + +bool UpdateEntitySel(eclass_t *pec) +{ +#ifdef DBG_UPDATESEL + Sys_FPrintf(SYS_WRN, "UpdateEntitySel\n"); +#endif + + GtkTreeModel* model = GTK_TREE_MODEL(g_entlist_store); + GtkTreeIter iter; + unsigned int i = 0; + for(gboolean good = gtk_tree_model_get_iter_first(model, &iter); good != FALSE; good = gtk_tree_model_iter_next(model, &iter)) + { + char* text; + gtk_tree_model_get(model, &iter, 0, &text, -1); + if (strcmp (text, pec->name) == 0) + { +#ifdef DBG_UPDATESEL + Sys_FPrintf(SYS_WRN, "found a match: %d %s\n", i, pec->name); +#endif + return UpdateSel (i, pec); + } + g_free(text); + ++i; + } + return UpdateSel (-1, pec); +} + +// CreateEntity +// +// Creates a new entity based on the currently selected brush and entity type. +// + +void CreateEntity(void) +{ + GtkTreeView* view = GTK_TREE_VIEW(EntWidgets[EntList]); + + // check to make sure we have a brush + if (selected_brushes.next == &selected_brushes) + { + gtk_MessageBox(g_pParentWnd->m_pWidget, "You must have a selected brush to create an entity", "info"); + return; + } + + // find out what type of entity we are trying to create + GtkTreeModel* model; + GtkTreeIter iter; + if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(view), &model, &iter) == FALSE) + { + gtk_MessageBox (g_pParentWnd->m_pWidget, "You must have a selected class to create an entity", "info"); + return; + } + + char* text; + gtk_tree_model_get(model, &iter, 0, &text, -1); + CreateEntityFromName(text, vec3_origin); + g_free(text); + + if (selected_brushes.next == &selected_brushes) + edit_entity = world_entity; + else + edit_entity = selected_brushes.next->owner; + + SetKeyValuePairs(); + Select_Deselect (); + Select_Brush (edit_entity->brushes.onext); + Sys_UpdateWindows(W_ALL); +} + +/* +=============== +AddProp + +=============== +*/ +void AddProp() +{ + if (edit_entity == NULL) + return; + + // Get current selection text + const char* key = gtk_entry_get_text (GTK_ENTRY (EntWidgets[EntKeyField])); + const char* value = gtk_entry_get_text (GTK_ENTRY (EntWidgets[EntValueField])); + + + // TTimo: if you change the classname to worldspawn you won't merge back in the structural brushes but create a parasite entity + if (!strcmp(key, "classname") && !strcmp(value, "worldspawn")) + { + gtk_MessageBox(g_pParentWnd->m_pWidget, "Cannot change \"classname\" key back to worldspawn.", NULL, MB_OK ); + return; + } + + + // RR2DO2: we don't want spaces in entity keys + if (strstr( key, " " )) + { + gtk_MessageBox(g_pParentWnd->m_pWidget, "No spaces are allowed in entity keys.", NULL, MB_OK ); + return; + } + + if (multiple_entities) + { + brush_t *b; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + SetKeyValue(b->owner, key, value); + } + else + SetKeyValue(edit_entity, key, value); + + // refresh the prop listbox + SetKeyValuePairs(); + + +#ifdef USEPLUGINENTITIES + // if it's a plugin entity, perhaps we need to update some drawing parameters + // NOTE: perhaps moving this code to a seperate func would help if we need it in other places + // TODO: we need to call some update func in the IPluginEntity in case model name changes etc. + // ( for the moment only bounding brush is updated ), see UpdateModelBrush in Ritual's Q3Radiant + if (edit_entity->eclass->nShowFlags & ECLASS_PLUGINENTITY) + { + vec3_t mins, maxs; + edit_entity->pPlugEnt->GetBounds( mins, maxs ); + // replace old bounding brush by newly computed one + // NOTE: this part is similar to Entity_BuildModelBrush in Ritual's Q3Radiant, it can be + // usefull moved into a seperate func + brush_t *b,*oldbrush; + if (edit_entity->brushes.onext != &edit_entity->brushes) + oldbrush = edit_entity->brushes.onext; + b = Brush_Create (mins, maxs, &edit_entity->eclass->texdef); + Entity_LinkBrush (edit_entity, b); + Brush_Build( b, true ); + Select_Deselect(); + Brush_AddToList (edit_entity->brushes.onext, &selected_brushes); + if (oldbrush) + Brush_Free( oldbrush ); + } +#endif // USEPLUGINENTITIES +} + +/* +=============== +DelProp + +=============== +*/ +void DelProp(void) +{ + if (edit_entity == NULL) + return; + + // Get current selection text + const char* key = gtk_entry_get_text (GTK_ENTRY (EntWidgets[EntKeyField])); + + if (multiple_entities) + { + brush_t *b; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + DeleteKey(b->owner, key); + } + else + DeleteKey(edit_entity, key); + + // refresh the prop listbox + SetKeyValuePairs(); +} + +void ResetEntity () +{ + epair_t *pep; + int i; + + if (edit_entity == NULL) + return; + + if (multiple_entities) + { + brush_t *b; + + for (b=selected_brushes.next; b != &selected_brushes; b=b->next) + for (pep = b->owner->epairs; pep; ) + { + if (strcmp (pep->key, "classname") != 0) + { + DeleteKey (b->owner, pep->key); + pep = b->owner->epairs; + } + else + pep = pep->next; + } + } + else + for (pep = edit_entity->epairs; pep; ) + { + if (strcmp (pep->key, "classname") != 0) + { + DeleteKey (edit_entity, pep->key); + pep = edit_entity->epairs; + } + else + pep = pep->next; + } + + // refresh the dialog + SetKeyValuePairs (); + for (i = EntCheck1; i <= EntCheck16; i++) + gtk_signal_handler_block_by_func (GTK_OBJECT (EntWidgets[i]), GTK_SIGNAL_FUNC (entity_check), NULL); + SetSpawnFlags (); + for (i = EntCheck1; i <= EntCheck16; i++) + gtk_signal_handler_unblock_by_func (GTK_OBJECT (EntWidgets[i]), GTK_SIGNAL_FUNC (entity_check), NULL); +} + +bool GetSelectAllCriteria(CString &strKey, CString &strVal) +{ + GtkTreeModel* model; + GtkTreeIter iter; + if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(EntWidgets[EntProps])), &model, &iter) + && (inspector_mode == W_ENTITY) + && GTK_WIDGET_VISIBLE (g_pGroupDlg->m_pWidget)) + { + strKey = gtk_entry_get_text (GTK_ENTRY (EntWidgets[EntKeyField])); + strVal = gtk_entry_get_text (GTK_ENTRY (EntWidgets[EntValueField])); + return TRUE; + } + return FALSE; +} + + +void AssignSound() +{ + char buffer[NAME_MAX]; + + strcpy (buffer, g_qeglobals.m_strHomeMaps.GetBuffer()); + strcat (buffer, "sound/"); + + if( access(buffer, R_OK) != 0 ) + { + // just go to fsmain + strcpy (buffer, g_qeglobals.m_strHomeMaps.GetBuffer()); + strcat (buffer, "/"); + } + + const char *filename = file_dialog (g_pGroupDlg->m_pWidget, TRUE, "Open Wav File", buffer, "sound"); + if (filename != NULL) + { + gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntKeyField]), "noise"); + char *aux = vfsExtractRelativePath (filename); + CString str; + if (aux) + str = aux; + else + { + Sys_FPrintf (SYS_WRN, "WARNING: could not extract the relative path, using full path instead\n"); + str = filename; + } + + gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntValueField]), str.GetBuffer()); + AddProp(); + } +} + +void AssignModel() +{ + char buffer[NAME_MAX]; + + strcpy (buffer, g_qeglobals.m_strHomeMaps.GetBuffer()); + strcat (buffer, "models/"); + + if( access(buffer, R_OK) != 0 ) + { + // just go to fsmain + strcpy (buffer, g_qeglobals.m_strHomeMaps.GetBuffer()); + strcat (buffer, "/"); + } + + const char *filename = file_dialog (g_pGroupDlg->m_pWidget, TRUE, "Open Model", buffer, MODEL_MAJOR); + if (filename != NULL) + { + gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntKeyField]), "model"); + // use VFS to get the correct relative path + char *aux = vfsExtractRelativePath (filename); + CString str; + if (aux) + str = aux; + else + { + Sys_FPrintf (SYS_WRN, "WARNING: could not extract the relative path, using full path instead\n"); + str = filename; + } + + gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntValueField]), str.GetBuffer()); + AddProp(); + edit_entity->brushes.onext->bModelFailed = false; + } +} + +/* +============== +SetInspectorMode +============== +*/ +void SetInspectorMode(int iType) +{ + if (iType == W_GROUP) + gtk_MessageBox(g_pParentWnd->m_pWidget, "Brush grouping is not functional yet", NULL, MB_OK | MB_ICONWARNING ); + + if (!g_pParentWnd->FloatingGroupDialog() && + (iType == W_TEXTURE || iType == W_CONSOLE)) + return; + + // Is the caller asking us to cycle to the next window? + if (iType == -1) + { + if (inspector_mode == W_ENTITY) + iType = W_TEXTURE; + else if (inspector_mode == W_TEXTURE) + iType = W_CONSOLE; + else if (inspector_mode == W_CONSOLE) + iType = W_GROUP; + else + iType = W_ENTITY; + } + + switch(iType) + { + case W_ENTITY: + // entity is always first in the inspector + gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_entity), "Entities"); + gtk_notebook_set_page (GTK_NOTEBOOK (g_pGroupDlg->m_pNotebook), 0); + break; + + case W_TEXTURE: + g_pParentWnd->GetTexWnd()->FocusEdit(); + gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_entity), "Textures"); + if (g_pParentWnd->FloatingGroupDialog()) + gtk_notebook_set_page (GTK_NOTEBOOK (g_pGroupDlg->m_pNotebook), 1); + break; + + case W_CONSOLE: + gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_entity), "Console"); + if (g_pParentWnd->FloatingGroupDialog()) + gtk_notebook_set_page (GTK_NOTEBOOK (g_pGroupDlg->m_pNotebook), 2); + break; + + case W_GROUP: + if (g_pParentWnd->FloatingGroupDialog()) + gtk_notebook_set_page (GTK_NOTEBOOK (g_pGroupDlg->m_pNotebook), 3); + else + gtk_notebook_set_page (GTK_NOTEBOOK (g_pGroupDlg->m_pNotebook), 1); + break; + + default: + break; + } +} + +void Group_Add(entity_t *e) +{ + /* + group_t *g = (group_t*)qmalloc(sizeof(group_t)); + g->epairs = e->epairs; + g->next = NULL; + e->epairs = NULL; + + // create a new group node + char *text = ValueForKey(g->epairs, "group"); + g->itemOwner = gtk_ctree_insert_node (GTK_CTREE (g_wndGroup.m_pTree), g_wndGroup.m_hWorld, NULL, &text, 0, + tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP], + tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP], TRUE, TRUE); + g->next = g_pGroups; + g_pGroups = g; + */ +} +/* +group_t* Group_Alloc(char *name) +{ + group_t *g = (group_t*)qmalloc(sizeof(group_t)); + SetKeyValue( g->epairs, "group", name ); + return g; +} + +group_t* Group_ForName(const char * name) +{ + group_t *g = g_pGroups; + while (g != NULL) + { + if (strcmp( ValueForKey(g->epairs,"group"), name ) == 0) + break; + g = g->next; + } + return g; +} + +void Group_AddToItem(brush_t *b, GtkCTreeNode* item) +{ + int nImage = IMG_BRUSH; + if (!g_qeglobals.m_bBrushPrimitMode) + { + return; + } + const char *pName = NULL; + // const char *pNamed = Brush_GetKeyValue(b, "name"); + + if (!b->owner || (b->owner == world_entity)) + { + if (b->patchBrush) + { + pName = "Generic Patch"; + nImage = IMG_PATCH; + } + else + { + pName = "Generic Brush"; + nImage = IMG_BRUSH; + } + } + else + { + pName = b->owner->eclass->name; + if (b->owner->eclass->fixedsize) + { + nImage = IMG_ENTITY; + } + else + { + nImage = IMG_ENTITYGROUP; + } + } + + GtkCTreeNode *newItem; + int i = (b->patchBrush) ? IMG_PATCH : IMG_BRUSH; + newItem = gtk_ctree_insert_node (GTK_CTREE (g_wndGroup.m_pTree), item, NULL, (gchar**)&pName, 0, + tree_pixmaps[i], tree_masks[i], tree_pixmaps[i], + tree_masks[i], TRUE, TRUE); + gtk_ctree_node_set_row_data (GTK_CTREE (g_wndGroup.m_pTree), newItem, b); + b->itemOwner = newItem; +} +*/ +void Group_RemoveBrush(brush_t *b) +{ + /* + if (!g_qeglobals.m_bBrushPrimitMode) + { + return; + } + if (b->itemOwner) + { + gtk_ctree_remove_node (GTK_CTREE (g_pGroupDlg->m_pTree), b->itemOwner); + b->itemOwner = NULL; + } + DeleteKey(b->epairs, "group"); + */ +} +/* +void Group_AddToWorld(brush_t *b) +{ + if (!g_qeglobals.m_bBrushPrimitMode) + { + return; + } + GtkCTreeNode *parent = gtk_ctree_node_nth (GTK_CTREE (g_pGroupDlg->m_pTree), 0); + Group_AddToItem(b, parent); +} +*/ +void Group_AddToProperGroup(brush_t *b) +{ + /* + if (!g_qeglobals.m_bBrushPrimitMode) + { + return; + } + + // NOTE: we do a local copy of the "group" key because it gets erased by Group_RemoveBrush + const char *pGroup = Brush_GetKeyValue(b, "group"); + // remove the entry in the tree if there's one + if (b->itemOwner) + { + gtk_ctree_remove_node (GTK_CTREE (g_pGroupDlg->m_pTree), b->itemOwner); + b->itemOwner = NULL; + } + + if (*pGroup != 0) + { + // find the item + group_t *g = Group_ForName(pGroup); + if (g) + Group_AddToItem(b, g->itemOwner); +#ifdef _DEBUG + else + Sys_Printf("WARNING: unexpected Group_ForName not found in Group_AddToProperGroup\n"); +#endif + } + else + { + Group_AddToWorld(b); + } + */ +} +/* +void Group_AddToSelected(brush_t *b) +{ + if (!g_qeglobals.m_bBrushPrimitMode) + { + return; + } + GtkCTreeNode *item; + item = gtk_ctree_node_nth (GTK_CTREE (g_pGroupDlg->m_pTree), GTK_CLIST (g_pGroupDlg->m_pTree)->focus_row); + if (item == NULL) + { + item = gtk_ctree_node_nth (GTK_CTREE (g_pGroupDlg->m_pTree), 0); + } + Group_AddToItem(b, item); +} +*/ +/* +void Group_Save(FILE *f) +{ + group_t *g = g_pGroups; + while (g) + { + fprintf(f,"{\n\"classname\" \"group_info\"\n\"group\" \"%s\"\n}\n", ValueForKey( g->epairs, "group" )); + g = g->next; + } +} +*/ + +void Group_Init() +{ + if (!g_qeglobals.m_bBrushPrimitMode) + { + return; + } + // start by cleaning everything + // clean the groups + //++timo FIXME: we leak, delete the groups on the way (I don't have time to do it now) +#ifdef _DEBUG + Sys_Printf("TODO: fix leak in Group_Init\n"); +#endif + group_t *g = g_pGroups; + while (g) + { + epair_t *ep,*enext; + for (ep = g->epairs ; ep ; ep=enext ) + { + enext = ep->next; + free (ep->key); + free (ep->value); + free (ep); + } + g = g->next; + } + /* + GtkCTreeNode *world; + char *text = "World"; + g_pGroups = NULL; + gtk_clist_clear (GTK_CLIST (g_wndGroup.m_pTree)); + world = gtk_ctree_insert_node (GTK_CTREE (g_wndGroup.m_pTree), NULL, NULL, &text, 0, + tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP], tree_pixmaps[IMG_GROUP], + tree_masks[IMG_GROUP], FALSE, TRUE); + */ + // walk through all the brushes, remove the itemOwner key and add them back where they belong + brush_t *b; + for (b = active_brushes.next; b != &active_brushes; b = b->next) + { + b->itemOwner = NULL; + Group_AddToProperGroup(b); + } + for (b = selected_brushes.next ; b != &selected_brushes ; b = b->next) + { + b->itemOwner = NULL; + Group_AddToProperGroup(b); + } +} +/* +// scan through world_entity for groups in this map? +// we use GROUPNAME "QER_group_%i" to look for existing groups and their naming +//++timo FIXME: is this actually needed for anything? +void Group_GetListFromWorld(GSList **pArray) +{ + if (!g_qeglobals.m_bBrushPrimitMode) + { + return; + } + + if (world_entity == NULL) + { + return; + } + + char cBuff[1024]; + for (int i =0; i < MAX_GROUPS; i++) + { + sprintf(cBuff, GROUPNAME, i); + char *pGroup = ValueForKey(world_entity, cBuff); + if (pGroup && strlen(pGroup) > 0) + { + *pArray = g_slist_append (*pArray, g_strdup (pGroup)); + } + else + { + break; + } + } +} + +void Group_RemoveListFromWorld() +{ + if (!g_qeglobals.m_bBrushPrimitMode) + { + return; + } + GSList* array = NULL; + Group_GetListFromWorld(&array); + + while (array) + { + DeleteKey(world_entity, (char*)array->data); + g_free (array->data); + array = g_slist_remove (array, array->data); + } +} + +int CountChar(const char *p, char c) +{ + int nCount = 0; + int nLen = strlen(p)-1; + while (nLen-- >= 0) + { + if (p[nLen] == c) + { + nCount++; + } + } + return nCount; +} +*/ +// ============================================================================= +// callbacks + +static void eclasslist_selection_changed(GtkTreeSelection* selection, gpointer data) +{ + GtkTreeModel* model; + GtkTreeIter selected; + // no world entity, we are not ready yet + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=917 + if( !world_entity ) { + return; + } + if(gtk_tree_selection_get_selected(selection, &model, &selected)) + { + eclass_t* eclass; + gtk_tree_model_get(model, &selected, 1, &eclass, -1); + if(eclass != NULL) + { + GtkTreePath* path = gtk_tree_model_get_path(model, &selected); + UpdateSel(gtk_tree_path_get_indices(path)[0], eclass); + gtk_tree_path_free(path); + } + } +} + +static gint eclasslist_button_press (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + if (event->type == GDK_2BUTTON_PRESS) + { + CreateEntity (); + return TRUE; + } + return FALSE; +} + +static gint eclasslist_keypress (GtkWidget* widget, GdkEventKey* event, gpointer data) +{ + unsigned int code = gdk_keyval_to_upper (event->keyval); + + if (event->keyval == GDK_Return) + { + CreateEntity (); + return TRUE; + } + + // select the entity that starts with the key pressed + if (code <= 'Z' && code >= 'A') + { + GtkTreeView* view = GTK_TREE_VIEW(EntWidgets[EntList]); + GtkTreeModel* model; + GtkTreeIter iter; + if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(view), &model, &iter) == FALSE + || gtk_tree_model_iter_next(model, &iter) == FALSE) + { + gtk_tree_model_get_iter_first(model, &iter); + } + + for(unsigned int count = gtk_tree_model_iter_n_children(model, NULL); count > 0; --count) + { + char* text; + gtk_tree_model_get(model, &iter, 0, &text, -1); + + if (toupper (text[0]) == (int)code) + { + GtkTreePath* path = gtk_tree_model_get_path(model, &iter); + gtk_tree_selection_select_path(gtk_tree_view_get_selection(view), path); + gtk_tree_view_scroll_to_cell(view, path, NULL, FALSE, 0, 0); + gtk_tree_path_free(path); + count = 1; + } + + g_free(text); + + if(gtk_tree_model_iter_next(model, &iter) == FALSE) + gtk_tree_model_get_iter_first(model, &iter); + } + + return TRUE; + } + return FALSE; +} + + +static void proplist_selection_changed(GtkTreeSelection* selection, gpointer data) +{ + // find out what type of entity we are trying to create + GtkTreeModel* model; + GtkTreeIter iter; + if(gtk_tree_selection_get_selected(selection, &model, &iter) == FALSE) + { + return; + } + + char* key; + char* val; + gtk_tree_model_get(model, &iter, 0, &key, 1, &val, -1); + + gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntKeyField]), key); + gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntValueField]), val); + + g_free(key); + g_free(val); +} + +static void entity_check (GtkWidget *widget, gpointer data) +{ + if( !disable_spawn_get ) + GetSpawnFlags(); +} + +static void entitylist_angle (GtkWidget *widget, gpointer data) +{ + SetKeyValue (edit_entity, "angle", (char*)data); + SetKeyValuePairs (); +} + +static gint entityentry_keypress (GtkWidget* widget, GdkEventKey* event, gpointer data) +{ + if (event->keyval == GDK_Tab) + { + if (widget == EntWidgets[EntKeyField]) + { + //gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntValueField]), ""); + gtk_window_set_focus (GTK_WINDOW (g_pGroupDlg->m_pWidget), EntWidgets[EntValueField]); + } + else + gtk_window_set_focus (GTK_WINDOW (g_pGroupDlg->m_pWidget), EntWidgets[EntKeyField]); + + return TRUE; + } + else if (event->keyval == GDK_Return) + { + if (widget == EntWidgets[EntKeyField]) + { + gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntValueField]), ""); + gtk_window_set_focus (GTK_WINDOW (g_pGroupDlg->m_pWidget), EntWidgets[EntValueField]); + } + else + { + AddProp (); + } + return TRUE; + } + + return FALSE; +} +/* +// add a new group, put all selected brushes into the group +static void groupdlg_add (GtkWidget *widget, gpointer data) +{ + char* name = DoNameDlg ("New Group"); + + if (name != NULL) + { + // create a new group node + GtkCTreeNode *item; + item = gtk_ctree_insert_node (GTK_CTREE (g_wndGroup.m_pTree), g_pGroupDlg->m_hWorld, NULL, &name, 0, + tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP], + tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP], FALSE, TRUE); + + // create a new group + group_t *g = Group_Alloc (name); + g->itemOwner = item; + g->next = g_pGroups; + g_pGroups = g; + + // now add the selected brushes + // NOTE: it would be much faster to give the group_t for adding + // but Select_AddToGroup is the standard way for all other cases + Select_AddToGroup (name); + g_free (name); + } +} +*/ +static void switch_page (GtkNotebook *notebook, GtkNotebookPage *page, guint page_num, gpointer data) +{ + char *text; + gtk_label_get(GTK_LABEL(gtk_notebook_get_tab_label(notebook, gtk_notebook_get_nth_page(notebook, page_num))), &text); + gtk_window_set_title (GTK_WINDOW (data), text); + + gpointer item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_misc_selectentitycolor"); + + if (g_pParentWnd->FloatingGroupDialog()) + { + switch (page_num) + { + case 0: inspector_mode = W_ENTITY; break; + case 1: inspector_mode = W_TEXTURE; break; + case 2: inspector_mode = W_CONSOLE; break; + default: inspector_mode = W_GROUP; break; + } + } + else + { + if (page_num == 0) + inspector_mode = W_ENTITY; + else + inspector_mode = W_GROUP; + } + + if (inspector_mode == W_ENTITY) + gtk_widget_set_sensitive (GTK_WIDGET (item), TRUE); + else + gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE); +} + +// ============================================================================= +// GroupDlg class + +// NOTE: when a key is hit with group window focused, we catch in this handler but it gets propagated to mainframe too +// therefore the message will be intercepted and used as a ID_SELECTION_DESELECT +static gint OnDialogKey (GtkWidget* widget, GdkEventKey* event, gpointer data) +{ +#ifdef DBG_PI + Sys_Printf("OnDialogKey\n"); +#endif + if ((event->keyval == GDK_Escape) && (g_pParentWnd->CurrentStyle() != MainFrame::eFloating)) + { + // toggle off the group view (whatever part of it is currently displayed) + // this used to be done with a g_pParentWnd->OnViewEntity(); but it had bad consequences + // http://fenris.lokigames.com/show_bug.cgi?id=2773 + widget_delete_hide (g_qeglobals_gui.d_entity); + return TRUE; + } + return FALSE; +} + +GroupDlg::GroupDlg () +{ + m_pWidget = NULL; + m_hWorld = NULL; +} + +#ifdef _WIN32 +extern void PositionWindowOnPrimaryScreen(window_position_t& position); +#endif + +void GroupDlg::Create () +{ + if (m_pWidget != NULL) + return; + + GtkWidget* dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + +#ifdef _WIN32 + if( g_PrefsDlg.m_bStartOnPrimMon ) { + PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.posEntityWnd ); + } +#endif + load_window_pos (dlg, g_PrefsDlg.mWindowInfo.posEntityWnd); + + gtk_window_set_title (GTK_WINDOW (dlg), "Entities"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", GTK_SIGNAL_FUNC (widget_delete_hide), NULL); + // catch 'Esc' + gtk_signal_connect (GTK_OBJECT (dlg), "key_press_event", GTK_SIGNAL_FUNC (OnDialogKey), NULL); + gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pParentWnd->m_pWidget)); + g_qeglobals_gui.d_entity = dlg; + + { + GtkWidget* notebook = gtk_notebook_new (); + gtk_widget_show (notebook); + gtk_container_add (GTK_CONTAINER (dlg), notebook); + gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_BOTTOM); + m_pNotebook = notebook; + + { + GtkWidget* vbox = gtk_vbox_new (FALSE, 2); + gtk_widget_show (vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 2); + + { + GtkWidget* label = gtk_label_new ("Entities"); + gtk_widget_show (label); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); + } + + { + GtkWidget* split1 = gtk_vpaned_new (); + gtk_box_pack_start (GTK_BOX (vbox), split1, TRUE, TRUE, 0); + gtk_widget_show (split1); + + { + GtkWidget* split2 = gtk_vpaned_new (); + gtk_paned_add1 (GTK_PANED (split1), split2); + gtk_widget_show (split2); + + g_object_set_data (G_OBJECT (dlg), "split1", split1); + g_object_set_data (G_OBJECT (dlg), "split2", split2); + + { + GtkWidget* vbox2 = gtk_vbox_new (FALSE, 2); + gtk_widget_show (vbox2); + gtk_paned_pack2 (GTK_PANED (split1), vbox2, FALSE, FALSE); + + { + GtkWidget* scr = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scr); + gtk_paned_add1 (GTK_PANED (split2), scr); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); + + { + GtkListStore* store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER); + + GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); + g_signal_connect(G_OBJECT(view), "button_press_event", G_CALLBACK(eclasslist_button_press), NULL); + g_signal_connect(G_OBJECT(view), "key_press_event", G_CALLBACK(eclasslist_keypress), this); + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Key", renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + { + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); + g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(eclasslist_selection_changed), dlg); + } + + gtk_widget_show(view); + + gtk_container_add(GTK_CONTAINER (scr), view); + + g_object_unref(G_OBJECT(store)); + EntWidgets[EntList] = view; + g_entlist_store = store; + } + } + + { + GtkWidget* scr = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scr); + gtk_paned_add2 (GTK_PANED (split2), scr); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); + + { + GtkWidget* text = gtk_text_view_new(); + gtk_widget_set_size_request(text, 0, -1); // allow shrinking + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD); + gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE); + gtk_widget_show (text); + gtk_container_add (GTK_CONTAINER (scr), text); + EntWidgets[EntComment] = text; + } + } + + { + // Spawnflags (4 colums wide max, or window gets too wide.) + GtkWidget* table = LayoutTable = gtk_table_new (4, 4, FALSE); + gtk_box_pack_start (GTK_BOX (vbox2), LayoutTable, FALSE, TRUE, 0); + gtk_widget_show(LayoutTable); + + for (int i = 0; i < MAX_FLAGS; i++) + { + GtkWidget* check = gtk_check_button_new_with_label (""); + gtk_widget_ref (check); + gtk_signal_connect (GTK_OBJECT (check), "toggled", GTK_SIGNAL_FUNC (entity_check), NULL); + EntWidgets[EntCheck1+i] = check; + } + + //++timo cleanme: these flags where Q2 stuff + /* + check = gtk_check_button_new_with_label ("!Easy"); + gtk_widget_show (check); + gtk_signal_connect (GTK_OBJECT (check), "toggled", GTK_SIGNAL_FUNC (entity_check), NULL); + gtk_table_attach (GTK_TABLE (table), check, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + EntWidgets[EntCheck17] = check; + + check = gtk_check_button_new_with_label ("!Medium"); + gtk_widget_show (check); + gtk_signal_connect (GTK_OBJECT (check), "toggled", GTK_SIGNAL_FUNC (entity_check), NULL); + gtk_table_attach (GTK_TABLE (table), check, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + EntWidgets[EntCheck18] = check; + + check = gtk_check_button_new_with_label ("!Hard"); + gtk_widget_show (check); + gtk_signal_connect (GTK_OBJECT (check), "toggled", GTK_SIGNAL_FUNC (entity_check), NULL); + gtk_table_attach (GTK_TABLE (table), check, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + EntWidgets[EntCheck19] = check; + + check = gtk_check_button_new_with_label ("!DeathMatch"); + gtk_widget_show (check); + gtk_signal_connect (GTK_OBJECT (check), "toggled", GTK_SIGNAL_FUNC (entity_check), NULL); + gtk_table_attach (GTK_TABLE (table), check, 2, 3, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + EntWidgets[EntCheck20] = check; + */ + } + + { + GtkWidget* scr = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scr); + gtk_box_pack_start (GTK_BOX (vbox2), scr, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); + + { + GtkListStore* store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); + + GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 1, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + { + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); + g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(proplist_selection_changed), dlg); + } + + gtk_widget_show(view); + + gtk_container_add(GTK_CONTAINER (scr), view); + + g_object_unref(G_OBJECT(store)); + + EntWidgets[EntProps] = view; + g_entprops_store = store; + } + } + } + + int x = g_PrefsDlg.mWindowInfo.nEntitySplit1; + if (x != -1) + { + gtk_paned_set_position (GTK_PANED (split1), x); + + while (gtk_events_pending ()) gtk_main_iteration (); + x = g_PrefsDlg.mWindowInfo.nEntitySplit2; + + if (x != -1) + gtk_paned_set_position (GTK_PANED (split2), x); + } + } + } + + { + GtkWidget* table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 3); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + { + GtkWidget* entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_events (entry, GDK_KEY_PRESS_MASK); + gtk_signal_connect (GTK_OBJECT (entry), "key_press_event", + GTK_SIGNAL_FUNC (entityentry_keypress), this); + EntWidgets[EntKeyField] = entry; + } + + { + GtkWidget* entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_events (entry, GDK_KEY_PRESS_MASK); + gtk_signal_connect (GTK_OBJECT (entry), "key_press_event", + GTK_SIGNAL_FUNC (entityentry_keypress), this); + EntWidgets[EntValueField] = entry; + } + + { + GtkWidget* label = gtk_label_new ("Value"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + } + + { + GtkWidget* label = gtk_label_new ("Key"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + } + } + + { + GtkWidget* hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + + { + GtkWidget* table = gtk_table_new (3, 3, TRUE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, TRUE, 0); + + { + GtkWidget* button = gtk_button_new_with_label ("360"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"360"); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + } + + { + GtkWidget* button = gtk_button_new_with_label ("45"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"45"); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + } + + { + GtkWidget* button = gtk_button_new_with_label ("90"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"90"); + gtk_table_attach (GTK_TABLE (table), button, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + } + + + { + GtkWidget* button = gtk_button_new_with_label ("135"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"135"); + gtk_table_attach (GTK_TABLE (table), button, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + } + + { + GtkWidget* button = gtk_button_new_with_label ("180"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"180"); + gtk_table_attach (GTK_TABLE (table), button, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + } + + { + GtkWidget* button = gtk_button_new_with_label ("225"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"225"); + gtk_table_attach (GTK_TABLE (table), button, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + } + + { + GtkWidget* button = gtk_button_new_with_label ("270"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"270"); + gtk_table_attach (GTK_TABLE (table), button, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + } + + { + GtkWidget* button = gtk_button_new_with_label ("315"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"315"); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + } + } + + { + GtkWidget* vbox2 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox2); + gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 0); + + { + GtkWidget* button = gtk_button_new_with_label ("Reset"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (ResetEntity), NULL); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + } + + { + GtkWidget* button = gtk_button_new_with_label ("Up"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"-1"); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + } + + { + GtkWidget* button = gtk_button_new_with_label ("Dn"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (entitylist_angle), (void *)"-2"); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + } + } + + { + GtkWidget* vbox2 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox2); + gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 0); + + { + GtkWidget* button = gtk_button_new_with_label ("Del Key/Pair"); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (DelProp), NULL); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + } + + { + GtkWidget* button = gtk_button_new_with_label ("Sound..."); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (AssignSound), NULL); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + } + + { + GtkWidget* button = gtk_button_new_with_label ("Model..."); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (AssignModel), NULL); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + } + } + } + } + + if (g_pParentWnd->FloatingGroupDialog()) + { + { + GtkWidget* scr = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); + gtk_widget_show (scr); + gtk_container_set_border_width (GTK_CONTAINER (scr), 3); + + { + GtkWidget* text = gtk_text_view_new (); + gtk_widget_set_size_request(text, 0, -1); // allow shrinking + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD); + gtk_text_view_set_editable (GTK_TEXT_VIEW(text), FALSE); + gtk_container_add (GTK_CONTAINER (scr), text); + gtk_widget_show (text); + g_qeglobals_gui.d_edit = text; + } + + { + GtkWidget* label = gtk_label_new ("Console"); + gtk_widget_show (label); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scr, label); + } + } + } + + + //++timo NOTE: this part for grouping code, don't remove! (we'll put it back in sometime soon) + + /* + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 3); + + scr = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scr); + gtk_box_pack_start (GTK_BOX (vbox), scr, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + + ctree = gtk_ctree_new (1, 0); + gtk_widget_show (ctree); + gtk_container_add (GTK_CONTAINER (scr), ctree); + gtk_clist_column_titles_hide (GTK_CLIST (ctree)); + m_pTree = ctree; + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("Add..."); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (groupdlg_add), NULL); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Edit..."); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Delete"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_widget_set_usize (button, 60, -2); + + label = gtk_label_new ("Groups"); + gtk_widget_show (label); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); + */ + inspector_mode = W_ENTITY; + // gtk_window_set_title (GTK_WINDOW (dlg), "Entities"); + m_pWidget = dlg; + /* + load_pixmap ("grouptree1.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[0], &tree_masks[0]); + load_pixmap ("grouptree2.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[1], &tree_masks[1]); + load_pixmap ("grouptree3.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[2], &tree_masks[2]); + load_pixmap ("grouptree4.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[3], &tree_masks[3]); + load_pixmap ("grouptree5.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[4], &tree_masks[4]); + load_pixmap ("grouptree6.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[5], &tree_masks[5]); + load_pixmap ("grouptree7.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[6], &tree_masks[6]); + + Group_Init(); +*/ + g_signal_connect (G_OBJECT (notebook), "switch_page", G_CALLBACK (switch_page), dlg); + } +} + diff --git a/radiant/gtkdlgs.cpp b/radiant/gtkdlgs.cpp index b75b02d1..f97682fe 100644 --- a/radiant/gtkdlgs.cpp +++ b/radiant/gtkdlgs.cpp @@ -1,4045 +1,4045 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -// -// Some small dialogs that don't need much -// -// Leonardo Zide (leo@lokigames.com) -// - -#include "stdafx.h" -#include -#include - -#ifdef _WIN32 -#include -#endif - -#ifdef _WIN32 -#include -#endif - -// ============================================================================= -// Color selection dialog - -qboolean DoColor (int iIndex) -{ - static bool bColorOpen = false; - - if(bColorOpen) - { - Sys_FPrintf(SYS_WRN, "DoColor dialog is already open\n"); - return false; - } - - bColorOpen = true; - - if (color_dialog (g_pParentWnd->m_pWidget, g_qeglobals.d_savedinfo.colors[iIndex])) - { - /* - ** scale colors so that at least one component is at 1.0F - ** if this is meant to select an entity color - */ - if (iIndex == COLOR_ENTITY) - { - float largest = 0.0F; - - if ( g_qeglobals.d_savedinfo.colors[iIndex][0] > largest ) - largest = g_qeglobals.d_savedinfo.colors[iIndex][0]; - if ( g_qeglobals.d_savedinfo.colors[iIndex][1] > largest ) - largest = g_qeglobals.d_savedinfo.colors[iIndex][1]; - if ( g_qeglobals.d_savedinfo.colors[iIndex][2] > largest ) - largest = g_qeglobals.d_savedinfo.colors[iIndex][2]; - - if ( largest == 0.0F ) - { - g_qeglobals.d_savedinfo.colors[iIndex][0] = 1.0F; - g_qeglobals.d_savedinfo.colors[iIndex][1] = 1.0F; - g_qeglobals.d_savedinfo.colors[iIndex][2] = 1.0F; - } - else - { - float scaler = 1.0F / largest; - - g_qeglobals.d_savedinfo.colors[iIndex][0] *= scaler; - g_qeglobals.d_savedinfo.colors[iIndex][1] *= scaler; - g_qeglobals.d_savedinfo.colors[iIndex][2] *= scaler; - } - } - - Sys_UpdateWindows (W_ALL); - bColorOpen = false; - return true; - } - else { - bColorOpen = false; - return false; - } -} - -// ============================================================================= -// Project settings dialog - -static void UpdateBSPCommandList (GtkWidget *dialog); - -static void DoProjectAddEdit (bool edit, GtkWidget *parent) -{ - GtkWidget *dlg, *vbox, *hbox, *label, *table, *button; - GtkWidget *cmd, *text; - int loop = 1, ret = IDCANCEL; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - if (edit) - gtk_window_set_title (GTK_WINDOW (dlg), "Edit Command"); - else - gtk_window_set_title (GTK_WINDOW (dlg), "Add Command"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_container_add (GTK_CONTAINER (dlg), vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - - table = gtk_table_new (2, 2, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("Menu text"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - label = gtk_label_new ("Command"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - text = gtk_entry_new (); - g_object_set_data (G_OBJECT (dlg), "text", text); - gtk_widget_show (text); - gtk_table_attach (GTK_TABLE (table), text, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (text, 300, -2); - - cmd = gtk_entry_new (); - g_object_set_data (G_OBJECT (dlg), "cmd", cmd); - gtk_widget_show (cmd); - gtk_table_attach (GTK_TABLE (table), cmd, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (cmd, 300, -2); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Cancel"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_set_usize (button, 60, -2); - - if (edit) - { - GtkTreeView* view = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(parent), "view")); - GtkTreeSelection* selection = gtk_tree_view_get_selection(view); - GtkTreeIter iter; - GtkTreeModel* model; - if(gtk_tree_selection_get_selected(selection, &model, &iter)) - { - char* key; - gtk_tree_model_get(model, &iter, 0, &key, -1); - const char* value = ValueForKey (g_qeglobals.d_project_entity, key); - gtk_entry_set_text (GTK_ENTRY (text), key); - gtk_entry_set_text (GTK_ENTRY (cmd), value); - g_free(key); - } - } - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - if (ret == IDOK) - { - const char* key = gtk_entry_get_text (GTK_ENTRY (text)); - const char* value = gtk_entry_get_text (GTK_ENTRY (cmd)); - - if (strlen (key) <= 0 || strlen (value) <= 0) - { - Sys_Printf ("Command not added\n"); - } - else - { - if (edit) - { - SetKeyValue (g_qeglobals.d_project_entity, key, value); - FillBSPMenu (); - } - else - { - if (key[0] == 'b' && key[1] == 's' && key[2] == 'p') - { - SetKeyValue (g_qeglobals.d_project_entity, key, value); - FillBSPMenu (); - } - else - Sys_Printf ("BSP commands must be preceded by \"bsp\""); - } - - UpdateBSPCommandList (parent); - } - } - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); -} - -static void UpdateBSPCommandList (GtkWidget *dialog) -{ - GtkListStore* store = GTK_LIST_STORE (g_object_get_data (G_OBJECT(dialog), "bsp_commands")); - - gtk_list_store_clear(store); - - for(epair_t* ep = g_qeglobals.d_project_entity->epairs; ep != NULL; ep = ep->next) - { - if(ep->key[0] == 'b' && ep->key[1] == 's' && ep->key[2] == 'p') - { - GtkTreeIter iter; - gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, 0, ep->key, -1); - } - } -} - -static void project_add (GtkWidget *widget, gpointer data) -{ - GtkWidget *dlg = GTK_WIDGET (data); - DoProjectAddEdit (false, dlg); - UpdateBSPCommandList (dlg); -} - -static void project_change (GtkWidget *widget, gpointer data) -{ - GtkWidget *dlg = GTK_WIDGET (data); - DoProjectAddEdit (true, dlg); - UpdateBSPCommandList (dlg); -} - -static void project_remove (GtkWidget *widget, gpointer data) -{ - GtkWidget* project = GTK_WIDGET(data); - - GtkTreeView* view = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(project), "view")); - GtkTreeSelection* selection = gtk_tree_view_get_selection(view); - GtkTreeIter iter; - GtkTreeModel* model; - if(gtk_tree_selection_get_selected(selection, &model, &iter)) - { - char* key; - gtk_tree_model_get(model, &iter, 0, &key, -1); - DeleteKey (g_qeglobals.d_project_entity, key); - g_free(key); - - char* index = gtk_tree_model_get_string_from_iter(model, &iter); - Sys_Printf ("Selected %s\n", index); - g_free(index); - - UpdateBSPCommandList(project); - FillBSPMenu(); - } -} - -static const char* sQ3ComboItem = "Quake III Arena"; -static const char* sTAComboItem = "Quake III: Team Arena"; -static const char* sModComboItem = "Custom Quake III modification"; -static const char* sWolfComboItem = "Return To Castle Wolfenstein"; -static const char* sWolfModComboItem = "Custom RTCW modification"; -static const char* sHLComboItem = "Half-life"; -static const char* sHLModComboItem = "Custom Half-life modification"; - -static const char* sWolfSPCombo = "Single Player mapping mode"; -static const char* sWolfMPCombo = "Multiplayer mapping mode"; - -// Arnout -// HARD-CODED ET HACK -static const char* sETComboItem = "Wolfenstein: Enemy Territory"; -static const char* sETModComboItem = "Custom ET modification"; - -// RIANT -// HARD-CODED JK2 HACK -static const char* sJK2ComboItem = "Jedi Knight II Outcast"; -static const char* sJK2ModComboItem = "Custom JK2 modification"; -static const char* sJK2SPCombo = "Single Player mapping mode"; -static const char* sJK2MPCombo = "Multiplayer mapping mode"; - -// TTimo -// HARD-CODED JA HACK -static const char* sJAComboItem = "Jedi Knight Jedi Academy"; -static const char* sJAModComboItem = "Custom JA modification"; -static const char* sJASPCombo = "Single Player mapping mode"; -static const char* sJAMPCombo = "Multiplayer mapping mode"; - -// RIANT -// HARD-CODED STVEF2 HACK -static const char* sSTVEFComboItem = "Star Trek Voyager : Elite Force"; -static const char* sSTVEFModComboItem = "Custom Elite Force modification"; -static const char* sSTVEFSPCombo = "Single Player mapping mode"; -static const char* sSTVEFMPCombo = "Holo Match mapping mode"; - -// RIANT -// HARD-CODED SOF2 HACK -static const char* sSOF2ComboItem = "Soldier of Fortune II - Double Helix"; -static const char* sSOF2ModComboItem = "Custom Sof2 modification"; -static const char* sSOF2SPCombo = "Single Player mapping mode"; -static const char* sSOF2MPCombo = "Multiplayer mapping mode"; - -static GtkWidget* game_select; // GTK_COMBO -static GtkEntry* fsgame_entry; - -gint OnSelchangeComboWhatgame (GtkWidget *widget, GdkEvent* event, gpointer data) -{ - const char *dir = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO(game_select)->entry)); - // HACK: Wolf - if (g_pGameDescription->mGameFile == "wolf.game") - { - if (!strcmp(dir,sWolfComboItem)) - { - // disable the fs_game text entry - gtk_entry_set_text (fsgame_entry, ""); - gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); - } - else - { - gtk_entry_set_text (fsgame_entry, ""); - gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); - } - - } - // HACK: ET - else if (g_pGameDescription->mGameFile == "et.game") - { - if (!strcmp(dir,sETComboItem)) - { - // disable the fs_game text entry - gtk_entry_set_text (fsgame_entry, ""); - gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); - } - else - { - gtk_entry_set_text (fsgame_entry, ""); - gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); - } - - } - else if (g_pGameDescription->mGameFile == "hl.game") - { - if (!strcmp(dir,sHLComboItem)) - { - // disable the fs_game text entry - gtk_entry_set_text (fsgame_entry, ""); - gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); - } - else - { - gtk_entry_set_text (fsgame_entry, ""); - gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); - } - - } - // RIANT - // HACK: JK2 - else if (g_pGameDescription->mGameFile == "jk2.game") - { - if (!strcmp(dir,sJK2ComboItem)) - { - // disable the fs_game text entry - gtk_entry_set_text (fsgame_entry, ""); - gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); - } - else - { - gtk_entry_set_text (fsgame_entry, ""); - gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); - } - } - // TTimo - // HACK: JA - else if (g_pGameDescription->mGameFile == "ja.game") - { - if (!strcmp(dir,sJAComboItem)) - { - // disable the fs_game text entry - gtk_entry_set_text (fsgame_entry, ""); - gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); - } - else - { - gtk_entry_set_text (fsgame_entry, ""); - gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); - } - } - // RIANT - // HACK: STVEF - else if (g_pGameDescription->mGameFile == "stvef.game") - { - if (!strcmp(dir,sSTVEFComboItem)) - { - // disable the fs_game text entry - gtk_entry_set_text (fsgame_entry, ""); - gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); - } - else - { - gtk_entry_set_text (fsgame_entry, ""); - gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); - } - } - // RIANT - // HACK: SOF2 - else if (g_pGameDescription->mGameFile == "sof2.game") - { - if (!strcmp(dir,sSOF2ComboItem)) - { - // disable the fs_game text entry - gtk_entry_set_text (fsgame_entry, ""); - gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); - } - else - { - gtk_entry_set_text (fsgame_entry, ""); - gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); - } - } - // QUAKE 3 - else - { - if (!strcmp(dir,sQ3ComboItem)) - { - // disable the fs_game text entry - gtk_entry_set_text (fsgame_entry, ""); - gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); - } - else if (!strcmp(dir,sTAComboItem)) - { - gtk_entry_set_text (fsgame_entry, "missionpack"); - gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); - } - else - { - gtk_entry_set_text (fsgame_entry, ""); - gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); - } - } - - return TRUE; -} - -void DoProjectSettings () -{ - GtkWidget *project; - GtkWidget *frame, *label, *vbox, *table1, *table2, *button; - GtkWidget *brush; - GtkWidget *scr; - GtkWidget *base, *game; - GtkWidget *gamemode_combo; - GList *combo_list = (GList*)NULL; - - int loop = 1, ret = IDCANCEL; - - project = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (project), "Project Settings"); - gtk_signal_connect (GTK_OBJECT (project), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (project), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (project), "loop", &loop); - g_object_set_data (G_OBJECT (project), "ret", &ret); - gtk_window_set_default_size (GTK_WINDOW (project), 550, 400); - - table1 = gtk_table_new (3, 2, FALSE); - gtk_widget_show (table1); - gtk_container_add (GTK_CONTAINER (project), table1); - gtk_container_set_border_width (GTK_CONTAINER (table1), 5); - gtk_table_set_row_spacings (GTK_TABLE (table1), 5); - gtk_table_set_col_spacings (GTK_TABLE (table1), 5); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_table_attach (GTK_TABLE (table1), vbox, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Cancel"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_set_usize (button, 60, -2); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_table_attach (GTK_TABLE (table1), vbox, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - button = gtk_button_new_with_label ("Add..."); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (project_add), project); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Change..."); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (project_change), project); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Remove"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (project_remove), project); - gtk_widget_set_usize (button, 60, -2); - - frame = gtk_frame_new ("Misc settings"); - gtk_widget_show (frame); - gtk_table_attach (GTK_TABLE (table1), frame, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - brush = gtk_check_button_new_with_label ("Use brush primitives in MAP files (NOTE: experimental feature,\n" - "required by the texture tools plugin)"); - gtk_widget_show (brush); - gtk_container_add (GTK_CONTAINER (frame), brush); - gtk_container_set_border_width (GTK_CONTAINER (brush), 5); - - frame = gtk_frame_new ("Menu commands"); - gtk_widget_show (frame); - gtk_table_attach (GTK_TABLE (table1), frame, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - - scr = gtk_scrolled_window_new ((GtkAdjustment*)NULL, (GtkAdjustment*)NULL); - gtk_widget_show (scr); - gtk_container_add (GTK_CONTAINER (frame), scr); - gtk_container_set_border_width (GTK_CONTAINER (scr), 5); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); - - - { - GtkListStore* store = gtk_list_store_new(1, G_TYPE_STRING); - - GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); - - GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); - GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); - - GtkTreeSelection* selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view)); - gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE); - - gtk_widget_show(view); - - g_object_set_data(G_OBJECT (project), "view", view); - g_object_set_data(G_OBJECT (project), "bsp_commands", store); - gtk_container_add(GTK_CONTAINER (scr), view); - - g_object_unref(G_OBJECT(store)); - } - - frame = gtk_frame_new ("Project settings"); - gtk_widget_show (frame); - gtk_table_attach (GTK_TABLE (table1), frame, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - - // HACK: hardcoded game stuff - if (g_pGameDescription->mGameFile == "wolf.game" || - g_pGameDescription->mGameFile == "et.game" || - g_pGameDescription->mGameFile == "jk2.game" || - g_pGameDescription->mGameFile == "stvef.game" || - g_pGameDescription->mGameFile == "sof2.game" || - g_pGameDescription->mGameFile == "ja.game" ) - { - table2 = gtk_table_new (9, 2, FALSE); - } - else - { - table2 = gtk_table_new (8, 2, FALSE); - } - gtk_widget_show (table2); - gtk_container_add (GTK_CONTAINER (frame), table2); - gtk_container_set_border_width (GTK_CONTAINER (table2), 5); - gtk_table_set_row_spacings (GTK_TABLE (table2), 5); - gtk_table_set_col_spacings (GTK_TABLE (table2), 5); - - /* - fill in the game selection combo - HACK: hardcoded Q3/Wolf/HL switch - \todo that stuff would be faster to write with implementation of property bags and associated code to edit - */ - if (g_pGameDescription->mGameFile == "wolf.game") - { - combo_list = g_list_append (combo_list, (void *)sWolfComboItem); - combo_list = g_list_append (combo_list, (void *)sWolfModComboItem); - } - else if (g_pGameDescription->mGameFile == "et.game") - { - combo_list = g_list_append (combo_list, (void *)sETComboItem); - combo_list = g_list_append (combo_list, (void *)sETModComboItem); - } - else if (g_pGameDescription->mGameFile == "hl.game") - { - combo_list = g_list_append (combo_list, (void *)sHLComboItem); - combo_list = g_list_append (combo_list, (void *)sHLModComboItem); - } - // RIANT - // JK2 HACK - else if (g_pGameDescription->mGameFile == "jk2.game") - { - combo_list = g_list_append (combo_list, (void *)sJK2ComboItem); - combo_list = g_list_append (combo_list, (void *)sJK2ModComboItem); - } - // TTimo - // JA HACK - else if (g_pGameDescription->mGameFile == "ja.game") - { - combo_list = g_list_append (combo_list, (void *)sJAComboItem); - combo_list = g_list_append (combo_list, (void *)sJAModComboItem); - } - // RIANT - // STVEF HACK - else if (g_pGameDescription->mGameFile == "stvef.game") - { - combo_list = g_list_append (combo_list, (void *)sSTVEFComboItem); - combo_list = g_list_append (combo_list, (void *)sSTVEFModComboItem); - } - // RIANT - // SOF2 HACK A LA JK2 A LA WOLF - else if (g_pGameDescription->mGameFile == "sof2.game") - { - combo_list = g_list_append (combo_list, (void *)sSOF2ComboItem); - combo_list = g_list_append (combo_list, (void *)sSOF2ModComboItem); - } - else - { - // Q3 or default - combo_list = g_list_append (combo_list, (void *)sQ3ComboItem); - combo_list = g_list_append (combo_list, (void *)sTAComboItem); - combo_list = g_list_append (combo_list, (void *)sModComboItem); - } - - game_select = gtk_combo_new (); - gtk_combo_set_popdown_strings (GTK_COMBO (game_select), combo_list); - gtk_widget_show (game_select); - gtk_table_attach (GTK_TABLE (table2), game_select, 1, 2, 6, 7, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - gtk_signal_connect (GTK_OBJECT(GTK_COMBO (game_select)->entry), "changed", - GTK_SIGNAL_FUNC (OnSelchangeComboWhatgame), NULL); - - g_list_free (combo_list); - gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (game_select)->entry), FALSE); - - game = gtk_entry_new(); - fsgame_entry = GTK_ENTRY(game); - gtk_widget_show(game); - gtk_table_attach(GTK_TABLE(table2), game, 1, 2, 7, 8, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - /* - wolf specific: select MP or SP mode - */ - if (g_pGameDescription->mGameFile == "wolf.game") - { - combo_list = NULL; - combo_list = g_list_append (combo_list, (void *)sWolfSPCombo); - combo_list = g_list_append (combo_list, (void *)sWolfMPCombo); - - gamemode_combo = gtk_combo_new (); - gtk_combo_set_popdown_strings (GTK_COMBO (gamemode_combo), combo_list); - gtk_widget_show(gamemode_combo); - gtk_table_attach (GTK_TABLE (table2), gamemode_combo, 1, 2, 8, 9, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - g_list_free (combo_list); - combo_list = NULL; - - label = gtk_label_new ("Mapping mode"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 8, 9, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - } - - // RIANT - // JK2 HACK - if (g_pGameDescription->mGameFile == "jk2.game") - { - combo_list = NULL; - combo_list = g_list_append (combo_list, (void *)sJK2SPCombo); - combo_list = g_list_append (combo_list, (void *)sJK2MPCombo); - - gamemode_combo = gtk_combo_new (); - gtk_combo_set_popdown_strings (GTK_COMBO (gamemode_combo), combo_list); - gtk_widget_show(gamemode_combo); - gtk_table_attach (GTK_TABLE (table2), gamemode_combo, 1, 2, 8, 9, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - g_list_free (combo_list); - combo_list = NULL; - - label = gtk_label_new ("Mapping mode"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 8, 9, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - } - // TTimo - // JA HACK - if (g_pGameDescription->mGameFile == "ja.game") - { - combo_list = NULL; - combo_list = g_list_append (combo_list, (void *)sJASPCombo); - combo_list = g_list_append (combo_list, (void *)sJAMPCombo); - - gamemode_combo = gtk_combo_new (); - gtk_combo_set_popdown_strings (GTK_COMBO (gamemode_combo), combo_list); - gtk_widget_show(gamemode_combo); - gtk_table_attach (GTK_TABLE (table2), gamemode_combo, 1, 2, 8, 9, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - g_list_free (combo_list); - combo_list = NULL; - - label = gtk_label_new ("Mapping mode"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 8, 9, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - } - // RIANT - // STVEF HACK - if (g_pGameDescription->mGameFile == "stvef.game") - { - combo_list = NULL; - combo_list = g_list_append (combo_list, (void *)sSTVEFSPCombo); - combo_list = g_list_append (combo_list, (void *)sSTVEFMPCombo); - - gamemode_combo = gtk_combo_new (); - gtk_combo_set_popdown_strings (GTK_COMBO (gamemode_combo), combo_list); - gtk_widget_show(gamemode_combo); - gtk_table_attach (GTK_TABLE (table2), gamemode_combo, 1, 2, 8, 9, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - g_list_free (combo_list); - combo_list = NULL; - - label = gtk_label_new ("Mapping mode"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 8, 9, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - } - // RIANT - // SOF2 HACK - if (g_pGameDescription->mGameFile == "sof2.game") - { - combo_list = NULL; - combo_list = g_list_append (combo_list, (void *)sSOF2SPCombo); - combo_list = g_list_append (combo_list, (void *)sSOF2MPCombo); - - gamemode_combo = gtk_combo_new (); - gtk_combo_set_popdown_strings (GTK_COMBO (gamemode_combo), combo_list); - gtk_widget_show(gamemode_combo); - gtk_table_attach (GTK_TABLE (table2), gamemode_combo, 1, 2, 8, 9, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - g_list_free (combo_list); - combo_list = NULL; - - label = gtk_label_new ("Mapping mode"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 8, 9, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - } - - /* - the usual stuff - */ - - base = gtk_entry_new (); - g_object_set_data (G_OBJECT (project), "base", base); - gtk_widget_show (base); - gtk_table_attach (GTK_TABLE (table2), base, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - - label = gtk_label_new ("basepath"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - - label = gtk_label_new ("Select mod"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 6, 7, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - label = gtk_label_new ("fs_game"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 7, 8, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - // Initialize fields - gtk_entry_set_text (GTK_ENTRY (base), ValueForKey (g_qeglobals.d_project_entity, "basepath")); - UpdateBSPCommandList (project); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (brush), (g_qeglobals.m_bBrushPrimitMode) ? TRUE : FALSE); - - // initialise the fs_game selection from the project settings into the dialog - const char *dir = ValueForKey (g_qeglobals.d_project_entity, "gamename"); - // HACK: hardcoded wolf stuff - if (g_pGameDescription->mGameFile == "wolf.game") - { - if ((strlen(dir) == 0) || !stricmp(dir,"main")) - { - // no fs_game set, we are running stock Quake III Arena editing - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sWolfComboItem); - gtk_entry_set_text (GTK_ENTRY (game), ""); - gtk_widget_set_sensitive(game, false); - } - else - { - // this is a custom mod - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sWolfModComboItem); - gtk_entry_set_text (GTK_ENTRY (game), dir); - gtk_widget_set_sensitive(game, true); - } - } - // HACK: hardcoded et stuff - if (g_pGameDescription->mGameFile == "et.game") - { - if ((strlen(dir) == 0) || !stricmp(dir,"etmain")) - { - // no fs_game set, we are running stock Quake III Arena editing - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sETComboItem); - gtk_entry_set_text (GTK_ENTRY (game), ""); - gtk_widget_set_sensitive(game, false); - } - else - { - // this is a custom mod - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sETModComboItem); - gtk_entry_set_text (GTK_ENTRY (game), dir); - gtk_widget_set_sensitive(game, true); - } - } - // HACK: hardcoded half-life stuff - else if (g_pGameDescription->mGameFile == "hl.game") - { - if ((strlen(dir) == 0) || !stricmp(dir,"valve")) - { - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sHLComboItem); - gtk_entry_set_text (GTK_ENTRY (game), ""); - gtk_widget_set_sensitive(game, false); - } - else - { - // this is a custom mod - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sHLModComboItem); - gtk_entry_set_text (GTK_ENTRY (game), dir); - gtk_widget_set_sensitive(game, true); - } - } - // RIANT - // JK2 HACK - else if (g_pGameDescription->mGameFile == "jk2.game") - { - if ((strlen(dir) == 0) || !stricmp(dir,"base")) - { - // no fs_game set, we are running stock Quake III Arena editing - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sJK2ComboItem); - gtk_entry_set_text (GTK_ENTRY (game), ""); - gtk_widget_set_sensitive(game, false); - } - else - { - // this is a custom mod - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sJK2ModComboItem); - gtk_entry_set_text (GTK_ENTRY (game), dir); - gtk_widget_set_sensitive(game, true); - } - } - // TTimo - // JA HACK - else if (g_pGameDescription->mGameFile == "ja.game") - { - if ((strlen(dir) == 0) || !stricmp(dir,"base")) - { - // no fs_game set, we are running stock editing - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sJAComboItem); - gtk_entry_set_text (GTK_ENTRY (game), ""); - gtk_widget_set_sensitive(game, false); - } - else - { - // this is a custom mod - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sJAModComboItem); - gtk_entry_set_text (GTK_ENTRY (game), dir); - gtk_widget_set_sensitive(game, true); - } - } - // RIANT - // STVEF2 HACK - else if (g_pGameDescription->mGameFile == "stvef.game") - { - if ((strlen(dir) == 0) || !stricmp(dir,"baseEf")) - { - // no fs_game set, we are running stock Quake III Arena editing - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sSTVEFComboItem); - gtk_entry_set_text (GTK_ENTRY (game), ""); - gtk_widget_set_sensitive(game, false); - } - else - { - // this is a custom mod - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sSTVEFModComboItem); - gtk_entry_set_text (GTK_ENTRY (game), dir); - gtk_widget_set_sensitive(game, true); - } - } - // RIANT - // SOF2 HACK - else if (g_pGameDescription->mGameFile == "sof2.game") - { - if ((strlen(dir) == 0) || !stricmp(dir,"base")) - { - // no fs_game set, we are running stock Quake III Arena editing - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sSOF2ComboItem); - gtk_entry_set_text (GTK_ENTRY (game), ""); - gtk_widget_set_sensitive(game, false); - } - else - { - // this is a custom mod - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sSOF2ModComboItem); - gtk_entry_set_text (GTK_ENTRY (game), dir); - gtk_widget_set_sensitive(game, true); - } - } - else - { - if ((strlen(dir) == 0) || !strcmp(dir,"baseq3")) - { - // no fs_game set, we are running stock Quake III Arena editing - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sQ3ComboItem); - gtk_entry_set_text (GTK_ENTRY (game), ""); - gtk_widget_set_sensitive(game, false); - } - else if (!strcmp(dir,"missionpack")) - { - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sTAComboItem); - gtk_entry_set_text (GTK_ENTRY (game), "missionpack"); - gtk_widget_set_sensitive(game, false); - } - else - { - // this is a custom mod - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sModComboItem); - gtk_entry_set_text (GTK_ENTRY (game), dir); - gtk_widget_set_sensitive(game, true); - } - } - - // HACK: hardcoded wolf stuff - if (g_pGameDescription->mGameFile == "wolf.game") - { - const char *gamemode = ValueForKey (g_qeglobals.d_project_entity, "gamemode"); - if ((strlen(gamemode) == 0) || !strcmp(gamemode,"sp")) - { - // nothing set yet, or single player - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sWolfSPCombo); - } - else - { - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sWolfMPCombo); - } - } - - // JK2 HACK - else if (g_pGameDescription->mGameFile == "jk2.game") - { - const char *gamemode = ValueForKey (g_qeglobals.d_project_entity, "gamemode"); - if ((strlen(gamemode) == 0) || !strcmp(gamemode,"sp")) - { - // nothing set yet, or single player - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sJK2SPCombo); - } - else - { - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sJK2MPCombo); - } - } - // JA HACK - else if (g_pGameDescription->mGameFile == "ja.game") - { - const char *gamemode = ValueForKey (g_qeglobals.d_project_entity, "gamemode"); - if ((strlen(gamemode) == 0) || !strcmp(gamemode,"sp")) - { - // nothing set yet, or single player - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sJASPCombo); - } - else - { - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sJAMPCombo); - } - } - // STVEF HACK - else if (g_pGameDescription->mGameFile == "stvef.game") - { - const char *gamemode = ValueForKey (g_qeglobals.d_project_entity, "gamemode"); - if ((strlen(gamemode) == 0) || !strcmp(gamemode,"sp")) - { - // nothing set yet, or single player - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sSTVEFSPCombo); - } - else - { - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sSTVEFMPCombo); - } - } - // SOF2 HACK - else if (g_pGameDescription->mGameFile == "sof2.game") - { - const char *gamemode = ValueForKey (g_qeglobals.d_project_entity, "gamemode"); - if ((strlen(gamemode) == 0) || !strcmp(gamemode,"sp")) - { - // nothing set yet, or single player - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sSOF2SPCombo); - } - else - { - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sSOF2MPCombo); - } - } - - gtk_grab_add (project); - gtk_widget_show (project); - - g_pGameDescription->Dump(); - - while (loop) - gtk_main_iteration (); - - if (ret == IDOK) - { - char buf[1024]; - const char *r; - char *w; - - // convert path to unix format - for(r = gtk_entry_get_text (GTK_ENTRY (base)), w=buf; *r != '\0'; r++, w++) - *w = (*r == '\\') ? '/' : *r; - // add last slash - if(w != buf && *(w-1) != '/') *(w++) = '/'; - // terminate string - *w = '\0'; - SetKeyValue (g_qeglobals.d_project_entity, "basepath", buf); - - dir = gtk_entry_get_text (GTK_ENTRY (game)); - // Hack: hard coded wolf stuff - if (g_pGameDescription->mGameFile == "wolf.game") - { - if (!strlen(dir) || !stricmp(dir,"main")) - { - DeleteKey (g_qeglobals.d_project_entity, "gamename"); - } - else - { - SetKeyValue (g_qeglobals.d_project_entity, "gamename", dir); - } - } - // Hack: hard coded ET stuff - else if (g_pGameDescription->mGameFile == "et.game") - { - if (!strlen(dir) || !stricmp(dir,"etmain")) - { - DeleteKey (g_qeglobals.d_project_entity, "gamename"); - } - else - { - SetKeyValue (g_qeglobals.d_project_entity, "gamename", dir); - } - } - // Hack: hard coded Half-life stuff - else if (g_pGameDescription->mGameFile == "hl.game") - { - if (!strlen(dir) || !stricmp(dir,"valve")) - { - DeleteKey (g_qeglobals.d_project_entity, "gamename"); - } - else - { - SetKeyValue (g_qeglobals.d_project_entity, "gamename", dir); - } - } - else if (g_pGameDescription->mGameFile == "jk2.game" || g_pGameDescription->mGameFile == "ja.game") - { - if (!strlen(dir) || !stricmp(dir,"base")) - { - DeleteKey (g_qeglobals.d_project_entity, "gamename"); - } - else - { - SetKeyValue (g_qeglobals.d_project_entity, "gamename", dir); - } - } - // RIANT - // STVEF HACK - else if (g_pGameDescription->mGameFile == "stvef.game") - { - if (!strlen(dir) || !stricmp(dir,"baseEf")) - { - DeleteKey (g_qeglobals.d_project_entity, "gamename"); - } - else - { - SetKeyValue (g_qeglobals.d_project_entity, "gamename", dir); - } - } - else - { - if (!strlen(dir) || !strcmp(dir,"baseq3")) - { - DeleteKey (g_qeglobals.d_project_entity, "gamename"); - } - else - { - SetKeyValue (g_qeglobals.d_project_entity, "gamename", dir); - } - } - - // HACK: hardcoded wolf stuff - if (g_pGameDescription->mGameFile == "wolf.game") - { - // read from gamemode_combo - const char *gamemode = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO(gamemode_combo)->entry)); - if (!strlen(gamemode) || !strcmp(gamemode, sWolfSPCombo)) - { - SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "sp"); - } - else - { - SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "mp"); - } - } - - // RIANT - // JK2 HACK - if (g_pGameDescription->mGameFile == "jk2.game") - { - // read from gamemode_combo - const char *gamemode = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO(gamemode_combo)->entry)); - if (!strlen(gamemode) || !strcmp(gamemode, sJK2SPCombo)) - { - SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "sp"); - } - else - { - SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "mp"); - } - } - // TTimo - // JA HACK - if (g_pGameDescription->mGameFile == "ja.game") - { - // read from gamemode_combo - const char *gamemode = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO(gamemode_combo)->entry)); - if (!strlen(gamemode) || !strcmp(gamemode, sJASPCombo)) - { - SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "sp"); - } - else - { - SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "mp"); - } - } - - // RIANT - // STVEF HACK - if (g_pGameDescription->mGameFile == "stvef.game") - { - // read from gamemode_combo - const char *gamemode = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO(gamemode_combo)->entry)); - if (!strlen(gamemode) || !strcmp(gamemode, sSTVEFSPCombo)) - { - SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "sp"); - } - else - { - SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "mp"); - } - } - - g_qeglobals.m_strHomeMaps = g_qeglobals.m_strHomeGame; - const char* str = ValueForKey(g_qeglobals.d_project_entity, "gamename"); - if(str[0] == '\0') str = g_pGameDescription->mBaseGame.GetBuffer(); - g_qeglobals.m_strHomeMaps += str; - g_qeglobals.m_strHomeMaps += '/'; - - // RIANT - // SOF2 HACK - if (g_pGameDescription->mGameFile == "sof2.game") - { - // read from gamemode_combo - const char *gamemode = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO(gamemode_combo)->entry)); - if (!strlen(gamemode) || !strcmp(gamemode, sSOF2SPCombo)) - { - SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "sp"); - } - else - { - SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "mp"); - } - } - - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (brush))) - g_qeglobals.m_bBrushPrimitMode = TRUE; - else - g_qeglobals.m_bBrushPrimitMode = FALSE; - - SetKeyValue(g_qeglobals.d_project_entity, "brush_primit", (g_qeglobals.m_bBrushPrimitMode ? "1" : "0" )); - -// QE_CheckProjectEntity(); - - QE_SaveProject( g_PrefsDlg.m_strLastProject.GetBuffer() ); - } - - gtk_grab_remove (project); - gtk_widget_destroy (project); -} - -// ============================================================================= -// MapInfo dialog - -void DoMapInfo () -{ - static GtkWidget *dlg; - GtkWidget *vbox, *vbox2, *hbox, *table, *button, *label, *scr; - GtkWidget *brushes_entry, *entities_entry, *net_entry; - int loop = 1, ret = IDCANCEL; - - if (dlg != NULL) - return; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - - load_window_pos(dlg, g_PrefsDlg.mWindowInfo.posMapInfoWnd); - - gtk_window_set_title (GTK_WINDOW (dlg), "Map Info"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_container_add (GTK_CONTAINER (dlg), vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); - - table = gtk_table_new (3, 2, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - brushes_entry = gtk_entry_new (); - gtk_widget_show (brushes_entry); - gtk_table_attach (GTK_TABLE (table), brushes_entry, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_entry_set_editable (GTK_ENTRY (brushes_entry), FALSE); - - entities_entry = gtk_entry_new (); - gtk_widget_show (entities_entry); - gtk_table_attach (GTK_TABLE (table), entities_entry, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_entry_set_editable (GTK_ENTRY (entities_entry), FALSE); - - net_entry = gtk_entry_new (); - gtk_widget_show (net_entry); - gtk_table_attach (GTK_TABLE (table), net_entry, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_entry_set_editable (GTK_ENTRY (net_entry), FALSE); - - label = gtk_label_new ("Total Brushes"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - label = gtk_label_new ("Total Entities"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - label = gtk_label_new ("Net brush count\n(non entity)"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - vbox2 = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox2); - gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0); - - button = gtk_button_new_with_label ("Close"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - label = gtk_label_new ("Entity breakdown"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - scr = gtk_scrolled_window_new ((GtkAdjustment*)NULL, (GtkAdjustment*)NULL); - gtk_widget_show (scr); - gtk_box_pack_start (GTK_BOX (vbox), scr, TRUE, TRUE, 0); - gtk_container_set_border_width (GTK_CONTAINER (scr), 5); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scr), GTK_SHADOW_IN); - - GtkListStore* store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); - - { - GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); - gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(view), TRUE); - - { - GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); - GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Entity", renderer, "text", 0, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); - gtk_tree_view_column_set_sort_column_id(column, 0); - } - - { - GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); - GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Count", renderer, "text", 1, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); - gtk_tree_view_column_set_sort_column_id(column, 1); - } - - gtk_widget_show(view); - - gtk_container_add(GTK_CONTAINER (scr), view); - } - - // Initialize fields - int TotalBrushes = 0, TotalEntities = 0, Net = 0; - - for (brush_t* pBrush = active_brushes.next; pBrush != &active_brushes; pBrush = pBrush->next) - { - TotalBrushes++; - if (pBrush->owner == world_entity) - Net++; - } - - typedef struct - { - const char *name; - int count; - } map_t; - - GSList *l, *entitymap = NULL; - map_t *entry; - - for (entity_t* pEntity = entities.next; pEntity != &entities; pEntity=pEntity->next) - { - TotalEntities++; - bool add = true; - - for (l = entitymap; l; l = g_slist_next (l)) - { - entry = (map_t*)l->data; - - if (strcmp (entry->name, pEntity->eclass->name) == 0) - { - entry->count++; - add = false; - break; - } - } - - if (add) - { - entry = (map_t*)qmalloc (sizeof (map_t)); - entry->name = pEntity->eclass->name; - entry->count = 1; - entitymap = g_slist_append (entitymap, entry); - } - } - - while (entitymap) - { - entry = (map_t*)entitymap->data; - char tmp[16]; - sprintf (tmp, "%d", entry->count); - GtkTreeIter iter; - gtk_list_store_append(GTK_LIST_STORE(store), &iter); - gtk_list_store_set(GTK_LIST_STORE(store), &iter, 0, entry->name, 1, tmp, -1); - free (entry); - entitymap = g_slist_remove (entitymap, entry); - } - - g_object_unref(G_OBJECT(store)); - - char tmp[16]; - sprintf (tmp, "%d", TotalBrushes); - gtk_entry_set_text (GTK_ENTRY (brushes_entry), tmp); - sprintf (tmp, "%d", TotalEntities); - gtk_entry_set_text (GTK_ENTRY (entities_entry), tmp); - sprintf (tmp, "%d", Net); - gtk_entry_set_text (GTK_ENTRY (net_entry), tmp); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - // save before exit - save_window_pos(dlg, g_PrefsDlg.mWindowInfo.posMapInfoWnd); - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); - dlg = NULL; -} - -// ============================================================================= -// Entity List dialog - -static void entitylist_select (GtkWidget *widget, gpointer data) -{ - GtkTreeView* view = GTK_TREE_VIEW(g_object_get_data (G_OBJECT (data), "entities")); - - GtkTreeSelection* selection = gtk_tree_view_get_selection(view); - - GtkTreeModel* model; - GtkTreeIter selected; - if(gtk_tree_selection_get_selected(selection, &model, &selected)) - { - entity_t* pEntity; - gtk_tree_model_get(model, &selected, 1, &pEntity, -1); - - if (pEntity) - { - for (epair_t* pEpair = pEntity->epairs; pEpair; pEpair = pEpair->next) - { - Select_Deselect (); - Select_Brush (pEntity->brushes.onext); - Sys_UpdateWindows(W_ALL); - } - } - } -} - -static gint entitylist_click (GtkWidget *widget, GdkEventButton *event, gpointer data) -{ - if (event->type == GDK_2BUTTON_PRESS) - { - entitylist_select (NULL, data); - return TRUE; - } - return FALSE; -} - -static void entitylist_selection_changed(GtkTreeSelection* selection, gpointer data) -{ - GtkListStore* store = GTK_LIST_STORE (g_object_get_data (G_OBJECT (data), "keyvalues")); - - gtk_list_store_clear(store); - - GtkTreeModel* model; - GtkTreeIter selected; - if(gtk_tree_selection_get_selected(selection, &model, &selected)) - { - entity_t* pEntity; - gtk_tree_model_get(model, &selected, 1, &pEntity, -1); - - if (pEntity) - { - for (epair_t* pEpair = pEntity->epairs; pEpair; pEpair = pEpair->next) - { - GtkTreeIter appended; - gtk_list_store_append(store, &appended); - gtk_list_store_set(store, &appended, 0, pEpair->key, 1, pEpair->value, -1); - } - } - } -} - -void DoEntityList () -{ - static GtkWidget *dlg; - GtkWidget *vbox, *hbox, *hbox2, *button, *scr; - int loop = 1, ret = IDCANCEL; - - if (dlg != NULL) - return; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - - load_window_pos (dlg, g_PrefsDlg.mWindowInfo.posEntityInfoWnd); - - gtk_window_set_title (GTK_WINDOW (dlg), "Entities"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - hbox = gtk_hbox_new (TRUE, 5); - gtk_widget_show (hbox); - gtk_container_add (GTK_CONTAINER (dlg), hbox); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - - scr = gtk_scrolled_window_new ((GtkAdjustment*)NULL, (GtkAdjustment*)NULL); - gtk_widget_show (scr); - gtk_box_pack_start (GTK_BOX (hbox), scr, TRUE, TRUE, 0); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); - - { - GtkTreeStore* store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER); - - GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); - g_signal_connect(G_OBJECT(view), "button_press_event", G_CALLBACK(entitylist_click), dlg); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); - - { - GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); - GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); - } - - { - GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); - g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(entitylist_selection_changed), dlg); - } - - gtk_widget_show(view); - - gtk_container_add(GTK_CONTAINER (scr), view); - g_object_set_data (G_OBJECT (dlg), "entities", view); - - { - { - GtkTreeIter child; - gtk_tree_store_append(store, &child, NULL); - gtk_tree_store_set(store, &child, 0, world_entity->eclass->name, 1, world_entity, -1); - } - - GSList *l, *entitymap = NULL; - typedef struct - { - GtkTreeIter node; - const char *name; - } map_t; - map_t *entry; - - for (entity_t* pEntity=entities.next; pEntity != &entities; pEntity=pEntity->next) - { - GtkTreeIter parent; - bool found = false; - - for (l = entitymap; l; l = g_slist_next (l)) - { - entry = (map_t*)l->data; - - if (strcmp (entry->name, pEntity->eclass->name) == 0) - { - parent = entry->node; - found = true; - break; - } - } - - if (!found) - { - gtk_tree_store_append(store, &parent, NULL); - gtk_tree_store_set(store, &parent, 0, pEntity->eclass->name, 1, NULL, -1); - - entry = (map_t*)malloc (sizeof(map_t)); - entitymap = g_slist_append (entitymap, entry); - entry->name = pEntity->eclass->name; - entry->node = parent; - } - - GtkTreeIter child; - gtk_tree_store_append(store, &child, &parent); - gtk_tree_store_set(store, &child, 0, pEntity->eclass->name, 1, pEntity, -1); - } - - while (entitymap) - { - free (entitymap->data); - entitymap = g_slist_remove (entitymap, entitymap->data); - } - } - - g_object_unref(G_OBJECT(store)); - } - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); - - scr = gtk_scrolled_window_new ((GtkAdjustment*)NULL, (GtkAdjustment*)NULL); - gtk_widget_show (scr); - gtk_box_pack_start (GTK_BOX (vbox), scr, TRUE, TRUE, 0); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); - - { - GtkListStore* store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); - - GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); - - { - GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); - GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Key", renderer, "text", 0, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); - } - - { - GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); - GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Value", renderer, "text", 1, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); - } - - gtk_widget_show(view); - - g_object_set_data(G_OBJECT(dlg), "keyvalues", store); - gtk_container_add(GTK_CONTAINER (scr), view); - - g_object_unref(G_OBJECT(store)); - } - - hbox2 = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox2); - gtk_box_pack_start (GTK_BOX (vbox), hbox2, TRUE, TRUE, 0); - - button = gtk_button_new_with_label ("Select"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (entitylist_select), dlg); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Close"); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (hbox2), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - save_window_pos (dlg, g_PrefsDlg.mWindowInfo.posMapInfoWnd); - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); - - dlg = NULL; -} - -// ============================================================================= -// Rotate dialog - -static void rotatedlg_apply (GtkWidget *widget, gpointer data) -{ - GtkSpinButton *spin; - float f; - - spin = GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (data), "x")); - f = gtk_spin_button_get_value_as_float (spin); - if (f != 0.0) - Select_RotateAxis(0,f); - gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin), 0.0f); // reset to 0 on Apply - - spin = GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (data), "y")); - f = gtk_spin_button_get_value_as_float (spin); - if (f != 0.0) - Select_RotateAxis(1,f); - gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin), 0.0f); - - spin = GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (data), "z")); - f = gtk_spin_button_get_value_as_float (spin); - if (f != 0.0) - Select_RotateAxis(2,f); - gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin), 0.0f); -} - -void DoRotateDlg () -{ - GtkWidget *dlg, *hbox, *vbox, *table, *label, *button; - GtkWidget *x, *y, *z; - GtkObject *adj; - int loop = 1, ret = IDCANCEL; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "Arbitrary rotation"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_container_add (GTK_CONTAINER (dlg), hbox); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - - table = gtk_table_new (3, 2, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new (" X "); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - label = gtk_label_new (" Y "); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - label = gtk_label_new (" Z "); - - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - adj = gtk_adjustment_new (0, -359, 359, 1, 10, 10); - x = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); - g_object_set_data (G_OBJECT (dlg), "x", x); - gtk_widget_show (x); - gtk_table_attach (GTK_TABLE (table), x, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (x, 60, -2); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (x), TRUE); - - adj = gtk_adjustment_new (0, -359, 359, 1, 10, 10); - y = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); - g_object_set_data (G_OBJECT (dlg), "y", y); - gtk_widget_show (y); - gtk_table_attach (GTK_TABLE (table), y, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (y), TRUE); - - adj = gtk_adjustment_new (0, -359, 359, 1, 10, 10); - z = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); - g_object_set_data (G_OBJECT (dlg), "z", z); - gtk_widget_show (z); - gtk_table_attach (GTK_TABLE (table), z, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (z), TRUE); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Cancel"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - - button = gtk_button_new_with_label ("Apply"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (rotatedlg_apply), dlg); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - if (ret == IDOK) - rotatedlg_apply (button, dlg); - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); -} - -// ============================================================================= -// Gamma dialog - -void DoGamma () -{ - GtkWidget *dlg, *vbox, *hbox, *label, *button, *entry; - int loop = 1, ret = IDCANCEL; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "Gamma"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_container_add (GTK_CONTAINER (dlg), hbox); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0); - - label = gtk_label_new ("0.0 is brightest\n1.0 is darkest"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); - - label = gtk_label_new ("You must restart for the\nsettings to take effect"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Cancel"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - - // Initialize dialog - char buf[16]; - sprintf (buf, "%1.1f", g_qeglobals.d_savedinfo.fGamma); - gtk_entry_set_text (GTK_ENTRY (entry), buf); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - if (ret == IDOK) - g_qeglobals.d_savedinfo.fGamma = g_strtod (gtk_entry_get_text (GTK_ENTRY (entry)), NULL); - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); -} - -// ============================================================================= -// Find Brush Dialog - -// helper function to walk through the active brushes only and drop the regioned out ones -bool WalkRegionBrush (brush_t **b, entity_t *e) -{ - brush_t *b2; - do - { - for(b2=active_brushes.next ; b2 != &active_brushes ; b2=b2->next) - { - if (b2==*b) - break; // this is an active brush - } - if (b2==&active_brushes) - { - // this is a regioned out brush - *b = (*b)->onext; - if (*b == &e->brushes) - { - Sys_Status ("No such brush", 0); - return false; - } - } - } while (b2==&active_brushes); - return true; -} - -void SelectBrush (int entitynum, int brushnum) -{ - entity_t *e; - brush_t *b; - int i; - - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=503 - // making this work when regioning is on too - - if (entitynum == 0) - e = world_entity; - else - { - e = entities.next; - while (--entitynum) - { - e = e->next; - if (e == &entities) - { - Sys_Status ("No such entity", 0); - return; - } - if (region_active) - { - // we need to make sure we walk to the next 'active' entity to have a valid --entitynum - // that is, find a brush that belongs to this entity in the active brushes - do - { - for (b = active_brushes.next ; b != &active_brushes ; b=b->next) - { - if (b->owner == e) - break; // this is an active entity - } - if (b==&active_brushes) - { - // this is a regioned out entity - e = e->next; - // don't walk past the end either - if (e == &entities) - { - Sys_Status ("No such entity", 0); - return; - } - } - } while(b==&active_brushes); - } - } - } - - b = e->brushes.onext; - if (b == &e->brushes) - { - Sys_Status ("No such brush", 0); - return; - } - if (region_active) - { - if (!WalkRegionBrush(&b, e)) - return; - } - - while (brushnum--) - { - b = b->onext; - if (b == &e->brushes) - { - Sys_Status ("No such brush", 0); - return; - } - if (region_active) - { - if (!WalkRegionBrush(&b, e)) - return; - } - } - - Brush_RemoveFromList (b); - Brush_AddToList (b, &selected_brushes); - - Sys_UpdateWindows (W_ALL); - for (i = 0; i < 3; i++) - { - if (g_pParentWnd->GetXYWnd()) - g_pParentWnd->GetXYWnd()->GetOrigin()[i] = (b->mins[i] + b->maxs[i])/2; - - if (g_pParentWnd->GetXZWnd()) - g_pParentWnd->GetXZWnd()->GetOrigin()[i] = (b->mins[i] + b->maxs[i])/2; - - if (g_pParentWnd->GetYZWnd()) - g_pParentWnd->GetYZWnd()->GetOrigin()[i] = (b->mins[i] + b->maxs[i])/2; - } - - Sys_Status ("Selected", 0); -} - -static void GetSelectionIndex (int *ent, int *brush) -{ - brush_t *b, *b2; - entity_t *entity; - - *ent = *brush = 0; - - b = selected_brushes.next; - if (b == &selected_brushes) - return; - - // find entity - if (b->owner != world_entity) - { - (*ent)++; - for (entity = entities.next; entity != &entities; entity=entity->next, (*ent)++) - ; - } - - // find brush - for (b2=b->owner->brushes.onext; b2 != b && b2 != &b->owner->brushes; b2=b2->onext, (*brush)++) - ; -} - -void DoFind () -{ - GtkWidget *dlg, *vbox, *hbox, *table, *label, *button, *entity, *brush; - int loop = 1, ret = IDCANCEL; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "Find Brush"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_container_add (GTK_CONTAINER (dlg), vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - - table = gtk_table_new (2, 2, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("Entity number"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - label = gtk_label_new ("Brush number"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - entity = gtk_entry_new (); - gtk_widget_show (entity); - gtk_table_attach (GTK_TABLE (table), entity, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - brush = gtk_entry_new (); - gtk_widget_show (brush); - gtk_table_attach (GTK_TABLE (table), brush, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Cancel"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - - // Initialize dialog - char buf[16]; - int ent, br; - - GetSelectionIndex (&ent, &br); - sprintf (buf, "%i", ent); - gtk_entry_set_text (GTK_ENTRY (entity), buf); - sprintf (buf, "%i", br); - gtk_entry_set_text (GTK_ENTRY (brush), buf); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - if (ret == IDOK) - { - const char *entstr = gtk_entry_get_text (GTK_ENTRY (entity)); - const char *brushstr = gtk_entry_get_text (GTK_ENTRY (brush)); - SelectBrush (atoi(entstr), atoi(brushstr)); - } - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); -} - -// ============================================================================= -// Arbitrary Sides dialog - -void DoSides (bool bCone, bool bSphere, bool bTorus) -{ - GtkWidget *dlg, *vbox, *hbox, *button, *label, *entry; - int loop = 1, ret = IDCANCEL; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "Arbitrary sides"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_container_add (GTK_CONTAINER (dlg), hbox); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - - label = gtk_label_new ("Sides:"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, TRUE, 0); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Cancel"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - if (ret == IDOK) - { - const char *str = gtk_entry_get_text (GTK_ENTRY (entry)); - - if (bCone) - Brush_MakeSidedCone(atoi(str)); - else if (bSphere) - Brush_MakeSidedSphere(atoi(str)); - else - Brush_MakeSided (atoi(str)); - } - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); -} - -// ============================================================================= -// New Patch dialog - -void DoNewPatchDlg () -{ - GtkWidget *dlg, *hbox, *table, *vbox, *label, *button, *combo; - GtkWidget *width, *height; - GList *combo_list = (GList*)NULL; - int loop = 1, ret = IDCANCEL; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "Patch density"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_container_add (GTK_CONTAINER (dlg), hbox); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - - table = gtk_table_new (2, 2, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("Width:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - label = gtk_label_new ("Height:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - combo_list = g_list_append (combo_list, (void *)"3"); - combo_list = g_list_append (combo_list, (void *)"5"); - combo_list = g_list_append (combo_list, (void *)"7"); - combo_list = g_list_append (combo_list, (void *)"9"); - combo_list = g_list_append (combo_list, (void *)"11"); - combo_list = g_list_append (combo_list, (void *)"13"); - combo_list = g_list_append (combo_list, (void *)"15"); - - combo = gtk_combo_new (); - width = GTK_COMBO (combo)->entry; - gtk_combo_set_popdown_strings (GTK_COMBO (combo), combo_list); - gtk_widget_show (combo); - gtk_table_attach (GTK_TABLE (table), combo, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - combo = gtk_combo_new (); - height = GTK_COMBO (combo)->entry; - gtk_combo_set_popdown_strings (GTK_COMBO (combo), combo_list); - gtk_widget_show (combo); - gtk_table_attach (GTK_TABLE (table), combo, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Cancel"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - - // Initialize dialog - g_list_free (combo_list); - gtk_entry_set_text (GTK_ENTRY (width), "3"); - gtk_entry_set_editable (GTK_ENTRY (width), FALSE); - gtk_entry_set_text (GTK_ENTRY (height), "3"); - gtk_entry_set_editable (GTK_ENTRY (height), FALSE); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - if (ret == IDOK) - { - const char* w = gtk_entry_get_text (GTK_ENTRY (width)); - const char* h = gtk_entry_get_text (GTK_ENTRY (height)); - - Patch_GenericMesh(atoi (w), atoi (h), g_pParentWnd->ActiveXY ()->GetViewType ()); - Sys_UpdateWindows (W_ALL); - } - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); -} - -// ============================================================================= -// New Patch dialog - -void DoScaleDlg () -{ - GtkWidget *dlg, *hbox, *table, *vbox, *label, *button; - GtkWidget *x, *y, *z; - int loop = 1, ret = IDCANCEL; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "Scale"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_container_add (GTK_CONTAINER (dlg), hbox); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - - table = gtk_table_new (3, 2, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("X:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - label = gtk_label_new ("Y:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - label = gtk_label_new ("Z:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - x = gtk_entry_new (); - gtk_widget_show (x); - gtk_table_attach (GTK_TABLE (table), x, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - y = gtk_entry_new (); - gtk_widget_show (y); - gtk_table_attach (GTK_TABLE (table), y, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - z = gtk_entry_new (); - gtk_widget_show (z); - gtk_table_attach (GTK_TABLE (table), z, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Cancel"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - - // Initialize dialog - gtk_entry_set_text (GTK_ENTRY (x), "1.0"); - gtk_entry_set_text (GTK_ENTRY (y), "1.0"); - gtk_entry_set_text (GTK_ENTRY (z), "1.0"); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - if (ret == IDOK) - { - float sx, sy, sz; - sx = atof (gtk_entry_get_text (GTK_ENTRY (x))); - sy = atof (gtk_entry_get_text (GTK_ENTRY (y))); - sz = atof (gtk_entry_get_text (GTK_ENTRY (z))); - - if (sx > 0 && sy > 0 && sz > 0) - { - Select_Scale(sx, sy, sz); - Sys_UpdateWindows (W_ALL); - } - else - Sys_Printf("Warning.. Tried to scale by a zero value."); - } - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); -} - -// ============================================================================= -// Thicken Patch dialog - -void DoThickenDlg () -{ - GtkWidget *dlg, *vbox, *hbox, *vbox2, *button, *label; - GtkWidget *amount, *seams, *group; - int loop = 1, ret = IDCANCEL; - static qboolean bGroupResult = true; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "Thicken Patch"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_container_add (GTK_CONTAINER (dlg), vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); - - label = gtk_label_new ("This produces a set of patches\n" - "that contains the original patch along with the\n" - "'thick' patch and an optimal set of seam patches."); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - - vbox2 = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox2); - gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, TRUE, 0); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Cancel"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); - - label = gtk_label_new ("Amount:"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - - amount = gtk_entry_new (); - gtk_widget_show (amount); - gtk_box_pack_start (GTK_BOX (hbox), amount, FALSE, FALSE, 0); - - seams = gtk_check_button_new_with_label ("Seams"); - gtk_widget_show (seams); - gtk_box_pack_start (GTK_BOX (hbox), seams, FALSE, FALSE, 0); - - // bGroupResult - group = gtk_check_button_new_with_label("Result to func_group"); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(group), bGroupResult); - gtk_box_pack_start(GTK_BOX(vbox), group, FALSE, FALSE, 0); - gtk_widget_show(group); - - - // Initialize dialog - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (seams), TRUE); - gtk_entry_set_text (GTK_ENTRY (amount), "8"); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - if (ret == IDOK) - { - if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(group))) - bGroupResult = true; - else - bGroupResult = false; - Patch_Thicken (atoi (gtk_entry_get_text (GTK_ENTRY (amount))), - gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (seams)), bGroupResult); - Sys_UpdateWindows (W_ALL); - } - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); -} - -// ============================================================================= -// About dialog (no program is complete without one) - -void about_button_changelog (GtkWidget *widget, gpointer data) -{ - Str log; - log = g_strAppPath; - log += "changelog.txt"; - OpenURL(log.GetBuffer()); -} - -void about_button_credits (GtkWidget *widget, gpointer data) -{ - Str cred; - cred = g_strAppPath; - cred += "credits.html"; - OpenURL(cred.GetBuffer()); -} - -void DoAbout () -{ - GtkWidget *dlg, *vbox, *vbox2, *hbox, *frame, *table, *label, *pixmap, *button, *sc_extensions, *text_extensions; - int loop = 1, ret = IDCANCEL; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "About GtkRadiant"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - vbox = gtk_vbox_new (FALSE, 10); - gtk_widget_show (vbox); - gtk_container_add (GTK_CONTAINER (dlg), vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); - - vbox2 = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox2); - gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, FALSE, 0); - - frame = gtk_frame_new ((char*)NULL); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (vbox2), frame, FALSE, FALSE, 0); - gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); - - pixmap = new_pixmap (g_pParentWnd->m_pWidget, "logo.bmp"); - gtk_widget_show (pixmap); - gtk_container_add (GTK_CONTAINER (frame), pixmap); - - label = gtk_label_new ("GtkRadiant " RADIANT_VERSION "\n" - __DATE__ "\n\n" - RADIANT_ABOUTMSG "\n\n" - "By qeradiant.com\n\n" - "This product contains software technology\n" - "from id Software, Inc. ('id Technology').\n" - "id Technology 2000 id Software,Inc.\n\n" - "GtkRadiant is unsupported, however\n" - "you may report your problems at\n" - "http://zerowing.idsoftware.com/bugzilla" - ); - - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - - vbox2 = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox2); - gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, TRUE, 0); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - - button = gtk_button_new_with_label ("Credits"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (about_button_credits), NULL); - - button = gtk_button_new_with_label ("Changelog"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (about_button_changelog), NULL); - - frame = gtk_frame_new ("OpenGL Properties"); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0); - - table = gtk_table_new (3, 2, FALSE); - gtk_widget_show (table); - gtk_container_add (GTK_CONTAINER (frame), table); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - gtk_container_set_border_width (GTK_CONTAINER (table), 5); - - label = gtk_label_new ("Vendor:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - label = gtk_label_new ("Version:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - label = gtk_label_new ("Renderer:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - label = gtk_label_new ((char*)qglGetString (GL_VENDOR)); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - label = gtk_label_new ((char*)qglGetString (GL_VERSION)); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - label = gtk_label_new ((char*)qglGetString (GL_RENDERER)); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - frame = gtk_frame_new ("OpenGL Extensions"); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_container_add (GTK_CONTAINER (frame), hbox); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - - sc_extensions = gtk_scrolled_window_new(NULL, NULL); - gtk_box_pack_start(GTK_BOX(hbox), sc_extensions, TRUE, TRUE, 0); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sc_extensions), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sc_extensions), GTK_SHADOW_IN); - gtk_widget_show(sc_extensions); - - text_extensions = gtk_text_view_new(); - gtk_text_view_set_editable(GTK_TEXT_VIEW(text_extensions), FALSE); - gtk_container_add (GTK_CONTAINER (sc_extensions), text_extensions); - GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_extensions)); - gtk_text_buffer_set_text(buffer, (char *)qglGetString(GL_EXTENSIONS), -1); - gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text_extensions), GTK_WRAP_WORD);; - gtk_widget_show(text_extensions); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); -} - -// ============================================================================= -// Command List dialog - -void DoCommandListDlg () -{ - GtkWidget *dlg, *vbox, *hbox, *scr, *button; - int loop = 1, ret = IDCANCEL; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "Mapped Commands"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - gtk_window_set_default_size (GTK_WINDOW (dlg), 400, 400); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_container_add (GTK_CONTAINER (dlg), hbox); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - - scr = gtk_scrolled_window_new ((GtkAdjustment*)NULL, (GtkAdjustment*)NULL); - gtk_widget_show (scr); - gtk_box_pack_start (GTK_BOX (hbox), scr, TRUE, TRUE, 0); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scr), GTK_SHADOW_IN); - - { - GtkListStore* store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); - - GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); - - { - GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); - GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Command", renderer, "text", 0, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); - } - - { - GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); - GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Key", renderer, "text", 1, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); - } - - gtk_widget_show(view); - gtk_container_add(GTK_CONTAINER (scr), view); - - { - // Initialize dialog - CString path; - path = g_strTempPath; - path += "commandlist.txt"; - - GSList *cmds = NULL; - int n; - - for (n = 0; n < g_nCommandCount; n++) - cmds = g_slist_append (cmds, g_Commands[n].m_strCommand); - cmds = g_slist_sort (cmds, (gint (*)(const void *, const void *))strcmp); - - Sys_Printf("Writing the command list to %s", path.GetBuffer() ); - FILE* fileout = fopen (path.GetBuffer (), "wt"); - - while (cmds) - { - for (n = 0; n < g_nCommandCount; n++) - if (cmds->data == g_Commands[n].m_strCommand) - break; - - char c = g_Commands[n].m_nKey; - CString strLine, strMod(""), strKeys (c); - - for (int k = 0; k < g_nKeyCount; k++) - { - if (g_Keys[k].m_nVKKey == g_Commands[n].m_nKey) - { - strKeys = g_Keys[k].m_strName; - break; - } - } - - if (g_Commands[n].m_nModifiers & RAD_SHIFT) - strMod = "Shift"; - if (g_Commands[n].m_nModifiers & RAD_ALT) - strMod += (strMod.GetLength() > 0) ? " + Alt" : "Alt"; - if (g_Commands[n].m_nModifiers & RAD_CONTROL) - strMod += (strMod.GetLength() > 0) ? " + Control" : "Control"; - if (strMod.GetLength() > 0) - strMod += " + "; - strMod += strKeys; - - { - GtkTreeIter iter; - gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, 0, g_Commands[n].m_strCommand, 1, strMod.GetBuffer (), -1); - } - - if (fileout != NULL) - { - strLine.Format("%-25s %s\r\n", g_Commands[n].m_strCommand, strMod.GetBuffer ()); - fputs (strLine.GetBuffer (), fileout); - } - - cmds = g_slist_remove (cmds, cmds->data); - } - - if (fileout != NULL) - fclose (fileout); - } - - g_object_unref(G_OBJECT(store)); - } - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); - - button = gtk_button_new_with_label ("Close"); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); -} - -// ============================================================================= -// Texture List dialog - -void DoTextureListDlg () -{ - GtkWidget *dlg, *vbox, *hbox, *scr, *button; - int loop = 1, ret = IDCANCEL; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "Textures"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - gtk_window_set_default_size (GTK_WINDOW (dlg), 400, 400); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_container_add (GTK_CONTAINER (dlg), hbox); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - - scr = gtk_scrolled_window_new ((GtkAdjustment*)NULL, (GtkAdjustment*)NULL); - gtk_widget_show (scr); - gtk_box_pack_start (GTK_BOX (hbox), scr, TRUE, TRUE, 0); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scr), GTK_SHADOW_IN); - - GtkWidget* texture_list; - - { - GtkListStore* store = gtk_list_store_new(1, G_TYPE_STRING); - - GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); - - { - GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); - GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); - } - - gtk_widget_show(view); - gtk_container_add(GTK_CONTAINER (scr), view); - - { - // Initialize dialog - GSList *textures = (GSList*)NULL; - FillTextureMenu(&textures); - while (textures != NULL) - { - { - GtkTreeIter iter; - gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, 0, (gchar*)textures->data, -1); - } - free (textures->data); - textures = g_slist_remove (textures, textures->data); - } - } - - g_object_unref(G_OBJECT(store)); - - texture_list = view; - } - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); - - button = gtk_button_new_with_label ("Load"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Close"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_set_usize (button, 60, -2); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - if (ret == IDOK) - { - GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(texture_list)); - - GtkTreeModel* model; - GtkTreeIter iter; - if(gtk_tree_selection_get_selected(selection, &model, &iter)) - { - GtkTreePath* path = gtk_tree_model_get_path(model, &iter); - if(gtk_tree_path_get_depth(path) == 1) - Texture_ShowDirectory(gtk_tree_path_get_indices(path)[0] + CMD_TEXTUREWAD); - gtk_tree_path_free(path); - } - } - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); -} - -// ============================================================================= -// Cap dialog - -int DoCapDlg (int *type, bool *b_GroupResult) -{ - GtkWidget *dlg, *vbox, *hbox, *table, *pixmap, *button, *group_toggle, *radio_vbox; - GtkWidget *bevel, *endcap, *ibevel, *iendcap; - GSList *group = (GSList*)NULL; - int loop = 1, ret = IDCANCEL; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "Cap"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_container_add (GTK_CONTAINER (dlg), hbox); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - - // Gef: Added a vbox to contain the toggle buttons - radio_vbox = gtk_vbox_new(FALSE, 4); - gtk_container_add(GTK_CONTAINER(hbox), radio_vbox); - gtk_widget_show(radio_vbox); - - table = gtk_table_new (4, 2, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (radio_vbox), table, TRUE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - pixmap = new_pixmap (g_pParentWnd->m_pWidget, "cap_bevel.bmp"); - gtk_widget_show (pixmap); - gtk_table_attach (GTK_TABLE (table), pixmap, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - pixmap = new_pixmap (g_pParentWnd->m_pWidget, "cap_endcap.bmp"); - gtk_widget_show (pixmap); - gtk_table_attach (GTK_TABLE (table), pixmap, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - pixmap = new_pixmap (g_pParentWnd->m_pWidget, "cap_ibevel.bmp"); - gtk_widget_show (pixmap); - gtk_table_attach (GTK_TABLE (table), pixmap, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - pixmap = new_pixmap (g_pParentWnd->m_pWidget, "cap_iendcap.bmp"); - gtk_widget_show (pixmap); - gtk_table_attach (GTK_TABLE (table), pixmap, 0, 1, 3, 4, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - bevel = gtk_radio_button_new_with_label (group, "Bevel"); - gtk_widget_show (bevel); - gtk_table_attach (GTK_TABLE (table), bevel, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL | GTK_EXPAND), - (GtkAttachOptions) (0), 0, 0); - group = gtk_radio_button_group (GTK_RADIO_BUTTON (bevel)); - - endcap = gtk_radio_button_new_with_label (group, "Endcap"); - gtk_widget_show (endcap); - gtk_table_attach (GTK_TABLE (table), endcap, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_FILL | GTK_EXPAND), - (GtkAttachOptions) (0), 0, 0); - group = gtk_radio_button_group (GTK_RADIO_BUTTON (endcap)); - - ibevel = gtk_radio_button_new_with_label (group, "Inverted Bevel"); - gtk_widget_show (ibevel); - gtk_table_attach (GTK_TABLE (table), ibevel, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_FILL | GTK_EXPAND), - (GtkAttachOptions) (0), 0, 0); - group = gtk_radio_button_group (GTK_RADIO_BUTTON (ibevel)); - - iendcap = gtk_radio_button_new_with_label (group, "Inverted Endcap"); - gtk_widget_show (iendcap); - gtk_table_attach (GTK_TABLE (table), iendcap, 1, 2, 3, 4, - (GtkAttachOptions) (GTK_FILL | GTK_EXPAND), - (GtkAttachOptions) (0), 0, 0); - group = gtk_radio_button_group (GTK_RADIO_BUTTON (iendcap)); - - // Gef: added radio toggle for func_grouping capped patches - group_toggle = gtk_check_button_new_with_label("Result to func_group"); - gtk_container_add(GTK_CONTAINER(radio_vbox), group_toggle); - gtk_widget_show(group_toggle); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Cancel"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_set_usize (button, 60, -2); - - // Gef: Set the state of the func_group toggle - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (group_toggle), *b_GroupResult); - - // Initialize dialog - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bevel), TRUE); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - if (ret == IDOK) - { - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (bevel))) - *type = BEVEL; //*type = CapDialog::BEVEL; - else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (endcap))) - *type = ENDCAP; //*type = CapDialog::ENDCAP; - else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ibevel))) - *type = IBEVEL; // *type = CapDialog::IBEVEL; - else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (iendcap))) - *type = IENDCAP; // *type = CapDialog::IENDCAP; - - // Gef: Added toggle for optional cap func_grouping - *b_GroupResult = (bool *)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(group_toggle)); - } - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); - - return ret; -} - -// ============================================================================= -// Scripts dialog - -void DoScriptsDlg () -{ - GtkWidget *dlg, *vbox, *vbox2, *hbox, *label, *button, *scr; - int loop = 1, ret = IDCANCEL; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "Available Scripts - Not Implemented Yet"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_container_add (GTK_CONTAINER (dlg), vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - - label = gtk_label_new ("WARNING: BrushScripting is in a highly experimental state and is\n" - "far from complete. If you attempt to use them it is VERY LIKELY\n" - "that Radiant will crash. Save your work before attempting to\n" - "make use of any scripting features."); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0); - - scr = gtk_scrolled_window_new ((GtkAdjustment*)NULL, (GtkAdjustment*)NULL); - gtk_widget_show (scr); - gtk_box_pack_start (GTK_BOX (hbox), scr, TRUE, TRUE, 0); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scr), GTK_SHADOW_IN); - - GtkWidget* scripts_list; - - { - GtkListStore* store = gtk_list_store_new(1, G_TYPE_STRING); - - GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); - - { - GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); - GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); - } - - gtk_widget_show(view); - gtk_container_add(GTK_CONTAINER (scr), view); - - { - // Initialize dialog - CString strINI; - strINI = g_strGameToolsPath; - strINI += "/scripts.ini"; - FILE *f; - - f = fopen (strINI.GetBuffer(), "rt"); - if (f != NULL) - { - char line[1024], *ptr; - - // read section names - while (fgets (line, 1024, f) != 0) - { - if (line[0] != '[') - continue; - - ptr = strchr (line, ']'); - *ptr = '\0'; - - { - GtkTreeIter iter; - gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, 0, line, -1); - } - } - fclose (f); - } - } - - g_object_unref(G_OBJECT(store)); - - scripts_list = view; - } - - vbox2 = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox2); - gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0); - - button = gtk_button_new_with_label ("Run"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("New..."); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); - gtk_widget_set_sensitive (button, FALSE); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Edit..."); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); - gtk_widget_set_sensitive (button, FALSE); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Close"); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (vbox2), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_set_usize (button, 60, -2); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - if (ret == IDOK) - { - GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(scripts_list)); - - GtkTreeModel* model; - GtkTreeIter iter; - if(gtk_tree_selection_get_selected(selection, &model, &iter)) - { - char* script; - gtk_tree_model_get(model, &iter, 0, &script, -1); - RunScriptByName(script, true); - g_free(script); - } - } - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); -} - -// ============================================================================= -// dialog - -int DoBSInputDlg (const char *fields[5], float values[5]) -{ - GtkWidget *dlg, *vbox, *hbox, *label, *button; - GtkWidget *entries[5]; - int i, loop = 1, ret = IDCANCEL; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "BrushScript Input"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_container_add (GTK_CONTAINER (dlg), hbox); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); - - // Create entries and initialize them - for (i = 0; i < 5; i++) - { - if (strlen (fields[i]) == 0) - continue; - - label = gtk_label_new (fields[i]); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - - entries[i] = gtk_entry_new (); - gtk_widget_show (entries[i]); - gtk_box_pack_start (GTK_BOX (vbox), entries[i], TRUE, TRUE, 0); - - char buf[32]; - sprintf (buf, "%f", values[i]); - gtk_entry_set_text (GTK_ENTRY (entries[i]), buf); - } - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Cancel"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_set_usize (button, 60, -2); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - for (i = 0; i < 5; i++) - { - if (strlen (fields[i]) == 0) - continue; - - values[i] = atof (gtk_entry_get_text (GTK_ENTRY (entries[i]))); - } - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); - - return ret; -} - -// ============================================================================= -// TextureLayout dialog - -int DoTextureLayout (float *fx, float *fy) -{ - GtkWidget *dlg, *vbox, *hbox, *table, *label, *button; - GtkWidget *x, *y; - int loop = 1, ret = IDCANCEL; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "Patch texture layout"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_container_add (GTK_CONTAINER (dlg), hbox); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); - - label = gtk_label_new ("Texture will be fit across the patch based\n" - "on the x and y values given. Values of 1x1\n" - "will \"fit\" the texture. 2x2 will repeat\n" - "it twice, etc."); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - - table = gtk_table_new (2, 2, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("Texture x:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - label = gtk_label_new ("Texture y:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - x = gtk_entry_new (); - gtk_widget_show (x); - gtk_table_attach (GTK_TABLE (table), x, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - y = gtk_entry_new (); - gtk_widget_show (y); - gtk_table_attach (GTK_TABLE (table), y, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Cancel"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_set_usize (button, 60, -2); - - // Initialize - gtk_entry_set_text (GTK_ENTRY (x), "4.0"); - gtk_entry_set_text (GTK_ENTRY (y), "4.0"); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - if (ret == IDOK) - { - *fx = atof (gtk_entry_get_text (GTK_ENTRY (x))); - *fy = atof (gtk_entry_get_text (GTK_ENTRY (y))); - } - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); - - return ret; -} - -// ============================================================================= -// Name dialog - -char* DoNameDlg (const char* title) -{ - GtkWidget *dlg, *vbox, *hbox, *label, *button, *entry; - int loop = 1, ret = IDCANCEL; - char *str; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), title); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_container_add (GTK_CONTAINER (dlg), hbox); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - - label = gtk_label_new ("Name:"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Cancel"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_set_usize (button, 60, -2); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - if (ret == IDOK) - str = strdup (gtk_entry_get_text (GTK_ENTRY (entry))); - else - str = NULL; - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); - - return str; -} - -// ============================================================================= -// NewProject dialog - -char* DoNewProjectDlg () -{ - GtkWidget *dlg, *vbox, *hbox, *label, *button, *entry, *check; - int loop = 1, ret = IDCANCEL; - char *str; - - // start by a warning message - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=459 - CString msg; - msg = "Are you sure you want a new project?\n"; - msg += "Please note that creating a new project is not the prefered way to setup GtkRadiant for mod editing.\n"; - msg += "Check http://www.qeradiant.com/faq/index.cgi?file=220 for more information"; - if (gtk_MessageBox(NULL, msg.GetBuffer(), "Confirm", MB_YESNO, "http://www.qeradiant.com/faq/index.cgi?file=220" ) == IDNO) - { - return NULL; - } - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "New Project"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - hbox = gtk_hbox_new (FALSE, 10); - gtk_widget_show (hbox); - gtk_container_add (GTK_CONTAINER (dlg), hbox); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); - - label = gtk_label_new ("This will create a new directory beneath your\n" - "game path based on the project name you give."); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - - label = gtk_label_new ("Project name:"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0); - - check = gtk_check_button_new_with_label ("Include game dll files"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, TRUE, TRUE, 0); - gtk_widget_set_sensitive (check, FALSE); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Cancel"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_set_usize (button, 60, -2); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - if (ret == IDOK) - str = strdup (gtk_entry_get_text (GTK_ENTRY (entry))); - else - str = NULL; - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); - - return str; -} - -// ============================================================================= -// Text Editor dialog - -// master window widget -static GtkWidget *text_editor = NULL; -static GtkWidget *text_widget; // slave, text widget from the gtk editor - -static gint editor_delete (GtkWidget *widget, gpointer data) -{ - if (gtk_MessageBox (widget, "Close the shader editor ?", "Radiant", MB_YESNO) == IDNO) - return TRUE; - - gtk_widget_hide (text_editor); - - return TRUE; -} - -static void editor_save (GtkWidget *widget, gpointer data) -{ - FILE *f = fopen ((char*)g_object_get_data (G_OBJECT (data), "filename"), "w"); - gpointer text = g_object_get_data (G_OBJECT (data), "text"); - - if (f == NULL) - { - gtk_MessageBox (GTK_WIDGET(data), "Error saving file !"); - return; - } - - char *str = gtk_editable_get_chars (GTK_EDITABLE (text), 0, -1); - fwrite (str, 1, strlen (str), f); - fclose (f); -} - -static void editor_close (GtkWidget *widget, gpointer data) -{ - if (gtk_MessageBox (text_editor, "Close the shader editor ?", "Radiant", MB_YESNO) == IDNO) - return; - - gtk_widget_hide (text_editor); -} - -// several attempts -// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=355 -#if 0 -#ifdef _WIN32 - -HWND FindEditWindow() -{ - return FindWindow("TFormEditPadLite", NULL); -} - -HWND FindEditWindow() -{ - HWND hwnd = FindWindow("TFormEditPadLite", NULL); - if (hwnd) - { - hwnd = FindWindowEx(hwnd, NULL, "TPanel", NULL); - if (hwnd) - { - hwnd = FindWindowEx(hwnd, NULL, "TPanel", NULL); - if (hwnd) - { - hwnd = FindWindowEx(hwnd, NULL, "TEditPadEditor", NULL); - if (hwnd) - { - hwnd = FindWindowEx(hwnd, NULL, "TWinControlProxy", NULL); - return hwnd; - } - } - } - } - return NULL; -} - -HWND FindEditWindow() -{ - HWND hwnd = FindWindow("TFormEditPadLite", NULL); - if (hwnd) - { - hwnd = FindWindowEx(hwnd, NULL, "TPanel", NULL); - if (hwnd) - { - hwnd = FindWindowEx(hwnd, NULL, "TPanel", NULL); - if (hwnd) - { - hwnd = FindWindowEx(hwnd, NULL, "TPanel", NULL); - if (hwnd) - { - hwnd = FindWindowEx(hwnd, NULL, "TFrameSearchReplace", NULL); - if (hwnd) - { - hwnd = FindWindowEx(hwnd, NULL, "TJGStringEditorControl", NULL); - return hwnd; - } - } - } - } - } - return NULL; -} - -HWND FindEditWindow() -{ - HWND hwnd = FindWindow("TEditPadForm", NULL); - HWND hwndEdit = NULL; - if (hwnd != NULL) - { - HWND hwndTab = FindWindowEx(hwnd, NULL, "TTabControl", NULL); - if (hwndTab != NULL) - { - hwndEdit = FindWindowEx(hwndTab, NULL, "TRicherEdit", NULL); - } - } - return hwndEdit; -} -#endif -#endif // #if 0 - -static void CreateGtkTextEditor () -{ - GtkWidget *dlg; - GtkWidget *vbox, *hbox, *button, *scr, *text; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (editor_delete), NULL); - gtk_window_set_default_size (GTK_WINDOW (dlg), 600, 300); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_container_add (GTK_CONTAINER (dlg), vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - - scr = gtk_scrolled_window_new (NULL, NULL); - gtk_widget_show (scr); - gtk_box_pack_start (GTK_BOX (vbox), scr, TRUE, TRUE, 0); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); - - text = gtk_text_view_new(); - gtk_container_add (GTK_CONTAINER (scr), text); - gtk_widget_show (text); - g_object_set_data (G_OBJECT (dlg), "text", text); - gtk_text_view_set_editable (GTK_TEXT_VIEW(text), TRUE); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); - - button = gtk_button_new_with_label ("Close"); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (editor_close), dlg); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Save"); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (editor_save), dlg); - gtk_widget_set_usize (button, 60, -2); - - text_editor = dlg; - text_widget = text; -} - -static void DoGtkTextEditor (const char* filename, guint cursorpos) -{ - if (!text_editor) - CreateGtkTextEditor(); // build it the first time we need it - - // Load file - FILE *f = fopen (filename, "r"); - - if (f == NULL) - { - Sys_Printf("Unable to load file %s in shader editor.\n", filename); - gtk_widget_hide (text_editor); - } - else - { - fseek (f, 0, SEEK_END); - int len = ftell (f); - void *buf = qmalloc (len); - void *old_filename; - - rewind (f); - fread (buf, 1, len, f); - - gtk_window_set_title (GTK_WINDOW (text_editor), filename); - - GtkTextBuffer* text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_widget)); - gtk_text_buffer_set_text(text_buffer, (char*)buf, len); - - old_filename = g_object_get_data (G_OBJECT (text_editor), "filename"); - if (old_filename) - free(old_filename); - g_object_set_data (G_OBJECT (text_editor), "filename", strdup (filename)); - - // trying to show later - gtk_widget_show (text_editor); - -#ifdef _WIN32 - while (gtk_events_pending ()) - gtk_main_iteration (); -#endif - - // only move the cursor if it's not exceeding the size.. - // NOTE: this is erroneous, cursorpos is the offset in bytes, not in characters - // len is the max size in bytes, not in characters either, but the character count is below that limit.. - // thinking .. the difference between character count and byte count would be only because of CR/LF? - { - GtkTextIter text_iter; - // character offset, not byte offset - gtk_text_buffer_get_iter_at_offset(text_buffer, &text_iter, cursorpos); - gtk_text_buffer_place_cursor(text_buffer, &text_iter); - } - -#ifdef _WIN32 - gtk_widget_queue_draw(text_widget); -#endif - - free (buf); - fclose (f); - } -} - -void DoTextEditor (const char* filename, int cursorpos) -{ - CString strEditCommand; -#ifdef _WIN32 - if (g_PrefsDlg.m_bUseWin32Editor) - { - Sys_Printf("opening file '%s' (line %d info ignored)\n", filename); - ShellExecute((HWND)GDK_WINDOW_HWND (g_pParentWnd->m_pWidget->window), "open", filename, NULL, NULL, SW_SHOW ); - return; - } -#else - // check if a custom editor is set - if((g_PrefsDlg.m_bUseCustomEditor) && (g_PrefsDlg.m_strEditorCommand.GetLength() > 0)) - { - strEditCommand = g_PrefsDlg.m_strEditorCommand; - strEditCommand += " \""; - strEditCommand += filename; - strEditCommand += "\""; - - Sys_Printf("Launching: %s\n", strEditCommand.GetBuffer()); - // note: linux does not return false if the command failed so it will assume success - if (Q_Exec(NULL, (char *)strEditCommand.GetBuffer(), NULL, true) == false) - { - Sys_FPrintf(SYS_WRN, "Warning: Failed to execute %s, using default\n", strEditCommand.GetBuffer()); - } - else - { - // the command (appeared) to run successfully, no need to do anything more - return; - } - } -#endif - - DoGtkTextEditor (filename, cursorpos); - - // old win32 code with EditPad bindings, broken - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=355 -#if 0 - strEditCommand = g_strAppPath.GetBuffer(); - strEditCommand += "editpad.exe"; - strEditCommand += " \""; - strEditCommand += filename; - strEditCommand += "\""; - if (Q_Exec(NULL, (char *)strEditCommand.GetBuffer(), NULL, true) == false) - { - Sys_FPrintf(SYS_WRN, "WARNING: Gtk shader editor is not fully functional on windows in general and unstable on win98 in particular.\n"); - Sys_FPrintf(SYS_WRN, " you can use EditPad instead (install it in Radiant's directory): http://www.qeradiant.com/?data=files&files_dir=18\n"); - DoGtkTextEditor (filename, cursorpos); - } - else - { - // TTimo: we used to call Delay here, to continue processing messages. But it seems to induce a lot of instabilities. - // so now the user will simply have to wait. - Sleep( 1500 ); - - // now grab the edit window and scroll to the shader we want to edit - HWND hwndEdit = FindEditWindow(); - - if (hwndEdit != NULL) - PostMessage(hwndEdit, EM_SETSEL, cursorpos, cursorpos); - else - Sys_Printf("Unable to load shader editor.\n"); - } -#endif -} - -// ============================================================================= -// Light Intensity dialog - -int DoLightIntensityDlg (int *intensity) -{ - GtkWidget *dlg, *vbox, *hbox, *label, *button, *entry; - int loop = 1, ret = IDCANCEL; - - dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (dlg), "Light intensity"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - GtkAccelGroup *accel_group = gtk_accel_group_new (); - gtk_window_add_accel_group (GTK_WINDOW (dlg), accel_group); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_container_add (GTK_CONTAINER (dlg), hbox); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); - - label = gtk_label_new ("ESC for default, ENTER to validate"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_add_accelerator (button, "clicked", accel_group, - GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Cancel"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_add_accelerator (button, "clicked", accel_group, - GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE); - gtk_widget_set_usize (button, 60, -2); - - char buf[16]; - sprintf (buf, "%d", *intensity); - gtk_entry_set_text (GTK_ENTRY (entry), buf); - - gtk_grab_add (dlg); - gtk_widget_show (dlg); - - while (loop) - gtk_main_iteration (); - - if (ret == IDOK) - *intensity = atoi (gtk_entry_get_text (GTK_ENTRY (entry))); - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); - - return ret; -} +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// +// Some small dialogs that don't need much +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" +#include +#include + +#ifdef _WIN32 +#include +#endif + +#ifdef _WIN32 +#include +#endif + +// ============================================================================= +// Color selection dialog + +qboolean DoColor (int iIndex) +{ + static bool bColorOpen = false; + + if(bColorOpen) + { + Sys_FPrintf(SYS_WRN, "DoColor dialog is already open\n"); + return false; + } + + bColorOpen = true; + + if (color_dialog (g_pParentWnd->m_pWidget, g_qeglobals.d_savedinfo.colors[iIndex])) + { + /* + ** scale colors so that at least one component is at 1.0F + ** if this is meant to select an entity color + */ + if (iIndex == COLOR_ENTITY) + { + float largest = 0.0F; + + if ( g_qeglobals.d_savedinfo.colors[iIndex][0] > largest ) + largest = g_qeglobals.d_savedinfo.colors[iIndex][0]; + if ( g_qeglobals.d_savedinfo.colors[iIndex][1] > largest ) + largest = g_qeglobals.d_savedinfo.colors[iIndex][1]; + if ( g_qeglobals.d_savedinfo.colors[iIndex][2] > largest ) + largest = g_qeglobals.d_savedinfo.colors[iIndex][2]; + + if ( largest == 0.0F ) + { + g_qeglobals.d_savedinfo.colors[iIndex][0] = 1.0F; + g_qeglobals.d_savedinfo.colors[iIndex][1] = 1.0F; + g_qeglobals.d_savedinfo.colors[iIndex][2] = 1.0F; + } + else + { + float scaler = 1.0F / largest; + + g_qeglobals.d_savedinfo.colors[iIndex][0] *= scaler; + g_qeglobals.d_savedinfo.colors[iIndex][1] *= scaler; + g_qeglobals.d_savedinfo.colors[iIndex][2] *= scaler; + } + } + + Sys_UpdateWindows (W_ALL); + bColorOpen = false; + return true; + } + else { + bColorOpen = false; + return false; + } +} + +// ============================================================================= +// Project settings dialog + +static void UpdateBSPCommandList (GtkWidget *dialog); + +static void DoProjectAddEdit (bool edit, GtkWidget *parent) +{ + GtkWidget *dlg, *vbox, *hbox, *label, *table, *button; + GtkWidget *cmd, *text; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + if (edit) + gtk_window_set_title (GTK_WINDOW (dlg), "Edit Command"); + else + gtk_window_set_title (GTK_WINDOW (dlg), "Add Command"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Menu text"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + label = gtk_label_new ("Command"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + text = gtk_entry_new (); + g_object_set_data (G_OBJECT (dlg), "text", text); + gtk_widget_show (text); + gtk_table_attach (GTK_TABLE (table), text, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (text, 300, -2); + + cmd = gtk_entry_new (); + g_object_set_data (G_OBJECT (dlg), "cmd", cmd); + gtk_widget_show (cmd); + gtk_table_attach (GTK_TABLE (table), cmd, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (cmd, 300, -2); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + if (edit) + { + GtkTreeView* view = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(parent), "view")); + GtkTreeSelection* selection = gtk_tree_view_get_selection(view); + GtkTreeIter iter; + GtkTreeModel* model; + if(gtk_tree_selection_get_selected(selection, &model, &iter)) + { + char* key; + gtk_tree_model_get(model, &iter, 0, &key, -1); + const char* value = ValueForKey (g_qeglobals.d_project_entity, key); + gtk_entry_set_text (GTK_ENTRY (text), key); + gtk_entry_set_text (GTK_ENTRY (cmd), value); + g_free(key); + } + } + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + const char* key = gtk_entry_get_text (GTK_ENTRY (text)); + const char* value = gtk_entry_get_text (GTK_ENTRY (cmd)); + + if (strlen (key) <= 0 || strlen (value) <= 0) + { + Sys_Printf ("Command not added\n"); + } + else + { + if (edit) + { + SetKeyValue (g_qeglobals.d_project_entity, key, value); + FillBSPMenu (); + } + else + { + if (key[0] == 'b' && key[1] == 's' && key[2] == 'p') + { + SetKeyValue (g_qeglobals.d_project_entity, key, value); + FillBSPMenu (); + } + else + Sys_Printf ("BSP commands must be preceded by \"bsp\""); + } + + UpdateBSPCommandList (parent); + } + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +static void UpdateBSPCommandList (GtkWidget *dialog) +{ + GtkListStore* store = GTK_LIST_STORE (g_object_get_data (G_OBJECT(dialog), "bsp_commands")); + + gtk_list_store_clear(store); + + for(epair_t* ep = g_qeglobals.d_project_entity->epairs; ep != NULL; ep = ep->next) + { + if(ep->key[0] == 'b' && ep->key[1] == 's' && ep->key[2] == 'p') + { + GtkTreeIter iter; + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, ep->key, -1); + } + } +} + +static void project_add (GtkWidget *widget, gpointer data) +{ + GtkWidget *dlg = GTK_WIDGET (data); + DoProjectAddEdit (false, dlg); + UpdateBSPCommandList (dlg); +} + +static void project_change (GtkWidget *widget, gpointer data) +{ + GtkWidget *dlg = GTK_WIDGET (data); + DoProjectAddEdit (true, dlg); + UpdateBSPCommandList (dlg); +} + +static void project_remove (GtkWidget *widget, gpointer data) +{ + GtkWidget* project = GTK_WIDGET(data); + + GtkTreeView* view = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(project), "view")); + GtkTreeSelection* selection = gtk_tree_view_get_selection(view); + GtkTreeIter iter; + GtkTreeModel* model; + if(gtk_tree_selection_get_selected(selection, &model, &iter)) + { + char* key; + gtk_tree_model_get(model, &iter, 0, &key, -1); + DeleteKey (g_qeglobals.d_project_entity, key); + g_free(key); + + char* index = gtk_tree_model_get_string_from_iter(model, &iter); + Sys_Printf ("Selected %s\n", index); + g_free(index); + + UpdateBSPCommandList(project); + FillBSPMenu(); + } +} + +static const char* sQ3ComboItem = "Quake III Arena"; +static const char* sTAComboItem = "Quake III: Team Arena"; +static const char* sModComboItem = "Custom Quake III modification"; +static const char* sWolfComboItem = "Return To Castle Wolfenstein"; +static const char* sWolfModComboItem = "Custom RTCW modification"; +static const char* sHLComboItem = "Half-life"; +static const char* sHLModComboItem = "Custom Half-life modification"; + +static const char* sWolfSPCombo = "Single Player mapping mode"; +static const char* sWolfMPCombo = "Multiplayer mapping mode"; + +// Arnout +// HARD-CODED ET HACK +static const char* sETComboItem = "Wolfenstein: Enemy Territory"; +static const char* sETModComboItem = "Custom ET modification"; + +// RIANT +// HARD-CODED JK2 HACK +static const char* sJK2ComboItem = "Jedi Knight II Outcast"; +static const char* sJK2ModComboItem = "Custom JK2 modification"; +static const char* sJK2SPCombo = "Single Player mapping mode"; +static const char* sJK2MPCombo = "Multiplayer mapping mode"; + +// TTimo +// HARD-CODED JA HACK +static const char* sJAComboItem = "Jedi Knight Jedi Academy"; +static const char* sJAModComboItem = "Custom JA modification"; +static const char* sJASPCombo = "Single Player mapping mode"; +static const char* sJAMPCombo = "Multiplayer mapping mode"; + +// RIANT +// HARD-CODED STVEF2 HACK +static const char* sSTVEFComboItem = "Star Trek Voyager : Elite Force"; +static const char* sSTVEFModComboItem = "Custom Elite Force modification"; +static const char* sSTVEFSPCombo = "Single Player mapping mode"; +static const char* sSTVEFMPCombo = "Holo Match mapping mode"; + +// RIANT +// HARD-CODED SOF2 HACK +static const char* sSOF2ComboItem = "Soldier of Fortune II - Double Helix"; +static const char* sSOF2ModComboItem = "Custom Sof2 modification"; +static const char* sSOF2SPCombo = "Single Player mapping mode"; +static const char* sSOF2MPCombo = "Multiplayer mapping mode"; + +static GtkWidget* game_select; // GTK_COMBO +static GtkEntry* fsgame_entry; + +gint OnSelchangeComboWhatgame (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + const char *dir = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO(game_select)->entry)); + // HACK: Wolf + if (g_pGameDescription->mGameFile == "wolf.game") + { + if (!strcmp(dir,sWolfComboItem)) + { + // disable the fs_game text entry + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); + } + else + { + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); + } + + } + // HACK: ET + else if (g_pGameDescription->mGameFile == "et.game") + { + if (!strcmp(dir,sETComboItem)) + { + // disable the fs_game text entry + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); + } + else + { + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); + } + + } + else if (g_pGameDescription->mGameFile == "hl.game") + { + if (!strcmp(dir,sHLComboItem)) + { + // disable the fs_game text entry + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); + } + else + { + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); + } + + } + // RIANT + // HACK: JK2 + else if (g_pGameDescription->mGameFile == "jk2.game") + { + if (!strcmp(dir,sJK2ComboItem)) + { + // disable the fs_game text entry + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); + } + else + { + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); + } + } + // TTimo + // HACK: JA + else if (g_pGameDescription->mGameFile == "ja.game") + { + if (!strcmp(dir,sJAComboItem)) + { + // disable the fs_game text entry + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); + } + else + { + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); + } + } + // RIANT + // HACK: STVEF + else if (g_pGameDescription->mGameFile == "stvef.game") + { + if (!strcmp(dir,sSTVEFComboItem)) + { + // disable the fs_game text entry + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); + } + else + { + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); + } + } + // RIANT + // HACK: SOF2 + else if (g_pGameDescription->mGameFile == "sof2.game") + { + if (!strcmp(dir,sSOF2ComboItem)) + { + // disable the fs_game text entry + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); + } + else + { + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); + } + } + // QUAKE 3 + else + { + if (!strcmp(dir,sQ3ComboItem)) + { + // disable the fs_game text entry + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); + } + else if (!strcmp(dir,sTAComboItem)) + { + gtk_entry_set_text (fsgame_entry, "missionpack"); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), false); + } + else + { + gtk_entry_set_text (fsgame_entry, ""); + gtk_widget_set_sensitive(GTK_WIDGET(fsgame_entry), true); + } + } + + return TRUE; +} + +void DoProjectSettings () +{ + GtkWidget *project; + GtkWidget *frame, *label, *vbox, *table1, *table2, *button; + GtkWidget *brush; + GtkWidget *scr; + GtkWidget *base, *game; + GtkWidget *gamemode_combo; + GList *combo_list = (GList*)NULL; + + int loop = 1, ret = IDCANCEL; + + project = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (project), "Project Settings"); + gtk_signal_connect (GTK_OBJECT (project), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (project), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (project), "loop", &loop); + g_object_set_data (G_OBJECT (project), "ret", &ret); + gtk_window_set_default_size (GTK_WINDOW (project), 550, 400); + + table1 = gtk_table_new (3, 2, FALSE); + gtk_widget_show (table1); + gtk_container_add (GTK_CONTAINER (project), table1); + gtk_container_set_border_width (GTK_CONTAINER (table1), 5); + gtk_table_set_row_spacings (GTK_TABLE (table1), 5); + gtk_table_set_col_spacings (GTK_TABLE (table1), 5); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_table_attach (GTK_TABLE (table1), vbox, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_table_attach (GTK_TABLE (table1), vbox, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + button = gtk_button_new_with_label ("Add..."); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (project_add), project); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Change..."); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (project_change), project); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Remove"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (project_remove), project); + gtk_widget_set_usize (button, 60, -2); + + frame = gtk_frame_new ("Misc settings"); + gtk_widget_show (frame); + gtk_table_attach (GTK_TABLE (table1), frame, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + brush = gtk_check_button_new_with_label ("Use brush primitives in MAP files (NOTE: experimental feature,\n" + "required by the texture tools plugin)"); + gtk_widget_show (brush); + gtk_container_add (GTK_CONTAINER (frame), brush); + gtk_container_set_border_width (GTK_CONTAINER (brush), 5); + + frame = gtk_frame_new ("Menu commands"); + gtk_widget_show (frame); + gtk_table_attach (GTK_TABLE (table1), frame, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + + scr = gtk_scrolled_window_new ((GtkAdjustment*)NULL, (GtkAdjustment*)NULL); + gtk_widget_show (scr); + gtk_container_add (GTK_CONTAINER (frame), scr); + gtk_container_set_border_width (GTK_CONTAINER (scr), 5); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); + + + { + GtkListStore* store = gtk_list_store_new(1, G_TYPE_STRING); + + GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); + + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + + GtkTreeSelection* selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view)); + gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE); + + gtk_widget_show(view); + + g_object_set_data(G_OBJECT (project), "view", view); + g_object_set_data(G_OBJECT (project), "bsp_commands", store); + gtk_container_add(GTK_CONTAINER (scr), view); + + g_object_unref(G_OBJECT(store)); + } + + frame = gtk_frame_new ("Project settings"); + gtk_widget_show (frame); + gtk_table_attach (GTK_TABLE (table1), frame, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + // HACK: hardcoded game stuff + if (g_pGameDescription->mGameFile == "wolf.game" || + g_pGameDescription->mGameFile == "et.game" || + g_pGameDescription->mGameFile == "jk2.game" || + g_pGameDescription->mGameFile == "stvef.game" || + g_pGameDescription->mGameFile == "sof2.game" || + g_pGameDescription->mGameFile == "ja.game" ) + { + table2 = gtk_table_new (9, 2, FALSE); + } + else + { + table2 = gtk_table_new (8, 2, FALSE); + } + gtk_widget_show (table2); + gtk_container_add (GTK_CONTAINER (frame), table2); + gtk_container_set_border_width (GTK_CONTAINER (table2), 5); + gtk_table_set_row_spacings (GTK_TABLE (table2), 5); + gtk_table_set_col_spacings (GTK_TABLE (table2), 5); + + /* + fill in the game selection combo + HACK: hardcoded Q3/Wolf/HL switch + \todo that stuff would be faster to write with implementation of property bags and associated code to edit + */ + if (g_pGameDescription->mGameFile == "wolf.game") + { + combo_list = g_list_append (combo_list, (void *)sWolfComboItem); + combo_list = g_list_append (combo_list, (void *)sWolfModComboItem); + } + else if (g_pGameDescription->mGameFile == "et.game") + { + combo_list = g_list_append (combo_list, (void *)sETComboItem); + combo_list = g_list_append (combo_list, (void *)sETModComboItem); + } + else if (g_pGameDescription->mGameFile == "hl.game") + { + combo_list = g_list_append (combo_list, (void *)sHLComboItem); + combo_list = g_list_append (combo_list, (void *)sHLModComboItem); + } + // RIANT + // JK2 HACK + else if (g_pGameDescription->mGameFile == "jk2.game") + { + combo_list = g_list_append (combo_list, (void *)sJK2ComboItem); + combo_list = g_list_append (combo_list, (void *)sJK2ModComboItem); + } + // TTimo + // JA HACK + else if (g_pGameDescription->mGameFile == "ja.game") + { + combo_list = g_list_append (combo_list, (void *)sJAComboItem); + combo_list = g_list_append (combo_list, (void *)sJAModComboItem); + } + // RIANT + // STVEF HACK + else if (g_pGameDescription->mGameFile == "stvef.game") + { + combo_list = g_list_append (combo_list, (void *)sSTVEFComboItem); + combo_list = g_list_append (combo_list, (void *)sSTVEFModComboItem); + } + // RIANT + // SOF2 HACK A LA JK2 A LA WOLF + else if (g_pGameDescription->mGameFile == "sof2.game") + { + combo_list = g_list_append (combo_list, (void *)sSOF2ComboItem); + combo_list = g_list_append (combo_list, (void *)sSOF2ModComboItem); + } + else + { + // Q3 or default + combo_list = g_list_append (combo_list, (void *)sQ3ComboItem); + combo_list = g_list_append (combo_list, (void *)sTAComboItem); + combo_list = g_list_append (combo_list, (void *)sModComboItem); + } + + game_select = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (game_select), combo_list); + gtk_widget_show (game_select); + gtk_table_attach (GTK_TABLE (table2), game_select, 1, 2, 6, 7, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + gtk_signal_connect (GTK_OBJECT(GTK_COMBO (game_select)->entry), "changed", + GTK_SIGNAL_FUNC (OnSelchangeComboWhatgame), NULL); + + g_list_free (combo_list); + gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (game_select)->entry), FALSE); + + game = gtk_entry_new(); + fsgame_entry = GTK_ENTRY(game); + gtk_widget_show(game); + gtk_table_attach(GTK_TABLE(table2), game, 1, 2, 7, 8, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + /* + wolf specific: select MP or SP mode + */ + if (g_pGameDescription->mGameFile == "wolf.game") + { + combo_list = NULL; + combo_list = g_list_append (combo_list, (void *)sWolfSPCombo); + combo_list = g_list_append (combo_list, (void *)sWolfMPCombo); + + gamemode_combo = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (gamemode_combo), combo_list); + gtk_widget_show(gamemode_combo); + gtk_table_attach (GTK_TABLE (table2), gamemode_combo, 1, 2, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + g_list_free (combo_list); + combo_list = NULL; + + label = gtk_label_new ("Mapping mode"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 8, 9, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + } + + // RIANT + // JK2 HACK + if (g_pGameDescription->mGameFile == "jk2.game") + { + combo_list = NULL; + combo_list = g_list_append (combo_list, (void *)sJK2SPCombo); + combo_list = g_list_append (combo_list, (void *)sJK2MPCombo); + + gamemode_combo = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (gamemode_combo), combo_list); + gtk_widget_show(gamemode_combo); + gtk_table_attach (GTK_TABLE (table2), gamemode_combo, 1, 2, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + g_list_free (combo_list); + combo_list = NULL; + + label = gtk_label_new ("Mapping mode"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 8, 9, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + } + // TTimo + // JA HACK + if (g_pGameDescription->mGameFile == "ja.game") + { + combo_list = NULL; + combo_list = g_list_append (combo_list, (void *)sJASPCombo); + combo_list = g_list_append (combo_list, (void *)sJAMPCombo); + + gamemode_combo = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (gamemode_combo), combo_list); + gtk_widget_show(gamemode_combo); + gtk_table_attach (GTK_TABLE (table2), gamemode_combo, 1, 2, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + g_list_free (combo_list); + combo_list = NULL; + + label = gtk_label_new ("Mapping mode"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 8, 9, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + } + // RIANT + // STVEF HACK + if (g_pGameDescription->mGameFile == "stvef.game") + { + combo_list = NULL; + combo_list = g_list_append (combo_list, (void *)sSTVEFSPCombo); + combo_list = g_list_append (combo_list, (void *)sSTVEFMPCombo); + + gamemode_combo = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (gamemode_combo), combo_list); + gtk_widget_show(gamemode_combo); + gtk_table_attach (GTK_TABLE (table2), gamemode_combo, 1, 2, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + g_list_free (combo_list); + combo_list = NULL; + + label = gtk_label_new ("Mapping mode"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 8, 9, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + } + // RIANT + // SOF2 HACK + if (g_pGameDescription->mGameFile == "sof2.game") + { + combo_list = NULL; + combo_list = g_list_append (combo_list, (void *)sSOF2SPCombo); + combo_list = g_list_append (combo_list, (void *)sSOF2MPCombo); + + gamemode_combo = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (gamemode_combo), combo_list); + gtk_widget_show(gamemode_combo); + gtk_table_attach (GTK_TABLE (table2), gamemode_combo, 1, 2, 8, 9, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + g_list_free (combo_list); + combo_list = NULL; + + label = gtk_label_new ("Mapping mode"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 8, 9, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + } + + /* + the usual stuff + */ + + base = gtk_entry_new (); + g_object_set_data (G_OBJECT (project), "base", base); + gtk_widget_show (base); + gtk_table_attach (GTK_TABLE (table2), base, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + + label = gtk_label_new ("basepath"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + + label = gtk_label_new ("Select mod"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 6, 7, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + label = gtk_label_new ("fs_game"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 7, 8, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + // Initialize fields + gtk_entry_set_text (GTK_ENTRY (base), ValueForKey (g_qeglobals.d_project_entity, "basepath")); + UpdateBSPCommandList (project); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (brush), (g_qeglobals.m_bBrushPrimitMode) ? TRUE : FALSE); + + // initialise the fs_game selection from the project settings into the dialog + const char *dir = ValueForKey (g_qeglobals.d_project_entity, "gamename"); + // HACK: hardcoded wolf stuff + if (g_pGameDescription->mGameFile == "wolf.game") + { + if ((strlen(dir) == 0) || !stricmp(dir,"main")) + { + // no fs_game set, we are running stock Quake III Arena editing + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sWolfComboItem); + gtk_entry_set_text (GTK_ENTRY (game), ""); + gtk_widget_set_sensitive(game, false); + } + else + { + // this is a custom mod + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sWolfModComboItem); + gtk_entry_set_text (GTK_ENTRY (game), dir); + gtk_widget_set_sensitive(game, true); + } + } + // HACK: hardcoded et stuff + if (g_pGameDescription->mGameFile == "et.game") + { + if ((strlen(dir) == 0) || !stricmp(dir,"etmain")) + { + // no fs_game set, we are running stock Quake III Arena editing + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sETComboItem); + gtk_entry_set_text (GTK_ENTRY (game), ""); + gtk_widget_set_sensitive(game, false); + } + else + { + // this is a custom mod + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sETModComboItem); + gtk_entry_set_text (GTK_ENTRY (game), dir); + gtk_widget_set_sensitive(game, true); + } + } + // HACK: hardcoded half-life stuff + else if (g_pGameDescription->mGameFile == "hl.game") + { + if ((strlen(dir) == 0) || !stricmp(dir,"valve")) + { + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sHLComboItem); + gtk_entry_set_text (GTK_ENTRY (game), ""); + gtk_widget_set_sensitive(game, false); + } + else + { + // this is a custom mod + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sHLModComboItem); + gtk_entry_set_text (GTK_ENTRY (game), dir); + gtk_widget_set_sensitive(game, true); + } + } + // RIANT + // JK2 HACK + else if (g_pGameDescription->mGameFile == "jk2.game") + { + if ((strlen(dir) == 0) || !stricmp(dir,"base")) + { + // no fs_game set, we are running stock Quake III Arena editing + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sJK2ComboItem); + gtk_entry_set_text (GTK_ENTRY (game), ""); + gtk_widget_set_sensitive(game, false); + } + else + { + // this is a custom mod + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sJK2ModComboItem); + gtk_entry_set_text (GTK_ENTRY (game), dir); + gtk_widget_set_sensitive(game, true); + } + } + // TTimo + // JA HACK + else if (g_pGameDescription->mGameFile == "ja.game") + { + if ((strlen(dir) == 0) || !stricmp(dir,"base")) + { + // no fs_game set, we are running stock editing + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sJAComboItem); + gtk_entry_set_text (GTK_ENTRY (game), ""); + gtk_widget_set_sensitive(game, false); + } + else + { + // this is a custom mod + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sJAModComboItem); + gtk_entry_set_text (GTK_ENTRY (game), dir); + gtk_widget_set_sensitive(game, true); + } + } + // RIANT + // STVEF2 HACK + else if (g_pGameDescription->mGameFile == "stvef.game") + { + if ((strlen(dir) == 0) || !stricmp(dir,"baseEf")) + { + // no fs_game set, we are running stock Quake III Arena editing + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sSTVEFComboItem); + gtk_entry_set_text (GTK_ENTRY (game), ""); + gtk_widget_set_sensitive(game, false); + } + else + { + // this is a custom mod + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sSTVEFModComboItem); + gtk_entry_set_text (GTK_ENTRY (game), dir); + gtk_widget_set_sensitive(game, true); + } + } + // RIANT + // SOF2 HACK + else if (g_pGameDescription->mGameFile == "sof2.game") + { + if ((strlen(dir) == 0) || !stricmp(dir,"base")) + { + // no fs_game set, we are running stock Quake III Arena editing + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sSOF2ComboItem); + gtk_entry_set_text (GTK_ENTRY (game), ""); + gtk_widget_set_sensitive(game, false); + } + else + { + // this is a custom mod + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sSOF2ModComboItem); + gtk_entry_set_text (GTK_ENTRY (game), dir); + gtk_widget_set_sensitive(game, true); + } + } + else + { + if ((strlen(dir) == 0) || !strcmp(dir,"baseq3")) + { + // no fs_game set, we are running stock Quake III Arena editing + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sQ3ComboItem); + gtk_entry_set_text (GTK_ENTRY (game), ""); + gtk_widget_set_sensitive(game, false); + } + else if (!strcmp(dir,"missionpack")) + { + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sTAComboItem); + gtk_entry_set_text (GTK_ENTRY (game), "missionpack"); + gtk_widget_set_sensitive(game, false); + } + else + { + // this is a custom mod + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (game_select)->entry), sModComboItem); + gtk_entry_set_text (GTK_ENTRY (game), dir); + gtk_widget_set_sensitive(game, true); + } + } + + // HACK: hardcoded wolf stuff + if (g_pGameDescription->mGameFile == "wolf.game") + { + const char *gamemode = ValueForKey (g_qeglobals.d_project_entity, "gamemode"); + if ((strlen(gamemode) == 0) || !strcmp(gamemode,"sp")) + { + // nothing set yet, or single player + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sWolfSPCombo); + } + else + { + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sWolfMPCombo); + } + } + + // JK2 HACK + else if (g_pGameDescription->mGameFile == "jk2.game") + { + const char *gamemode = ValueForKey (g_qeglobals.d_project_entity, "gamemode"); + if ((strlen(gamemode) == 0) || !strcmp(gamemode,"sp")) + { + // nothing set yet, or single player + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sJK2SPCombo); + } + else + { + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sJK2MPCombo); + } + } + // JA HACK + else if (g_pGameDescription->mGameFile == "ja.game") + { + const char *gamemode = ValueForKey (g_qeglobals.d_project_entity, "gamemode"); + if ((strlen(gamemode) == 0) || !strcmp(gamemode,"sp")) + { + // nothing set yet, or single player + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sJASPCombo); + } + else + { + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sJAMPCombo); + } + } + // STVEF HACK + else if (g_pGameDescription->mGameFile == "stvef.game") + { + const char *gamemode = ValueForKey (g_qeglobals.d_project_entity, "gamemode"); + if ((strlen(gamemode) == 0) || !strcmp(gamemode,"sp")) + { + // nothing set yet, or single player + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sSTVEFSPCombo); + } + else + { + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sSTVEFMPCombo); + } + } + // SOF2 HACK + else if (g_pGameDescription->mGameFile == "sof2.game") + { + const char *gamemode = ValueForKey (g_qeglobals.d_project_entity, "gamemode"); + if ((strlen(gamemode) == 0) || !strcmp(gamemode,"sp")) + { + // nothing set yet, or single player + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sSOF2SPCombo); + } + else + { + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (gamemode_combo)->entry), sSOF2MPCombo); + } + } + + gtk_grab_add (project); + gtk_widget_show (project); + + g_pGameDescription->Dump(); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + char buf[1024]; + const char *r; + char *w; + + // convert path to unix format + for(r = gtk_entry_get_text (GTK_ENTRY (base)), w=buf; *r != '\0'; r++, w++) + *w = (*r == '\\') ? '/' : *r; + // add last slash + if(w != buf && *(w-1) != '/') *(w++) = '/'; + // terminate string + *w = '\0'; + SetKeyValue (g_qeglobals.d_project_entity, "basepath", buf); + + dir = gtk_entry_get_text (GTK_ENTRY (game)); + // Hack: hard coded wolf stuff + if (g_pGameDescription->mGameFile == "wolf.game") + { + if (!strlen(dir) || !stricmp(dir,"main")) + { + DeleteKey (g_qeglobals.d_project_entity, "gamename"); + } + else + { + SetKeyValue (g_qeglobals.d_project_entity, "gamename", dir); + } + } + // Hack: hard coded ET stuff + else if (g_pGameDescription->mGameFile == "et.game") + { + if (!strlen(dir) || !stricmp(dir,"etmain")) + { + DeleteKey (g_qeglobals.d_project_entity, "gamename"); + } + else + { + SetKeyValue (g_qeglobals.d_project_entity, "gamename", dir); + } + } + // Hack: hard coded Half-life stuff + else if (g_pGameDescription->mGameFile == "hl.game") + { + if (!strlen(dir) || !stricmp(dir,"valve")) + { + DeleteKey (g_qeglobals.d_project_entity, "gamename"); + } + else + { + SetKeyValue (g_qeglobals.d_project_entity, "gamename", dir); + } + } + else if (g_pGameDescription->mGameFile == "jk2.game" || g_pGameDescription->mGameFile == "ja.game") + { + if (!strlen(dir) || !stricmp(dir,"base")) + { + DeleteKey (g_qeglobals.d_project_entity, "gamename"); + } + else + { + SetKeyValue (g_qeglobals.d_project_entity, "gamename", dir); + } + } + // RIANT + // STVEF HACK + else if (g_pGameDescription->mGameFile == "stvef.game") + { + if (!strlen(dir) || !stricmp(dir,"baseEf")) + { + DeleteKey (g_qeglobals.d_project_entity, "gamename"); + } + else + { + SetKeyValue (g_qeglobals.d_project_entity, "gamename", dir); + } + } + else + { + if (!strlen(dir) || !strcmp(dir,"baseq3")) + { + DeleteKey (g_qeglobals.d_project_entity, "gamename"); + } + else + { + SetKeyValue (g_qeglobals.d_project_entity, "gamename", dir); + } + } + + // HACK: hardcoded wolf stuff + if (g_pGameDescription->mGameFile == "wolf.game") + { + // read from gamemode_combo + const char *gamemode = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO(gamemode_combo)->entry)); + if (!strlen(gamemode) || !strcmp(gamemode, sWolfSPCombo)) + { + SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "sp"); + } + else + { + SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "mp"); + } + } + + // RIANT + // JK2 HACK + if (g_pGameDescription->mGameFile == "jk2.game") + { + // read from gamemode_combo + const char *gamemode = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO(gamemode_combo)->entry)); + if (!strlen(gamemode) || !strcmp(gamemode, sJK2SPCombo)) + { + SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "sp"); + } + else + { + SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "mp"); + } + } + // TTimo + // JA HACK + if (g_pGameDescription->mGameFile == "ja.game") + { + // read from gamemode_combo + const char *gamemode = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO(gamemode_combo)->entry)); + if (!strlen(gamemode) || !strcmp(gamemode, sJASPCombo)) + { + SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "sp"); + } + else + { + SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "mp"); + } + } + + // RIANT + // STVEF HACK + if (g_pGameDescription->mGameFile == "stvef.game") + { + // read from gamemode_combo + const char *gamemode = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO(gamemode_combo)->entry)); + if (!strlen(gamemode) || !strcmp(gamemode, sSTVEFSPCombo)) + { + SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "sp"); + } + else + { + SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "mp"); + } + } + + g_qeglobals.m_strHomeMaps = g_qeglobals.m_strHomeGame; + const char* str = ValueForKey(g_qeglobals.d_project_entity, "gamename"); + if(str[0] == '\0') str = g_pGameDescription->mBaseGame.GetBuffer(); + g_qeglobals.m_strHomeMaps += str; + g_qeglobals.m_strHomeMaps += '/'; + + // RIANT + // SOF2 HACK + if (g_pGameDescription->mGameFile == "sof2.game") + { + // read from gamemode_combo + const char *gamemode = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO(gamemode_combo)->entry)); + if (!strlen(gamemode) || !strcmp(gamemode, sSOF2SPCombo)) + { + SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "sp"); + } + else + { + SetKeyValue (g_qeglobals.d_project_entity, "gamemode", "mp"); + } + } + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (brush))) + g_qeglobals.m_bBrushPrimitMode = TRUE; + else + g_qeglobals.m_bBrushPrimitMode = FALSE; + + SetKeyValue(g_qeglobals.d_project_entity, "brush_primit", (g_qeglobals.m_bBrushPrimitMode ? "1" : "0" )); + +// QE_CheckProjectEntity(); + + QE_SaveProject( g_PrefsDlg.m_strLastProject.GetBuffer() ); + } + + gtk_grab_remove (project); + gtk_widget_destroy (project); +} + +// ============================================================================= +// MapInfo dialog + +void DoMapInfo () +{ + static GtkWidget *dlg; + GtkWidget *vbox, *vbox2, *hbox, *table, *button, *label, *scr; + GtkWidget *brushes_entry, *entities_entry, *net_entry; + int loop = 1, ret = IDCANCEL; + + if (dlg != NULL) + return; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + load_window_pos(dlg, g_PrefsDlg.mWindowInfo.posMapInfoWnd); + + gtk_window_set_title (GTK_WINDOW (dlg), "Map Info"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + + table = gtk_table_new (3, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + brushes_entry = gtk_entry_new (); + gtk_widget_show (brushes_entry); + gtk_table_attach (GTK_TABLE (table), brushes_entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_editable (GTK_ENTRY (brushes_entry), FALSE); + + entities_entry = gtk_entry_new (); + gtk_widget_show (entities_entry); + gtk_table_attach (GTK_TABLE (table), entities_entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_editable (GTK_ENTRY (entities_entry), FALSE); + + net_entry = gtk_entry_new (); + gtk_widget_show (net_entry); + gtk_table_attach (GTK_TABLE (table), net_entry, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_editable (GTK_ENTRY (net_entry), FALSE); + + label = gtk_label_new ("Total Brushes"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Total Entities"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Net brush count\n(non entity)"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Close"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + label = gtk_label_new ("Entity breakdown"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + scr = gtk_scrolled_window_new ((GtkAdjustment*)NULL, (GtkAdjustment*)NULL); + gtk_widget_show (scr); + gtk_box_pack_start (GTK_BOX (vbox), scr, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (scr), 5); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scr), GTK_SHADOW_IN); + + GtkListStore* store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); + + { + GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(view), TRUE); + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Entity", renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + gtk_tree_view_column_set_sort_column_id(column, 0); + } + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Count", renderer, "text", 1, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + gtk_tree_view_column_set_sort_column_id(column, 1); + } + + gtk_widget_show(view); + + gtk_container_add(GTK_CONTAINER (scr), view); + } + + // Initialize fields + int TotalBrushes = 0, TotalEntities = 0, Net = 0; + + for (brush_t* pBrush = active_brushes.next; pBrush != &active_brushes; pBrush = pBrush->next) + { + TotalBrushes++; + if (pBrush->owner == world_entity) + Net++; + } + + typedef struct + { + const char *name; + int count; + } map_t; + + GSList *l, *entitymap = NULL; + map_t *entry; + + for (entity_t* pEntity = entities.next; pEntity != &entities; pEntity=pEntity->next) + { + TotalEntities++; + bool add = true; + + for (l = entitymap; l; l = g_slist_next (l)) + { + entry = (map_t*)l->data; + + if (strcmp (entry->name, pEntity->eclass->name) == 0) + { + entry->count++; + add = false; + break; + } + } + + if (add) + { + entry = (map_t*)qmalloc (sizeof (map_t)); + entry->name = pEntity->eclass->name; + entry->count = 1; + entitymap = g_slist_append (entitymap, entry); + } + } + + while (entitymap) + { + entry = (map_t*)entitymap->data; + char tmp[16]; + sprintf (tmp, "%d", entry->count); + GtkTreeIter iter; + gtk_list_store_append(GTK_LIST_STORE(store), &iter); + gtk_list_store_set(GTK_LIST_STORE(store), &iter, 0, entry->name, 1, tmp, -1); + free (entry); + entitymap = g_slist_remove (entitymap, entry); + } + + g_object_unref(G_OBJECT(store)); + + char tmp[16]; + sprintf (tmp, "%d", TotalBrushes); + gtk_entry_set_text (GTK_ENTRY (brushes_entry), tmp); + sprintf (tmp, "%d", TotalEntities); + gtk_entry_set_text (GTK_ENTRY (entities_entry), tmp); + sprintf (tmp, "%d", Net); + gtk_entry_set_text (GTK_ENTRY (net_entry), tmp); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + // save before exit + save_window_pos(dlg, g_PrefsDlg.mWindowInfo.posMapInfoWnd); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + dlg = NULL; +} + +// ============================================================================= +// Entity List dialog + +static void entitylist_select (GtkWidget *widget, gpointer data) +{ + GtkTreeView* view = GTK_TREE_VIEW(g_object_get_data (G_OBJECT (data), "entities")); + + GtkTreeSelection* selection = gtk_tree_view_get_selection(view); + + GtkTreeModel* model; + GtkTreeIter selected; + if(gtk_tree_selection_get_selected(selection, &model, &selected)) + { + entity_t* pEntity; + gtk_tree_model_get(model, &selected, 1, &pEntity, -1); + + if (pEntity) + { + for (epair_t* pEpair = pEntity->epairs; pEpair; pEpair = pEpair->next) + { + Select_Deselect (); + Select_Brush (pEntity->brushes.onext); + Sys_UpdateWindows(W_ALL); + } + } + } +} + +static gint entitylist_click (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + if (event->type == GDK_2BUTTON_PRESS) + { + entitylist_select (NULL, data); + return TRUE; + } + return FALSE; +} + +static void entitylist_selection_changed(GtkTreeSelection* selection, gpointer data) +{ + GtkListStore* store = GTK_LIST_STORE (g_object_get_data (G_OBJECT (data), "keyvalues")); + + gtk_list_store_clear(store); + + GtkTreeModel* model; + GtkTreeIter selected; + if(gtk_tree_selection_get_selected(selection, &model, &selected)) + { + entity_t* pEntity; + gtk_tree_model_get(model, &selected, 1, &pEntity, -1); + + if (pEntity) + { + for (epair_t* pEpair = pEntity->epairs; pEpair; pEpair = pEpair->next) + { + GtkTreeIter appended; + gtk_list_store_append(store, &appended); + gtk_list_store_set(store, &appended, 0, pEpair->key, 1, pEpair->value, -1); + } + } + } +} + +void DoEntityList () +{ + static GtkWidget *dlg; + GtkWidget *vbox, *hbox, *hbox2, *button, *scr; + int loop = 1, ret = IDCANCEL; + + if (dlg != NULL) + return; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + load_window_pos (dlg, g_PrefsDlg.mWindowInfo.posEntityInfoWnd); + + gtk_window_set_title (GTK_WINDOW (dlg), "Entities"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (TRUE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + scr = gtk_scrolled_window_new ((GtkAdjustment*)NULL, (GtkAdjustment*)NULL); + gtk_widget_show (scr); + gtk_box_pack_start (GTK_BOX (hbox), scr, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); + + { + GtkTreeStore* store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER); + + GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + g_signal_connect(G_OBJECT(view), "button_press_event", G_CALLBACK(entitylist_click), dlg); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + { + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); + g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(entitylist_selection_changed), dlg); + } + + gtk_widget_show(view); + + gtk_container_add(GTK_CONTAINER (scr), view); + g_object_set_data (G_OBJECT (dlg), "entities", view); + + { + { + GtkTreeIter child; + gtk_tree_store_append(store, &child, NULL); + gtk_tree_store_set(store, &child, 0, world_entity->eclass->name, 1, world_entity, -1); + } + + GSList *l, *entitymap = NULL; + typedef struct + { + GtkTreeIter node; + const char *name; + } map_t; + map_t *entry; + + for (entity_t* pEntity=entities.next; pEntity != &entities; pEntity=pEntity->next) + { + GtkTreeIter parent; + bool found = false; + + for (l = entitymap; l; l = g_slist_next (l)) + { + entry = (map_t*)l->data; + + if (strcmp (entry->name, pEntity->eclass->name) == 0) + { + parent = entry->node; + found = true; + break; + } + } + + if (!found) + { + gtk_tree_store_append(store, &parent, NULL); + gtk_tree_store_set(store, &parent, 0, pEntity->eclass->name, 1, NULL, -1); + + entry = (map_t*)malloc (sizeof(map_t)); + entitymap = g_slist_append (entitymap, entry); + entry->name = pEntity->eclass->name; + entry->node = parent; + } + + GtkTreeIter child; + gtk_tree_store_append(store, &child, &parent); + gtk_tree_store_set(store, &child, 0, pEntity->eclass->name, 1, pEntity, -1); + } + + while (entitymap) + { + free (entitymap->data); + entitymap = g_slist_remove (entitymap, entitymap->data); + } + } + + g_object_unref(G_OBJECT(store)); + } + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + scr = gtk_scrolled_window_new ((GtkAdjustment*)NULL, (GtkAdjustment*)NULL); + gtk_widget_show (scr); + gtk_box_pack_start (GTK_BOX (vbox), scr, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); + + { + GtkListStore* store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); + + GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Key", renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Value", renderer, "text", 1, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + gtk_widget_show(view); + + g_object_set_data(G_OBJECT(dlg), "keyvalues", store); + gtk_container_add(GTK_CONTAINER (scr), view); + + g_object_unref(G_OBJECT(store)); + } + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, TRUE, TRUE, 0); + + button = gtk_button_new_with_label ("Select"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (entitylist_select), dlg); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Close"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + save_window_pos (dlg, g_PrefsDlg.mWindowInfo.posMapInfoWnd); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + dlg = NULL; +} + +// ============================================================================= +// Rotate dialog + +static void rotatedlg_apply (GtkWidget *widget, gpointer data) +{ + GtkSpinButton *spin; + float f; + + spin = GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (data), "x")); + f = gtk_spin_button_get_value_as_float (spin); + if (f != 0.0) + Select_RotateAxis(0,f); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin), 0.0f); // reset to 0 on Apply + + spin = GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (data), "y")); + f = gtk_spin_button_get_value_as_float (spin); + if (f != 0.0) + Select_RotateAxis(1,f); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin), 0.0f); + + spin = GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (data), "z")); + f = gtk_spin_button_get_value_as_float (spin); + if (f != 0.0) + Select_RotateAxis(2,f); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin), 0.0f); +} + +void DoRotateDlg () +{ + GtkWidget *dlg, *hbox, *vbox, *table, *label, *button; + GtkWidget *x, *y, *z; + GtkObject *adj; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Arbitrary rotation"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + table = gtk_table_new (3, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new (" X "); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new (" Y "); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new (" Z "); + + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + adj = gtk_adjustment_new (0, -359, 359, 1, 10, 10); + x = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + g_object_set_data (G_OBJECT (dlg), "x", x); + gtk_widget_show (x); + gtk_table_attach (GTK_TABLE (table), x, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (x, 60, -2); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (x), TRUE); + + adj = gtk_adjustment_new (0, -359, 359, 1, 10, 10); + y = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + g_object_set_data (G_OBJECT (dlg), "y", y); + gtk_widget_show (y); + gtk_table_attach (GTK_TABLE (table), y, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (y), TRUE); + + adj = gtk_adjustment_new (0, -359, 359, 1, 10, 10); + z = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + g_object_set_data (G_OBJECT (dlg), "z", z); + gtk_widget_show (z); + gtk_table_attach (GTK_TABLE (table), z, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (z), TRUE); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + + button = gtk_button_new_with_label ("Apply"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (rotatedlg_apply), dlg); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + rotatedlg_apply (button, dlg); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// Gamma dialog + +void DoGamma () +{ + GtkWidget *dlg, *vbox, *hbox, *label, *button, *entry; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Gamma"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0); + + label = gtk_label_new ("0.0 is brightest\n1.0 is darkest"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); + + label = gtk_label_new ("You must restart for the\nsettings to take effect"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + + // Initialize dialog + char buf[16]; + sprintf (buf, "%1.1f", g_qeglobals.d_savedinfo.fGamma); + gtk_entry_set_text (GTK_ENTRY (entry), buf); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + g_qeglobals.d_savedinfo.fGamma = g_strtod (gtk_entry_get_text (GTK_ENTRY (entry)), NULL); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// Find Brush Dialog + +// helper function to walk through the active brushes only and drop the regioned out ones +bool WalkRegionBrush (brush_t **b, entity_t *e) +{ + brush_t *b2; + do + { + for(b2=active_brushes.next ; b2 != &active_brushes ; b2=b2->next) + { + if (b2==*b) + break; // this is an active brush + } + if (b2==&active_brushes) + { + // this is a regioned out brush + *b = (*b)->onext; + if (*b == &e->brushes) + { + Sys_Status ("No such brush", 0); + return false; + } + } + } while (b2==&active_brushes); + return true; +} + +void SelectBrush (int entitynum, int brushnum) +{ + entity_t *e; + brush_t *b; + int i; + + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=503 + // making this work when regioning is on too + + if (entitynum == 0) + e = world_entity; + else + { + e = entities.next; + while (--entitynum) + { + e = e->next; + if (e == &entities) + { + Sys_Status ("No such entity", 0); + return; + } + if (region_active) + { + // we need to make sure we walk to the next 'active' entity to have a valid --entitynum + // that is, find a brush that belongs to this entity in the active brushes + do + { + for (b = active_brushes.next ; b != &active_brushes ; b=b->next) + { + if (b->owner == e) + break; // this is an active entity + } + if (b==&active_brushes) + { + // this is a regioned out entity + e = e->next; + // don't walk past the end either + if (e == &entities) + { + Sys_Status ("No such entity", 0); + return; + } + } + } while(b==&active_brushes); + } + } + } + + b = e->brushes.onext; + if (b == &e->brushes) + { + Sys_Status ("No such brush", 0); + return; + } + if (region_active) + { + if (!WalkRegionBrush(&b, e)) + return; + } + + while (brushnum--) + { + b = b->onext; + if (b == &e->brushes) + { + Sys_Status ("No such brush", 0); + return; + } + if (region_active) + { + if (!WalkRegionBrush(&b, e)) + return; + } + } + + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + + Sys_UpdateWindows (W_ALL); + for (i = 0; i < 3; i++) + { + if (g_pParentWnd->GetXYWnd()) + g_pParentWnd->GetXYWnd()->GetOrigin()[i] = (b->mins[i] + b->maxs[i])/2; + + if (g_pParentWnd->GetXZWnd()) + g_pParentWnd->GetXZWnd()->GetOrigin()[i] = (b->mins[i] + b->maxs[i])/2; + + if (g_pParentWnd->GetYZWnd()) + g_pParentWnd->GetYZWnd()->GetOrigin()[i] = (b->mins[i] + b->maxs[i])/2; + } + + Sys_Status ("Selected", 0); +} + +static void GetSelectionIndex (int *ent, int *brush) +{ + brush_t *b, *b2; + entity_t *entity; + + *ent = *brush = 0; + + b = selected_brushes.next; + if (b == &selected_brushes) + return; + + // find entity + if (b->owner != world_entity) + { + (*ent)++; + for (entity = entities.next; entity != &entities; entity=entity->next, (*ent)++) + ; + } + + // find brush + for (b2=b->owner->brushes.onext; b2 != b && b2 != &b->owner->brushes; b2=b2->onext, (*brush)++) + ; +} + +void DoFind () +{ + GtkWidget *dlg, *vbox, *hbox, *table, *label, *button, *entity, *brush; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Find Brush"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Entity number"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("Brush number"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + entity = gtk_entry_new (); + gtk_widget_show (entity); + gtk_table_attach (GTK_TABLE (table), entity, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + brush = gtk_entry_new (); + gtk_widget_show (brush); + gtk_table_attach (GTK_TABLE (table), brush, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + + // Initialize dialog + char buf[16]; + int ent, br; + + GetSelectionIndex (&ent, &br); + sprintf (buf, "%i", ent); + gtk_entry_set_text (GTK_ENTRY (entity), buf); + sprintf (buf, "%i", br); + gtk_entry_set_text (GTK_ENTRY (brush), buf); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + const char *entstr = gtk_entry_get_text (GTK_ENTRY (entity)); + const char *brushstr = gtk_entry_get_text (GTK_ENTRY (brush)); + SelectBrush (atoi(entstr), atoi(brushstr)); + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// Arbitrary Sides dialog + +void DoSides (bool bCone, bool bSphere, bool bTorus) +{ + GtkWidget *dlg, *vbox, *hbox, *button, *label, *entry; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Arbitrary sides"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + label = gtk_label_new ("Sides:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + const char *str = gtk_entry_get_text (GTK_ENTRY (entry)); + + if (bCone) + Brush_MakeSidedCone(atoi(str)); + else if (bSphere) + Brush_MakeSidedSphere(atoi(str)); + else + Brush_MakeSided (atoi(str)); + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// New Patch dialog + +void DoNewPatchDlg () +{ + GtkWidget *dlg, *hbox, *table, *vbox, *label, *button, *combo; + GtkWidget *width, *height; + GList *combo_list = (GList*)NULL; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Patch density"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Width:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Height:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + combo_list = g_list_append (combo_list, (void *)"3"); + combo_list = g_list_append (combo_list, (void *)"5"); + combo_list = g_list_append (combo_list, (void *)"7"); + combo_list = g_list_append (combo_list, (void *)"9"); + combo_list = g_list_append (combo_list, (void *)"11"); + combo_list = g_list_append (combo_list, (void *)"13"); + combo_list = g_list_append (combo_list, (void *)"15"); + + combo = gtk_combo_new (); + width = GTK_COMBO (combo)->entry; + gtk_combo_set_popdown_strings (GTK_COMBO (combo), combo_list); + gtk_widget_show (combo); + gtk_table_attach (GTK_TABLE (table), combo, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + combo = gtk_combo_new (); + height = GTK_COMBO (combo)->entry; + gtk_combo_set_popdown_strings (GTK_COMBO (combo), combo_list); + gtk_widget_show (combo); + gtk_table_attach (GTK_TABLE (table), combo, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + + // Initialize dialog + g_list_free (combo_list); + gtk_entry_set_text (GTK_ENTRY (width), "3"); + gtk_entry_set_editable (GTK_ENTRY (width), FALSE); + gtk_entry_set_text (GTK_ENTRY (height), "3"); + gtk_entry_set_editable (GTK_ENTRY (height), FALSE); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + const char* w = gtk_entry_get_text (GTK_ENTRY (width)); + const char* h = gtk_entry_get_text (GTK_ENTRY (height)); + + Patch_GenericMesh(atoi (w), atoi (h), g_pParentWnd->ActiveXY ()->GetViewType ()); + Sys_UpdateWindows (W_ALL); + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// New Patch dialog + +void DoScaleDlg () +{ + GtkWidget *dlg, *hbox, *table, *vbox, *label, *button; + GtkWidget *x, *y, *z; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Scale"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + table = gtk_table_new (3, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("X:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Y:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Z:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + x = gtk_entry_new (); + gtk_widget_show (x); + gtk_table_attach (GTK_TABLE (table), x, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + y = gtk_entry_new (); + gtk_widget_show (y); + gtk_table_attach (GTK_TABLE (table), y, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + z = gtk_entry_new (); + gtk_widget_show (z); + gtk_table_attach (GTK_TABLE (table), z, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + + // Initialize dialog + gtk_entry_set_text (GTK_ENTRY (x), "1.0"); + gtk_entry_set_text (GTK_ENTRY (y), "1.0"); + gtk_entry_set_text (GTK_ENTRY (z), "1.0"); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + float sx, sy, sz; + sx = atof (gtk_entry_get_text (GTK_ENTRY (x))); + sy = atof (gtk_entry_get_text (GTK_ENTRY (y))); + sz = atof (gtk_entry_get_text (GTK_ENTRY (z))); + + if (sx > 0 && sy > 0 && sz > 0) + { + Select_Scale(sx, sy, sz); + Sys_UpdateWindows (W_ALL); + } + else + Sys_Printf("Warning.. Tried to scale by a zero value."); + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// Thicken Patch dialog + +void DoThickenDlg () +{ + GtkWidget *dlg, *vbox, *hbox, *vbox2, *button, *label; + GtkWidget *amount, *seams, *group; + int loop = 1, ret = IDCANCEL; + static qboolean bGroupResult = true; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Thicken Patch"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + + label = gtk_label_new ("This produces a set of patches\n" + "that contains the original patch along with the\n" + "'thick' patch and an optimal set of seam patches."); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + + label = gtk_label_new ("Amount:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + + amount = gtk_entry_new (); + gtk_widget_show (amount); + gtk_box_pack_start (GTK_BOX (hbox), amount, FALSE, FALSE, 0); + + seams = gtk_check_button_new_with_label ("Seams"); + gtk_widget_show (seams); + gtk_box_pack_start (GTK_BOX (hbox), seams, FALSE, FALSE, 0); + + // bGroupResult + group = gtk_check_button_new_with_label("Result to func_group"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(group), bGroupResult); + gtk_box_pack_start(GTK_BOX(vbox), group, FALSE, FALSE, 0); + gtk_widget_show(group); + + + // Initialize dialog + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (seams), TRUE); + gtk_entry_set_text (GTK_ENTRY (amount), "8"); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(group))) + bGroupResult = true; + else + bGroupResult = false; + Patch_Thicken (atoi (gtk_entry_get_text (GTK_ENTRY (amount))), + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (seams)), bGroupResult); + Sys_UpdateWindows (W_ALL); + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// About dialog (no program is complete without one) + +void about_button_changelog (GtkWidget *widget, gpointer data) +{ + Str log; + log = g_strAppPath; + log += "changelog.txt"; + OpenURL(log.GetBuffer()); +} + +void about_button_credits (GtkWidget *widget, gpointer data) +{ + Str cred; + cred = g_strAppPath; + cred += "credits.html"; + OpenURL(cred.GetBuffer()); +} + +void DoAbout () +{ + GtkWidget *dlg, *vbox, *vbox2, *hbox, *frame, *table, *label, *pixmap, *button, *sc_extensions, *text_extensions; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "About GtkRadiant"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, FALSE, 0); + + frame = gtk_frame_new ((char*)NULL); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox2), frame, FALSE, FALSE, 0); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + + pixmap = new_pixmap (g_pParentWnd->m_pWidget, "logo.bmp"); + gtk_widget_show (pixmap); + gtk_container_add (GTK_CONTAINER (frame), pixmap); + + label = gtk_label_new ("GtkRadiant " RADIANT_VERSION "\n" + __DATE__ "\n\n" + RADIANT_ABOUTMSG "\n\n" + "By qeradiant.com\n\n" + "This product contains software technology\n" + "from id Software, Inc. ('id Technology').\n" + "id Technology 2000 id Software,Inc.\n\n" + "GtkRadiant is unsupported, however\n" + "you may report your problems at\n" + "http://zerowing.idsoftware.com/bugzilla" + ); + + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + + button = gtk_button_new_with_label ("Credits"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (about_button_credits), NULL); + + button = gtk_button_new_with_label ("Changelog"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (about_button_changelog), NULL); + + frame = gtk_frame_new ("OpenGL Properties"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0); + + table = gtk_table_new (3, 2, FALSE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + label = gtk_label_new ("Vendor:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Version:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Renderer:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ((char*)qglGetString (GL_VENDOR)); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ((char*)qglGetString (GL_VERSION)); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ((char*)qglGetString (GL_RENDERER)); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + frame = gtk_frame_new ("OpenGL Extensions"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (frame), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + sc_extensions = gtk_scrolled_window_new(NULL, NULL); + gtk_box_pack_start(GTK_BOX(hbox), sc_extensions, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sc_extensions), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sc_extensions), GTK_SHADOW_IN); + gtk_widget_show(sc_extensions); + + text_extensions = gtk_text_view_new(); + gtk_text_view_set_editable(GTK_TEXT_VIEW(text_extensions), FALSE); + gtk_container_add (GTK_CONTAINER (sc_extensions), text_extensions); + GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_extensions)); + gtk_text_buffer_set_text(buffer, (char *)qglGetString(GL_EXTENSIONS), -1); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text_extensions), GTK_WRAP_WORD);; + gtk_widget_show(text_extensions); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// Command List dialog + +void DoCommandListDlg () +{ + GtkWidget *dlg, *vbox, *hbox, *scr, *button; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Mapped Commands"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + gtk_window_set_default_size (GTK_WINDOW (dlg), 400, 400); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + scr = gtk_scrolled_window_new ((GtkAdjustment*)NULL, (GtkAdjustment*)NULL); + gtk_widget_show (scr); + gtk_box_pack_start (GTK_BOX (hbox), scr, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scr), GTK_SHADOW_IN); + + { + GtkListStore* store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); + + GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Command", renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Key", renderer, "text", 1, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + gtk_widget_show(view); + gtk_container_add(GTK_CONTAINER (scr), view); + + { + // Initialize dialog + CString path; + path = g_strTempPath; + path += "commandlist.txt"; + + GSList *cmds = NULL; + int n; + + for (n = 0; n < g_nCommandCount; n++) + cmds = g_slist_append (cmds, g_Commands[n].m_strCommand); + cmds = g_slist_sort (cmds, (gint (*)(const void *, const void *))strcmp); + + Sys_Printf("Writing the command list to %s", path.GetBuffer() ); + FILE* fileout = fopen (path.GetBuffer (), "wt"); + + while (cmds) + { + for (n = 0; n < g_nCommandCount; n++) + if (cmds->data == g_Commands[n].m_strCommand) + break; + + char c = g_Commands[n].m_nKey; + CString strLine, strMod(""), strKeys (c); + + for (int k = 0; k < g_nKeyCount; k++) + { + if (g_Keys[k].m_nVKKey == g_Commands[n].m_nKey) + { + strKeys = g_Keys[k].m_strName; + break; + } + } + + if (g_Commands[n].m_nModifiers & RAD_SHIFT) + strMod = "Shift"; + if (g_Commands[n].m_nModifiers & RAD_ALT) + strMod += (strMod.GetLength() > 0) ? " + Alt" : "Alt"; + if (g_Commands[n].m_nModifiers & RAD_CONTROL) + strMod += (strMod.GetLength() > 0) ? " + Control" : "Control"; + if (strMod.GetLength() > 0) + strMod += " + "; + strMod += strKeys; + + { + GtkTreeIter iter; + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, g_Commands[n].m_strCommand, 1, strMod.GetBuffer (), -1); + } + + if (fileout != NULL) + { + strLine.Format("%-25s %s\r\n", g_Commands[n].m_strCommand, strMod.GetBuffer ()); + fputs (strLine.GetBuffer (), fileout); + } + + cmds = g_slist_remove (cmds, cmds->data); + } + + if (fileout != NULL) + fclose (fileout); + } + + g_object_unref(G_OBJECT(store)); + } + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Close"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// Texture List dialog + +void DoTextureListDlg () +{ + GtkWidget *dlg, *vbox, *hbox, *scr, *button; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Textures"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + gtk_window_set_default_size (GTK_WINDOW (dlg), 400, 400); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + scr = gtk_scrolled_window_new ((GtkAdjustment*)NULL, (GtkAdjustment*)NULL); + gtk_widget_show (scr); + gtk_box_pack_start (GTK_BOX (hbox), scr, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scr), GTK_SHADOW_IN); + + GtkWidget* texture_list; + + { + GtkListStore* store = gtk_list_store_new(1, G_TYPE_STRING); + + GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + gtk_widget_show(view); + gtk_container_add(GTK_CONTAINER (scr), view); + + { + // Initialize dialog + GSList *textures = (GSList*)NULL; + FillTextureMenu(&textures); + while (textures != NULL) + { + { + GtkTreeIter iter; + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, (gchar*)textures->data, -1); + } + free (textures->data); + textures = g_slist_remove (textures, textures->data); + } + } + + g_object_unref(G_OBJECT(store)); + + texture_list = view; + } + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Load"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Close"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(texture_list)); + + GtkTreeModel* model; + GtkTreeIter iter; + if(gtk_tree_selection_get_selected(selection, &model, &iter)) + { + GtkTreePath* path = gtk_tree_model_get_path(model, &iter); + if(gtk_tree_path_get_depth(path) == 1) + Texture_ShowDirectory(gtk_tree_path_get_indices(path)[0] + CMD_TEXTUREWAD); + gtk_tree_path_free(path); + } + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// Cap dialog + +int DoCapDlg (int *type, bool *b_GroupResult) +{ + GtkWidget *dlg, *vbox, *hbox, *table, *pixmap, *button, *group_toggle, *radio_vbox; + GtkWidget *bevel, *endcap, *ibevel, *iendcap; + GSList *group = (GSList*)NULL; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Cap"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + // Gef: Added a vbox to contain the toggle buttons + radio_vbox = gtk_vbox_new(FALSE, 4); + gtk_container_add(GTK_CONTAINER(hbox), radio_vbox); + gtk_widget_show(radio_vbox); + + table = gtk_table_new (4, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (radio_vbox), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + pixmap = new_pixmap (g_pParentWnd->m_pWidget, "cap_bevel.bmp"); + gtk_widget_show (pixmap); + gtk_table_attach (GTK_TABLE (table), pixmap, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + pixmap = new_pixmap (g_pParentWnd->m_pWidget, "cap_endcap.bmp"); + gtk_widget_show (pixmap); + gtk_table_attach (GTK_TABLE (table), pixmap, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + pixmap = new_pixmap (g_pParentWnd->m_pWidget, "cap_ibevel.bmp"); + gtk_widget_show (pixmap); + gtk_table_attach (GTK_TABLE (table), pixmap, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + pixmap = new_pixmap (g_pParentWnd->m_pWidget, "cap_iendcap.bmp"); + gtk_widget_show (pixmap); + gtk_table_attach (GTK_TABLE (table), pixmap, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + bevel = gtk_radio_button_new_with_label (group, "Bevel"); + gtk_widget_show (bevel); + gtk_table_attach (GTK_TABLE (table), bevel, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL | GTK_EXPAND), + (GtkAttachOptions) (0), 0, 0); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (bevel)); + + endcap = gtk_radio_button_new_with_label (group, "Endcap"); + gtk_widget_show (endcap); + gtk_table_attach (GTK_TABLE (table), endcap, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL | GTK_EXPAND), + (GtkAttachOptions) (0), 0, 0); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (endcap)); + + ibevel = gtk_radio_button_new_with_label (group, "Inverted Bevel"); + gtk_widget_show (ibevel); + gtk_table_attach (GTK_TABLE (table), ibevel, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL | GTK_EXPAND), + (GtkAttachOptions) (0), 0, 0); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (ibevel)); + + iendcap = gtk_radio_button_new_with_label (group, "Inverted Endcap"); + gtk_widget_show (iendcap); + gtk_table_attach (GTK_TABLE (table), iendcap, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_FILL | GTK_EXPAND), + (GtkAttachOptions) (0), 0, 0); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (iendcap)); + + // Gef: added radio toggle for func_grouping capped patches + group_toggle = gtk_check_button_new_with_label("Result to func_group"); + gtk_container_add(GTK_CONTAINER(radio_vbox), group_toggle); + gtk_widget_show(group_toggle); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + // Gef: Set the state of the func_group toggle + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (group_toggle), *b_GroupResult); + + // Initialize dialog + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bevel), TRUE); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (bevel))) + *type = BEVEL; //*type = CapDialog::BEVEL; + else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (endcap))) + *type = ENDCAP; //*type = CapDialog::ENDCAP; + else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ibevel))) + *type = IBEVEL; // *type = CapDialog::IBEVEL; + else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (iendcap))) + *type = IENDCAP; // *type = CapDialog::IENDCAP; + + // Gef: Added toggle for optional cap func_grouping + *b_GroupResult = (bool *)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(group_toggle)); + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + return ret; +} + +// ============================================================================= +// Scripts dialog + +void DoScriptsDlg () +{ + GtkWidget *dlg, *vbox, *vbox2, *hbox, *label, *button, *scr; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Available Scripts - Not Implemented Yet"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + label = gtk_label_new ("WARNING: BrushScripting is in a highly experimental state and is\n" + "far from complete. If you attempt to use them it is VERY LIKELY\n" + "that Radiant will crash. Save your work before attempting to\n" + "make use of any scripting features."); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0); + + scr = gtk_scrolled_window_new ((GtkAdjustment*)NULL, (GtkAdjustment*)NULL); + gtk_widget_show (scr); + gtk_box_pack_start (GTK_BOX (hbox), scr, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scr), GTK_SHADOW_IN); + + GtkWidget* scripts_list; + + { + GtkListStore* store = gtk_list_store_new(1, G_TYPE_STRING); + + GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + gtk_widget_show(view); + gtk_container_add(GTK_CONTAINER (scr), view); + + { + // Initialize dialog + CString strINI; + strINI = g_strGameToolsPath; + strINI += "/scripts.ini"; + FILE *f; + + f = fopen (strINI.GetBuffer(), "rt"); + if (f != NULL) + { + char line[1024], *ptr; + + // read section names + while (fgets (line, 1024, f) != 0) + { + if (line[0] != '[') + continue; + + ptr = strchr (line, ']'); + *ptr = '\0'; + + { + GtkTreeIter iter; + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, line, -1); + } + } + fclose (f); + } + } + + g_object_unref(G_OBJECT(store)); + + scripts_list = view; + } + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Run"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("New..."); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + gtk_widget_set_sensitive (button, FALSE); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Edit..."); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + gtk_widget_set_sensitive (button, FALSE); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Close"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(scripts_list)); + + GtkTreeModel* model; + GtkTreeIter iter; + if(gtk_tree_selection_get_selected(selection, &model, &iter)) + { + char* script; + gtk_tree_model_get(model, &iter, 0, &script, -1); + RunScriptByName(script, true); + g_free(script); + } + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// dialog + +int DoBSInputDlg (const char *fields[5], float values[5]) +{ + GtkWidget *dlg, *vbox, *hbox, *label, *button; + GtkWidget *entries[5]; + int i, loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "BrushScript Input"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + // Create entries and initialize them + for (i = 0; i < 5; i++) + { + if (strlen (fields[i]) == 0) + continue; + + label = gtk_label_new (fields[i]); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + entries[i] = gtk_entry_new (); + gtk_widget_show (entries[i]); + gtk_box_pack_start (GTK_BOX (vbox), entries[i], TRUE, TRUE, 0); + + char buf[32]; + sprintf (buf, "%f", values[i]); + gtk_entry_set_text (GTK_ENTRY (entries[i]), buf); + } + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + for (i = 0; i < 5; i++) + { + if (strlen (fields[i]) == 0) + continue; + + values[i] = atof (gtk_entry_get_text (GTK_ENTRY (entries[i]))); + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + return ret; +} + +// ============================================================================= +// TextureLayout dialog + +int DoTextureLayout (float *fx, float *fy) +{ + GtkWidget *dlg, *vbox, *hbox, *table, *label, *button; + GtkWidget *x, *y; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Patch texture layout"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + label = gtk_label_new ("Texture will be fit across the patch based\n" + "on the x and y values given. Values of 1x1\n" + "will \"fit\" the texture. 2x2 will repeat\n" + "it twice, etc."); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Texture x:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Texture y:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + x = gtk_entry_new (); + gtk_widget_show (x); + gtk_table_attach (GTK_TABLE (table), x, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + y = gtk_entry_new (); + gtk_widget_show (y); + gtk_table_attach (GTK_TABLE (table), y, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + // Initialize + gtk_entry_set_text (GTK_ENTRY (x), "4.0"); + gtk_entry_set_text (GTK_ENTRY (y), "4.0"); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + *fx = atof (gtk_entry_get_text (GTK_ENTRY (x))); + *fy = atof (gtk_entry_get_text (GTK_ENTRY (y))); + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + return ret; +} + +// ============================================================================= +// Name dialog + +char* DoNameDlg (const char* title) +{ + GtkWidget *dlg, *vbox, *hbox, *label, *button, *entry; + int loop = 1, ret = IDCANCEL; + char *str; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), title); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + label = gtk_label_new ("Name:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + str = strdup (gtk_entry_get_text (GTK_ENTRY (entry))); + else + str = NULL; + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + return str; +} + +// ============================================================================= +// NewProject dialog + +char* DoNewProjectDlg () +{ + GtkWidget *dlg, *vbox, *hbox, *label, *button, *entry, *check; + int loop = 1, ret = IDCANCEL; + char *str; + + // start by a warning message + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=459 + CString msg; + msg = "Are you sure you want a new project?\n"; + msg += "Please note that creating a new project is not the prefered way to setup GtkRadiant for mod editing.\n"; + msg += "Check http://www.qeradiant.com/faq/index.cgi?file=220 for more information"; + if (gtk_MessageBox(NULL, msg.GetBuffer(), "Confirm", MB_YESNO, "http://www.qeradiant.com/faq/index.cgi?file=220" ) == IDNO) + { + return NULL; + } + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "New Project"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + label = gtk_label_new ("This will create a new directory beneath your\n" + "game path based on the project name you give."); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + label = gtk_label_new ("Project name:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0); + + check = gtk_check_button_new_with_label ("Include game dll files"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, TRUE, TRUE, 0); + gtk_widget_set_sensitive (check, FALSE); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + str = strdup (gtk_entry_get_text (GTK_ENTRY (entry))); + else + str = NULL; + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + return str; +} + +// ============================================================================= +// Text Editor dialog + +// master window widget +static GtkWidget *text_editor = NULL; +static GtkWidget *text_widget; // slave, text widget from the gtk editor + +static gint editor_delete (GtkWidget *widget, gpointer data) +{ + if (gtk_MessageBox (widget, "Close the shader editor ?", "Radiant", MB_YESNO) == IDNO) + return TRUE; + + gtk_widget_hide (text_editor); + + return TRUE; +} + +static void editor_save (GtkWidget *widget, gpointer data) +{ + FILE *f = fopen ((char*)g_object_get_data (G_OBJECT (data), "filename"), "w"); + gpointer text = g_object_get_data (G_OBJECT (data), "text"); + + if (f == NULL) + { + gtk_MessageBox (GTK_WIDGET(data), "Error saving file !"); + return; + } + + char *str = gtk_editable_get_chars (GTK_EDITABLE (text), 0, -1); + fwrite (str, 1, strlen (str), f); + fclose (f); +} + +static void editor_close (GtkWidget *widget, gpointer data) +{ + if (gtk_MessageBox (text_editor, "Close the shader editor ?", "Radiant", MB_YESNO) == IDNO) + return; + + gtk_widget_hide (text_editor); +} + +// several attempts +// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=355 +#if 0 +#ifdef _WIN32 + +HWND FindEditWindow() +{ + return FindWindow("TFormEditPadLite", NULL); +} + +HWND FindEditWindow() +{ + HWND hwnd = FindWindow("TFormEditPadLite", NULL); + if (hwnd) + { + hwnd = FindWindowEx(hwnd, NULL, "TPanel", NULL); + if (hwnd) + { + hwnd = FindWindowEx(hwnd, NULL, "TPanel", NULL); + if (hwnd) + { + hwnd = FindWindowEx(hwnd, NULL, "TEditPadEditor", NULL); + if (hwnd) + { + hwnd = FindWindowEx(hwnd, NULL, "TWinControlProxy", NULL); + return hwnd; + } + } + } + } + return NULL; +} + +HWND FindEditWindow() +{ + HWND hwnd = FindWindow("TFormEditPadLite", NULL); + if (hwnd) + { + hwnd = FindWindowEx(hwnd, NULL, "TPanel", NULL); + if (hwnd) + { + hwnd = FindWindowEx(hwnd, NULL, "TPanel", NULL); + if (hwnd) + { + hwnd = FindWindowEx(hwnd, NULL, "TPanel", NULL); + if (hwnd) + { + hwnd = FindWindowEx(hwnd, NULL, "TFrameSearchReplace", NULL); + if (hwnd) + { + hwnd = FindWindowEx(hwnd, NULL, "TJGStringEditorControl", NULL); + return hwnd; + } + } + } + } + } + return NULL; +} + +HWND FindEditWindow() +{ + HWND hwnd = FindWindow("TEditPadForm", NULL); + HWND hwndEdit = NULL; + if (hwnd != NULL) + { + HWND hwndTab = FindWindowEx(hwnd, NULL, "TTabControl", NULL); + if (hwndTab != NULL) + { + hwndEdit = FindWindowEx(hwndTab, NULL, "TRicherEdit", NULL); + } + } + return hwndEdit; +} +#endif +#endif // #if 0 + +static void CreateGtkTextEditor () +{ + GtkWidget *dlg; + GtkWidget *vbox, *hbox, *button, *scr, *text; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (editor_delete), NULL); + gtk_window_set_default_size (GTK_WINDOW (dlg), 600, 300); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + scr = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scr); + gtk_box_pack_start (GTK_BOX (vbox), scr, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); + + text = gtk_text_view_new(); + gtk_container_add (GTK_CONTAINER (scr), text); + gtk_widget_show (text); + g_object_set_data (G_OBJECT (dlg), "text", text); + gtk_text_view_set_editable (GTK_TEXT_VIEW(text), TRUE); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("Close"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (editor_close), dlg); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Save"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (editor_save), dlg); + gtk_widget_set_usize (button, 60, -2); + + text_editor = dlg; + text_widget = text; +} + +static void DoGtkTextEditor (const char* filename, guint cursorpos) +{ + if (!text_editor) + CreateGtkTextEditor(); // build it the first time we need it + + // Load file + FILE *f = fopen (filename, "r"); + + if (f == NULL) + { + Sys_Printf("Unable to load file %s in shader editor.\n", filename); + gtk_widget_hide (text_editor); + } + else + { + fseek (f, 0, SEEK_END); + int len = ftell (f); + void *buf = qmalloc (len); + void *old_filename; + + rewind (f); + fread (buf, 1, len, f); + + gtk_window_set_title (GTK_WINDOW (text_editor), filename); + + GtkTextBuffer* text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_widget)); + gtk_text_buffer_set_text(text_buffer, (char*)buf, len); + + old_filename = g_object_get_data (G_OBJECT (text_editor), "filename"); + if (old_filename) + free(old_filename); + g_object_set_data (G_OBJECT (text_editor), "filename", strdup (filename)); + + // trying to show later + gtk_widget_show (text_editor); + +#ifdef _WIN32 + while (gtk_events_pending ()) + gtk_main_iteration (); +#endif + + // only move the cursor if it's not exceeding the size.. + // NOTE: this is erroneous, cursorpos is the offset in bytes, not in characters + // len is the max size in bytes, not in characters either, but the character count is below that limit.. + // thinking .. the difference between character count and byte count would be only because of CR/LF? + { + GtkTextIter text_iter; + // character offset, not byte offset + gtk_text_buffer_get_iter_at_offset(text_buffer, &text_iter, cursorpos); + gtk_text_buffer_place_cursor(text_buffer, &text_iter); + } + +#ifdef _WIN32 + gtk_widget_queue_draw(text_widget); +#endif + + free (buf); + fclose (f); + } +} + +void DoTextEditor (const char* filename, int cursorpos) +{ + CString strEditCommand; +#ifdef _WIN32 + if (g_PrefsDlg.m_bUseWin32Editor) + { + Sys_Printf("opening file '%s' (line %d info ignored)\n", filename); + ShellExecute((HWND)GDK_WINDOW_HWND (g_pParentWnd->m_pWidget->window), "open", filename, NULL, NULL, SW_SHOW ); + return; + } +#else + // check if a custom editor is set + if((g_PrefsDlg.m_bUseCustomEditor) && (g_PrefsDlg.m_strEditorCommand.GetLength() > 0)) + { + strEditCommand = g_PrefsDlg.m_strEditorCommand; + strEditCommand += " \""; + strEditCommand += filename; + strEditCommand += "\""; + + Sys_Printf("Launching: %s\n", strEditCommand.GetBuffer()); + // note: linux does not return false if the command failed so it will assume success + if (Q_Exec(NULL, (char *)strEditCommand.GetBuffer(), NULL, true) == false) + { + Sys_FPrintf(SYS_WRN, "Warning: Failed to execute %s, using default\n", strEditCommand.GetBuffer()); + } + else + { + // the command (appeared) to run successfully, no need to do anything more + return; + } + } +#endif + + DoGtkTextEditor (filename, cursorpos); + + // old win32 code with EditPad bindings, broken + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=355 +#if 0 + strEditCommand = g_strAppPath.GetBuffer(); + strEditCommand += "editpad.exe"; + strEditCommand += " \""; + strEditCommand += filename; + strEditCommand += "\""; + if (Q_Exec(NULL, (char *)strEditCommand.GetBuffer(), NULL, true) == false) + { + Sys_FPrintf(SYS_WRN, "WARNING: Gtk shader editor is not fully functional on windows in general and unstable on win98 in particular.\n"); + Sys_FPrintf(SYS_WRN, " you can use EditPad instead (install it in Radiant's directory): http://www.qeradiant.com/?data=files&files_dir=18\n"); + DoGtkTextEditor (filename, cursorpos); + } + else + { + // TTimo: we used to call Delay here, to continue processing messages. But it seems to induce a lot of instabilities. + // so now the user will simply have to wait. + Sleep( 1500 ); + + // now grab the edit window and scroll to the shader we want to edit + HWND hwndEdit = FindEditWindow(); + + if (hwndEdit != NULL) + PostMessage(hwndEdit, EM_SETSEL, cursorpos, cursorpos); + else + Sys_Printf("Unable to load shader editor.\n"); + } +#endif +} + +// ============================================================================= +// Light Intensity dialog + +int DoLightIntensityDlg (int *intensity) +{ + GtkWidget *dlg, *vbox, *hbox, *label, *button, *entry; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Light intensity"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + GtkAccelGroup *accel_group = gtk_accel_group_new (); + gtk_window_add_accel_group (GTK_WINDOW (dlg), accel_group); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + label = gtk_label_new ("ESC for default, ENTER to validate"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_add_accelerator (button, "clicked", accel_group, + GDK_Return, (GdkModifierType)0, GTK_ACCEL_VISIBLE); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_add_accelerator (button, "clicked", accel_group, + GDK_Escape, (GdkModifierType)0, GTK_ACCEL_VISIBLE); + gtk_widget_set_usize (button, 60, -2); + + char buf[16]; + sprintf (buf, "%d", *intensity); + gtk_entry_set_text (GTK_ENTRY (entry), buf); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + *intensity = atoi (gtk_entry_get_text (GTK_ENTRY (entry))); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + return ret; +} diff --git a/radiant/gtkmisc.cpp b/radiant/gtkmisc.cpp index 0ab59052..3d1f658c 100644 --- a/radiant/gtkmisc.cpp +++ b/radiant/gtkmisc.cpp @@ -1,1610 +1,1610 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -// -// Small functions to help with GTK -// - -#include - -#if defined (__linux__) || defined (__APPLE__) -#include -#endif - -#include - - -#ifdef _WIN32 -#include -#define WIN32_LEAN_AND_MEAN -#include -#endif - - - -#ifdef _WIN32 -#include -#include -#define R_OK 04 -#endif -#include "stdafx.h" - -// ============================================================================= -// Misc stuff - -// NOTE TTimo window position saving has always been tricky -// it doesn't work the same between win32 and linux .. see below that code is fairly different -// it's also very poorly done, the save calls are a bit randomly disctributed in the OnDestroy - -void save_window_pos (GtkWidget *wnd, window_position_t& pos) -{ - if ((wnd == NULL) || (wnd->window == NULL)) - return; - - get_window_pos(wnd, &pos.x, &pos.y); - - pos.w = wnd->allocation.width; - pos.h = wnd->allocation.height; - -#ifdef DBG_WINDOWPOS - //Sys_Printf("save_window_pos 'Window %s'\n",buf); -#endif -} - -#ifdef _WIN32 -void win32_get_window_pos(GtkWidget *widget, gint *x, gint *y) -{ - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=913 - if ( g_PrefsDlg.m_bStartOnPrimMon ) { - RECT rc; - POINT point; - HWND xwnd = (HWND)GDK_WINDOW_HWND (widget->window); - const GdkRectangle primaryMonitorRect = g_pParentWnd->GetPrimaryMonitorRect(); - - GetClientRect(xwnd,&rc); - point.x=rc.left; - point.y=rc.top; - ClientToScreen(xwnd,&point); - - *x=point.x; - *y=point.y; - - *x=max(*x,-widget->allocation.width+10); - *x=min(*x,primaryMonitorRect.width-10); - *y=max(*y,-widget->allocation.height+10); - *y=min(*y,primaryMonitorRect.height-10); - } else { - // this is the same as the unix version of get_window_pos - gdk_window_get_root_origin (widget->window, x, y); - } -#ifdef DBG_WINDOWPOS - Sys_Printf("win32_get_window_pos %p %d,%d\n",widget,*x,*y); -#endif -} -#endif - -void load_window_pos (GtkWidget *wnd, window_position_t& pos) -{ -#ifdef _WIN32 - const GdkRectangle primaryMonitorRect = g_pParentWnd->GetPrimaryMonitorRect(); - - if(pos.x < primaryMonitorRect.x - || pos.y < primaryMonitorRect.y - || pos.x > primaryMonitorRect.x + primaryMonitorRect.width - || pos.y > primaryMonitorRect.y + primaryMonitorRect.height) - gtk_window_set_position(GTK_WINDOW(wnd), GTK_WIN_POS_CENTER_ON_PARENT); -#else - // FIXME: not multihead safe - if(pos.x < 0 - || pos.y < 0 - || pos.x > gdk_screen_width () - || pos.y > gdk_screen_height ()) - gtk_window_set_position(GTK_WINDOW(wnd), GTK_WIN_POS_CENTER_ON_PARENT); -#endif - else - gtk_window_move(GTK_WINDOW(wnd), pos.x, pos.y); - - gtk_window_set_default_size (GTK_WINDOW (wnd), pos.w, pos.h); -#ifdef DBG_WINDOWPOS - Sys_Printf("load_window_pos %p 'Window,%s'\n",wnd,windowData); -#endif -} - -gint widget_delete_hide (GtkWidget *widget) -{ - gtk_widget_hide (widget); - - return TRUE; -} - - -// Thanks to Mercury, Fingolfin - ETG -int readLongLE(FILE *file, unsigned long *m_bytesRead, int *value) -{ - byte buf[4]; - int len = fread(buf, 4, 1, file); - *m_bytesRead += 4; - if (len != 1) - return -1; - - *value = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24; - return 0; -} - -short readShortLE(FILE *file, unsigned long *m_bytesRead, short unsigned *value) -{ - byte buf[2]; - int len = fread(buf, 2, 1, file); - *m_bytesRead += 2; - if (len != 1) - return -1; - - *value = buf[0] | buf[1] << 8; - return 0; -} - -unsigned char *load_bitmap_file (const char* filename, guint16 *width, guint16 *height) -{ - int bmWidth, bmHeight; - short unsigned bmPlanes, bmBitsPixel; - typedef struct { - unsigned char rgbBlue; - unsigned char rgbGreen; - unsigned char rgbRed; - unsigned char rgbReserved; - } RGBQUAD; - unsigned char m1,m2; - int sizeimage; - short unsigned res1,res2; - int filesize, pixoff; - int bmisize, compression; - int xscale, yscale; - int colors, impcol; - unsigned long m_bytesRead = 0; - unsigned char *imagebits = NULL; - FILE *fp; - - *width = *height = 0; - - fp = fopen(filename,"rb"); - if (fp == NULL) - { - return NULL; - } - - size_t rc; - rc = fread(&m1, 1, 1, fp); - m_bytesRead++; - if (rc == -1) - { - fclose(fp); - return NULL; - } - - rc = fread(&m2, 1, 1, fp); - m_bytesRead++; - if ((m1!='B') || (m2!='M')) - { - fclose(fp); - return NULL; - } - - if (readLongLE(fp,&m_bytesRead,&filesize)) { - fclose(fp); - return NULL; - } - - if (readShortLE(fp,&m_bytesRead,&res1)) { - fclose(fp); - return NULL; - } - - if (readShortLE(fp,&m_bytesRead,&res2)) { - fclose(fp); - return NULL; - } - - if (readLongLE(fp,&m_bytesRead,&pixoff)) { - fclose(fp); - return NULL; - } - - if (readLongLE(fp,&m_bytesRead,&bmisize)) { - fclose(fp); - return NULL; - } - - if (readLongLE(fp,&m_bytesRead,&bmWidth)) { - fclose(fp); - return NULL; - } - - if (readLongLE(fp,&m_bytesRead,&bmHeight)) { - fclose(fp); - return NULL; - } - - if (readShortLE(fp,&m_bytesRead,&bmPlanes)) { - fclose(fp); - return NULL; - } - - if (readShortLE(fp,&m_bytesRead,&bmBitsPixel)) { - fclose(fp); - return NULL; - } - - if (readLongLE(fp,&m_bytesRead,&compression)) { - fclose(fp); - return NULL; - } - - if (readLongLE(fp,&m_bytesRead,&sizeimage)) { - fclose(fp); - return NULL; - } - - if (readLongLE(fp,&m_bytesRead,&xscale)) { - fclose(fp); - return NULL; - } - - if (readLongLE(fp,&m_bytesRead,&yscale)) { - fclose(fp); - return NULL; - } - - if (readLongLE(fp,&m_bytesRead,&colors)) { - fclose(fp); - return NULL; - } - - if (readLongLE(fp,&m_bytesRead,&impcol)) { - fclose(fp); - return NULL; - } - - if (colors == 0) - colors = 1 << bmBitsPixel; - - RGBQUAD *colormap = NULL; - if (bmBitsPixel != 24) - { - colormap = new RGBQUAD[colors]; - if (colormap == NULL) - { - fclose(fp); - return NULL; - } - - int i; - for (i = 0; i < colors; i++) - { - unsigned char r ,g, b, dummy; - - rc = fread(&b, 1, 1, fp); - m_bytesRead++; - if (rc!=1) - { - delete [] colormap; - fclose(fp); - return NULL; - } - - rc = fread(&g, 1, 1, fp); - m_bytesRead++; - if (rc!=1) - { - delete [] colormap; - fclose(fp); - return NULL; - } - - rc = fread(&r, 1, 1, fp); - m_bytesRead++; - if (rc != 1) - { - delete [] colormap; - fclose(fp); - return NULL; - } - - rc = fread(&dummy, 1, 1, fp); - m_bytesRead++; - if (rc != 1) - { - delete [] colormap; - fclose(fp); - return NULL; - } - - colormap[i].rgbRed=r; - colormap[i].rgbGreen=g; - colormap[i].rgbBlue=b; - } - } - - if ((long)m_bytesRead > pixoff) - { - delete [] colormap; - fclose(fp); - return NULL; - } - - while ((long)m_bytesRead < pixoff) - { - char dummy; - fread(&dummy,1,1,fp); - m_bytesRead++; - } - - int w = bmWidth; - int h = bmHeight; - - // set the output params - imagebits = (unsigned char *)malloc(w * h * 3); - long row_size = w * 3; - - if (imagebits != NULL) - { - *width = w; - *height = h; - unsigned char *outbuf = imagebits; - long row = 0; - long rowOffset = 0; - - if (compression == 0) // BI_RGB - { - // read rows in reverse order - for (row = bmHeight - 1; row >= 0; row--) - { - // which row are we working on? - rowOffset = (long unsigned)row * row_size; - - if (bmBitsPixel == 24) - { - for (int col=0;col> bit_count) & mask; - - // lookup the color from the colormap - stuff it in our buffer - // swap red and blue - *(outbuf + rowOffset + col * 3 + 2) = colormap[pix].rgbBlue; - *(outbuf + rowOffset + col * 3 + 1) = colormap[pix].rgbGreen; - *(outbuf + rowOffset + col * 3 + 0) = colormap[pix].rgbRed; - } - - // read DWORD padding - while ((m_bytesRead - pixoff) & 3) - { - char dummy; - if (fread(&dummy,1,1,fp)!=1) - { - free(imagebits); - if (colormap) - delete [] colormap; - fclose(fp); - return NULL; - } - m_bytesRead++; - } - } - } - } - else - { - int i, x = 0; - unsigned char c, c1 = 0, *pp; - row = 0; - pp = outbuf + (bmHeight - 1) * bmWidth * 3; - - if (bmBitsPixel == 8) - { - while (row < bmHeight) - { - c = getc(fp); - - if (c) - { - // encoded mode - c1 = getc(fp); - for (i = 0; i < c; x++, i++) - { - *pp = colormap[c1].rgbRed; pp++; - *pp = colormap[c1].rgbGreen; pp++; - *pp = colormap[c1].rgbBlue; pp++; - } - } - else - { - // c==0x00, escape codes - c = getc(fp); - if (c == 0x00) // end of line - { - row++; - x = 0; - pp = outbuf + (bmHeight - row - 1) * bmWidth * 3; - } - else if (c == 0x01) - break; // end of pic - else if (c == 0x02) // delta - { - c = getc(fp); - x += c; - c = getc(fp); - row += c; - pp = outbuf + x*3 + (bmHeight - row - 1) * bmWidth * 3; - } - else // absolute mode - { - for (i = 0; i < c; x++, i++) - { - c1 = getc(fp); - *pp = colormap[c1].rgbRed; pp++; - *pp = colormap[c1].rgbGreen; pp++; - *pp = colormap[c1].rgbBlue; pp++; - } - - if (c & 1) - getc(fp); // odd length run: read an extra pad byte - } - } - } - } - else if (bmBitsPixel == 4) - { - while (row < bmHeight) - { - c = getc(fp); - - if (c) - { - // encoded mode - c1 = getc(fp); - for (i = 0; i < c; x++, i++) - { - *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbRed; pp++; - *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbGreen; pp++; - *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbBlue; pp++; - } - } - else - { - // c==0x00, escape codes - c = getc(fp); - - if (c == 0x00) // end of line - { - row++; - x = 0; - pp = outbuf + (bmHeight - row - 1) * bmWidth * 3; - } - else if (c == 0x01) - break; // end of pic - else if (c == 0x02) // delta - { - c = getc(fp); - x += c; - c = getc(fp); - row += c; - pp = outbuf + x * 3 + (bmHeight - row - 1) * bmWidth * 3; - } - else // absolute mode - { - for (i = 0; i < c; x++, i++) - { - if ((i&1) == 0) - c1 = getc(fp); - *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbRed; pp++; - *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbGreen; pp++; - *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbBlue; pp++; - } - - if (((c & 3) == 1) || ((c & 3) == 2)) - getc(fp); // odd length run: read an extra pad byte - } - } - } - } - } - if (colormap) - delete [] colormap; - - fclose(fp); - } - return imagebits; -} - -void bmp_to_pixmap (const char* filename, GdkPixmap **pixmap, GdkBitmap **mask) -{ - guint16 width, height; - unsigned char *buf; - GdkWindow *window = gdk_get_default_root_window(); - GdkColormap *colormap; - GdkGC* gc = gdk_gc_new (window); - int i, j; - bool hasMask = false; - - *pixmap = *mask = NULL; - buf = load_bitmap_file (filename, &width, &height); - if (!buf) - return; - - colormap = gdk_drawable_get_colormap (window); - *pixmap = gdk_pixmap_new (window, width, height, -1); - - typedef struct - { - GdkColor c; - unsigned char *p; - } PAL; - - for (i = 0; i < height; i++) - { - for (j = 0; j < width; j++) - { - unsigned char *p = &buf[(i * width + j) * 3]; - PAL pe; - - pe.c.red = (gushort)(p[0] * 0xFF); - pe.c.green = (gushort)(p[1] * 0xFF); - pe.c.blue = (gushort)(p[2] * 0xFF); - gdk_colormap_alloc_color(colormap, &pe.c, FALSE, TRUE); - gdk_gc_set_foreground(gc, &pe.c); - gdk_draw_point(*pixmap, gc, j, i); - - if (p[0] == 0xFF && p[1] == 0x00 && p[2] == 0xFF) - hasMask = true; - } - } - - gdk_gc_unref (gc); - *mask = gdk_pixmap_new (window, width, height, 1); - gc = gdk_gc_new (*mask); - if (hasMask) - { - for (i = 0; i < height; i++) - { - for (j = 0; j < width; j++) - { - GdkColor mask_pattern; - - // pink is transparent - if ((buf[(i*width+j)*3] == 0xff) && - (buf[(i*width+j)*3+1] == 0x00) && - (buf[(i*width+j)*3+2] == 0xff)) - mask_pattern.pixel = 0; - else - mask_pattern.pixel = 1; - - gdk_gc_set_foreground (gc, &mask_pattern); - // possible Win32 Gtk bug here - //gdk_draw_point (*mask, gc, j, i); - gdk_draw_line (*mask, gc, j, i, j + 1, i); - } - } - } - else - { - GdkColor mask_pattern; - mask_pattern.pixel = 1; - gdk_gc_set_foreground (gc, &mask_pattern); - gdk_draw_rectangle (*mask, gc, 1, 0, 0, width, height); - } - gdk_gc_unref(gc); - free (buf); -} - -void load_pixmap (const char* filename, GtkWidget* widget, GdkPixmap **gdkpixmap, GdkBitmap **mask) -{ - CString str; - - str = g_strBitmapsPath; - str += filename; - - bmp_to_pixmap (str.GetBuffer (), gdkpixmap, mask); - if (*gdkpixmap == NULL) - { - printf("gdkpixmap was null\n"); - char *dummy[] = { "1 1 1 1", " c None", " " }; - printf("calling gdk_pixmap_create_from_xpm_d\n"); - *gdkpixmap = gdk_pixmap_create_from_xpm_d (gdk_get_default_root_window(), mask, NULL, dummy); - } -} - -// this is the same as above but used by the plugins -// GdkPixmap **gdkpixmap, GdkBitmap **mask -bool WINAPI load_plugin_bitmap (const char* filename, void **gdkpixmap, void **mask) -{ - CString str; - - str = g_strGameToolsPath; - str += g_strPluginsDir; - str += "bitmaps/"; - str += filename; - bmp_to_pixmap (str.GetBuffer (), (GdkPixmap **)gdkpixmap, (GdkBitmap **)mask); - - if (*gdkpixmap == NULL) - { - // look in the core plugins - str = g_strAppPath; - str += g_strPluginsDir; - str += "bitmaps/"; - str += filename; - bmp_to_pixmap (str.GetBuffer (), (GdkPixmap **)gdkpixmap, (GdkBitmap **)mask); - - if (*gdkpixmap == NULL) - { - - // look in core modules - str = g_strAppPath; - str += g_strModulesDir; - str += "bitmaps/"; - str += filename; - bmp_to_pixmap (str.GetBuffer (), (GdkPixmap **)gdkpixmap, (GdkBitmap **)mask); - - if (*gdkpixmap == NULL) - { - char *dummy[] = { "1 1 1 1", " c None", " " }; - *gdkpixmap = gdk_pixmap_create_from_xpm_d (gdk_get_default_root_window(), (GdkBitmap **)mask, NULL, dummy); - return false; - } - } - } - return true; -} - -// Load a xpm file and return a pixmap widget. -GtkWidget* new_pixmap (GtkWidget* widget, char* filename) -{ - GdkPixmap *gdkpixmap; - GdkBitmap *mask; - GtkWidget *pixmap; - - load_pixmap (filename, widget, &gdkpixmap, &mask); - pixmap = gtk_pixmap_new (gdkpixmap, mask); - - gdk_drawable_unref (gdkpixmap); - gdk_drawable_unref (mask); - - return pixmap; -} - -// ============================================================================= -// Menu stuff - -GtkWidget* menu_separator (GtkWidget *menu) -{ - GtkWidget *menu_item = gtk_menu_item_new (); - gtk_menu_append (GTK_MENU (menu), menu_item); - gtk_widget_set_sensitive (menu_item, FALSE); - gtk_widget_show (menu_item); - return menu_item; -} - -GtkWidget* menu_tearoff (GtkWidget *menu) -{ - GtkWidget *menu_item = gtk_tearoff_menu_item_new (); - gtk_menu_append (GTK_MENU (menu), menu_item); -// gtk_widget_set_sensitive (menu_item, FALSE); -- controls whether menu is detachable - gtk_widget_show (menu_item); - return menu_item; -} - -GtkWidget* create_sub_menu_with_mnemonic (GtkWidget *bar, gchar *mnemonic) -{ - GtkWidget *item, *sub_menu; - - item = gtk_menu_item_new_with_mnemonic (mnemonic); - gtk_widget_show (item); - gtk_container_add (GTK_CONTAINER (bar), item); - - sub_menu = gtk_menu_new (); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), sub_menu); - - return sub_menu; -} - -extern void AddMenuItem (GtkWidget* menu, unsigned int id); - -GtkWidget* create_menu_item_with_mnemonic (GtkWidget *menu, gchar *mnemonic, GtkSignalFunc func, int id) -{ - GtkWidget *item; - - item = gtk_menu_item_new_with_mnemonic (mnemonic); - - gtk_widget_show (item); - gtk_container_add (GTK_CONTAINER (menu), item); - gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (func), GINT_TO_POINTER (id)); - - AddMenuItem (item, id); - return item; -} - -GtkWidget* create_check_menu_item_with_mnemonic (GtkWidget *menu, gchar *mnemonic, GtkSignalFunc func, int id, gboolean active) -{ - GtkWidget *item; - - item = gtk_check_menu_item_new_with_mnemonic(mnemonic); - - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), active); - gtk_widget_show (item); - gtk_container_add (GTK_CONTAINER (menu), item); - gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (func), GINT_TO_POINTER (id)); - - AddMenuItem (item, id); - return item; -} - -GtkWidget* create_radio_menu_item_with_mnemonic (GtkWidget *menu, GtkWidget *last, gchar *mnemonic, GtkSignalFunc func, int id, gboolean state) -{ - GtkWidget *item; - GSList *group = (GSList*)NULL; - - if (last != NULL) - group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (last)); - item = gtk_radio_menu_item_new_with_mnemonic (group, mnemonic); - gtk_check_menu_item_set_state (GTK_CHECK_MENU_ITEM (item), state); - - gtk_widget_show (item); - gtk_container_add (GTK_CONTAINER (menu), item); - gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (func), GINT_TO_POINTER (id)); - - AddMenuItem (item, id); - return item; -} - -GtkWidget* create_menu_in_menu_with_mnemonic (GtkWidget *menu, const gchar *mnemonic) -{ - GtkWidget *item, *submenu; - - item = gtk_menu_item_new_with_mnemonic(mnemonic); - gtk_widget_show (item); - gtk_container_add (GTK_CONTAINER (menu), item); - - submenu = gtk_menu_new (); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu); - - return submenu; -} - -// ============================================================================= -// Message Boxes - -void dialog_button_callback (GtkWidget *widget, gpointer data) -{ - GtkWidget *parent; - int *loop, *ret; - - parent = gtk_widget_get_toplevel (widget); - loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); - ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); - - *loop = 0; - *ret = (int)data; -} - -gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) -{ - int *loop; - - gtk_widget_hide (widget); - loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); - *loop = 0; - - return TRUE; -} - -gint dialog_url_callback (GtkWidget *widget, GdkEvent* event, gpointer data) -{ - OpenURL((const char *)g_object_get_data (G_OBJECT (widget), "URL")); - - return TRUE; -} - -int WINAPI gtk_MessageBox (void *parent, const char* lpText, const char* lpCaption, guint32 uType, const char* URL) -{ - GtkWidget *window, *w, *vbox, *hbox; - GtkAccelGroup *accel; - int mode = (uType & MB_TYPEMASK), ret, loop = 1; - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_signal_connect (GTK_OBJECT (window), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (window), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - gtk_window_set_title (GTK_WINDOW (window), lpCaption); - gtk_container_border_width (GTK_CONTAINER (window), 10); - g_object_set_data (G_OBJECT (window), "loop", &loop); - g_object_set_data (G_OBJECT (window), "ret", &ret); - gtk_widget_realize (window); - - gtk_window_set_policy(GTK_WINDOW (window),FALSE,FALSE,TRUE); - - if (parent != NULL) - gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (parent)); - - accel = gtk_accel_group_new (); - gtk_window_add_accel_group (GTK_WINDOW (window), accel); - - vbox = gtk_vbox_new (FALSE, 10); - gtk_container_add (GTK_CONTAINER (window), vbox); - gtk_widget_show (vbox); - - w = gtk_label_new (lpText); - gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); - gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); - gtk_widget_show (w); - - w = gtk_hseparator_new (); - gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); - gtk_widget_show (w); - - hbox = gtk_hbox_new (FALSE, 10); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); - gtk_widget_show (hbox); - - if (mode == MB_OK) - { - w = gtk_button_new_with_label ("Ok"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_add_accelerator (w, "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0); - gtk_widget_add_accelerator (w, "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0); - GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); - gtk_widget_grab_default (w); - gtk_widget_show (w); - ret = IDOK; - } - else if (mode == MB_OKCANCEL) - { - w = gtk_button_new_with_label ("Ok"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_widget_add_accelerator (w, "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0); - GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); - gtk_widget_grab_default (w); - gtk_widget_show (w); - - w = gtk_button_new_with_label ("Cancel"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_add_accelerator (w, "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0); - gtk_widget_show (w); - ret = IDCANCEL; - } - else if (mode == MB_YESNOCANCEL) - { - w = gtk_button_new_with_label ("Yes"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); - GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); - gtk_widget_grab_default (w); - gtk_widget_show (w); - - w = gtk_button_new_with_label ("No"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO)); - gtk_widget_show (w); - - w = gtk_button_new_with_label ("Cancel"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_widget_show (w); - ret = IDCANCEL; - } - else /* if (mode == MB_YESNO) */ - { - w = gtk_button_new_with_label ("Yes"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); - GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); - gtk_widget_grab_default (w); - gtk_widget_show (w); - - w = gtk_button_new_with_label ("No"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO)); - gtk_widget_show (w); - ret = IDNO; - } - - if (URL) - { - w = gtk_button_new_with_label ("Go to URL"); - gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); - gtk_signal_connect (GTK_OBJECT (w), "clicked", - GTK_SIGNAL_FUNC (dialog_url_callback), NULL); - g_object_set_data (G_OBJECT (w), "URL", (void *)URL); - GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); - gtk_widget_grab_default (w); - gtk_widget_show (w); - } - - - gtk_widget_show (window); - gtk_grab_add (window); - - while (loop) - gtk_main_iteration (); - - gtk_grab_remove (window); - gtk_widget_destroy (window); - - return ret; -} - -// ============================================================================= -// File dialog - -// fenris #3078 WHENHELLISFROZENOVER - -//#define FILEDLG_DBG - -static void file_sel_callback (GtkWidget *widget, gpointer data) -{ - GtkWidget *parent; - int *loop; - bool *success; - - parent = gtk_widget_get_toplevel (widget); - loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); - success = (bool*)g_object_get_data (G_OBJECT (parent), "success"); - - if ((int)data == IDOK) - *success = true; - -#ifdef FILEDLG_DBG - else - Sys_Printf("file_sel_callback != IDOK\n"); -#endif - - *loop = 0; -} - -#ifdef _WIN32 -#include -static OPENFILENAME ofn; /* common dialog box structure */ -static char szDirName[MAX_PATH]; /* directory string */ -static char szFile[MAX_PATH]; /* filename string */ -static char szFileTitle[MAX_PATH]; /* file title string */ -static int i, cbString; /* integer count variables */ -static HANDLE hf; /* file handle */ -#else -static char szFile[QER_MAX_NAMELEN]; -#endif - -#define FILEDLG_CUSTOM_FILTER_LENGTH 64 -// to be used with the advanced file selector - -class CFileType : public IFileTypeList -{ - struct filetype_copy_t - { - void operator=(const filetype_t& other) - { - m_name = other.name; - m_pattern = other.pattern; - } - string_t m_name; - string_t m_pattern; - }; -public: - CFileType() - { - m_nTypes = 0; - m_pTypes = NULL; - m_strWin32Filters = NULL; - m_pstrGTKMasks = NULL; - } - - virtual ~CFileType() - { - delete[] m_pTypes; - DestroyWin32Filters(); - DestroyGTKMasks(); - } - - void addType(filetype_t type) - { - filetype_copy_t* newTypes = new filetype_copy_t [m_nTypes+1]; - if(m_nTypes > 0) - { - for(int i=0; igetTypeList(pattern, &typelist); - -#ifdef FILEDLG_DBG - Sys_Printf("file_dialog: open = %d title = %s path = %s\n", open, title, path); - if (pattern) - { - Sys_Printf("Patterns:\n"); - char** p = typelist.m_pstrGTKMasks; - while(*p!=NULL) - Sys_Printf("%s\n", *p++); - } - else - Sys_Printf("no patterns\n"); -#endif - -#ifdef _WIN32 - // win32 dialog stores the selected "save as type" extension in the second null-terminated string - char customfilter[FILEDLG_CUSTOM_FILTER_LENGTH]; - - if (g_PrefsDlg.m_bNativeGUI) - { -#ifdef FILEDLG_DBG - Sys_Printf("Doing win32 file dialog..."); -#endif - // do that the native way - /* Place the terminating null character in the szFile. */ - szFile[0] = '\0'; - customfilter[0] = customfilter[1] = customfilter[2] = '\0'; - - /* Set the members of the OPENFILENAME structure. */ - ofn.lStructSize = sizeof(OPENFILENAME); - ofn.hwndOwner = (HWND)GDK_WINDOW_HWND (g_pParentWnd->m_pWidget->window); - if (pattern) - { - ofn.nFilterIndex = 0; - ofn.lpstrFilter = typelist.m_strWin32Filters; - } - else ofn.nFilterIndex = 1; - ofn.lpstrCustomFilter = customfilter; - ofn.nMaxCustFilter = sizeof(customfilter); - ofn.lpstrFile = szFile; - ofn.nMaxFile = sizeof(szFile); - ofn.lpstrFileTitle = NULL; // we don't need to get the name of the file - if(path) - { - // szDirName: Radiant uses unix convention for paths internally - // Win32 (of course) and Gtk (who would have thought) expect the '\\' convention - // copy path, replacing dir separators as appropriate - for(r=path, w=szDirName; *r!='\0'; r++) - *w++ = (*r=='/') ? '\\' : *r; - // terminate string - *w = '\0'; - ofn.lpstrInitialDir = szDirName; - } - else ofn.lpstrInitialDir = NULL; - ofn.lpstrTitle = title; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; - - /* Display the Open dialog box. */ - // it's open or close depending on 'open' parameter - if (open) - { - if (!GetOpenFileName(&ofn)) - return NULL; // canceled - } - else - { - if (!GetSaveFileName(&ofn)) - return NULL; // canceled - } - - if(pattern != NULL) - type = typelist.GetTypeForWin32Filter(customfilter+1); - -#ifdef FILEDLG_DBG - Sys_Printf("Done.\n"); -#endif - } - else - { -#endif - // do that the Gtk way - if (title == NULL) - title = open ? "Open File" : "Save File"; - -#ifdef FILEDLG_DBG - Sys_Printf("Doing Gtk file dialog:\nBuilding new_path.."); -#endif - // we expect an actual path below, if the path is NULL we might crash - if (!path || path[0] == '\0') - { -#ifdef _WIN32 - path = "C:\\"; -#elif defined (__linux__) || defined (__APPLE__) - path = "/"; -#else - path = "/"; -#endif - } - - // alloc new path with extra char for dir separator - new_path = new char[strlen(path)+1+1]; - // copy path, replacing dir separators as appropriate - for(r=path, w=new_path; *r!='\0'; r++) - *w++ = (*r=='/') ? G_DIR_SEPARATOR : *r; - // add dir separator to end of path if required - if(*(w-1) != G_DIR_SEPARATOR) *w++ = G_DIR_SEPARATOR; - // terminate string - *w = '\0'; - -#ifdef FILEDLG_DBG - Sys_Printf("Done.\n"); - Sys_Printf("Calling gtk_file_selection_new with title: %s...", title); -#endif - - file_sel = gtk_file_selection_new (title); - -#ifdef FILEDLG_DBG - Sys_Printf("Done.\n"); - Sys_Printf("Set the masks..."); -#endif - -#if 0 //!\todo Add masks to GtkFileSelection in gtk-2.0 - // set the masks - if (pattern) - { - gtk_file_selection_clear_masks (GTK_FILE_SELECTION (file_sel)); - gtk_file_selection_set_masks (GTK_FILE_SELECTION (file_sel), const_cast(typelist.m_pstrGTKMasks)); - } -#endif - -#ifdef FILEDLG_DBG - Sys_Printf("Done.\n"); -#endif - - gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked", - GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDOK)); - gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked", - GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_signal_connect (GTK_OBJECT (file_sel), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (file_sel)); - - if (parent != NULL) - gtk_window_set_transient_for (GTK_WINDOW (file_sel), GTK_WINDOW (parent)); - -#ifdef FILEDLG_DBG - Sys_Printf("set_data..."); -#endif - bool success = false; - g_object_set_data (G_OBJECT (file_sel), "loop", &loop); - g_object_set_data (G_OBJECT (file_sel), "success", &success); -#ifdef FILEDLG_DBG - Sys_Printf("Done.\n"); -#endif - - if (!open) - { -#ifdef FILEDLG_DBG - Sys_Printf("set_data \"overwrite\" ..."); -#endif - g_object_set_data (G_OBJECT (file_sel), "overwrite", GINT_TO_POINTER (1)); -#ifdef FILEDLG_DBG - Sys_Printf("Done.\n"); -#endif - } - - if (new_path != NULL) - { -#ifdef FILEDLG_DBG - Sys_Printf("gtk_file_selection_set_filename... %p", file_sel); -#endif - gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_sel), new_path); - delete[] new_path; -#ifdef FILEDLG_DBG - Sys_Printf("Done.\n"); -#endif - } - - gtk_grab_add (file_sel); -#ifdef FILEDLG_DBG - Sys_Printf("gtk_widget_show... %p", file_sel); -#endif - gtk_widget_show (file_sel); -#ifdef FILEDLG_DBG - Sys_Printf("Done.\n"); -#endif - -#ifdef FILEDLG_DBG - Sys_Printf("gtk_main_iteration..."); -#endif - while (loop) - gtk_main_iteration (); - if(success) - { -#if 0 //!\todo Add masks to GtkFileSelection in gtk2 - if(pattern!=NULL) - type = typelist.GetTypeForGTKMask(GTK_FILE_SELECTION (file_sel)->mask); -#endif - strcpy(szFile, gtk_file_selection_get_filename (GTK_FILE_SELECTION (file_sel))); - } -#ifdef FILEDLG_DBG - Sys_Printf("Done.\n"); -#endif - - gtk_grab_remove (file_sel); - gtk_widget_destroy (file_sel); -#ifdef _WIN32 - } -#endif - - // don't return an empty filename - if(szFile[0] == '\0') return NULL; - - // convert back to unix format - for(w=szFile; *w!='\0'; w++) - if(*w=='\\') - *w = '/'; - -#if defined(WIN32) - if (g_PrefsDlg.m_bNativeGUI) // filetype mask not supported in gtk dialog yet - { - // when saving, force an extension depending on filetype - /* \todo SPoG - file_dialog should return filetype information separately.. not force file extension.. */ - if(!open && pattern != NULL) - { - // last ext separator - w = strrchr(szFile, '.'); - // no extension - w = (w!=NULL) ? w : szFile+strlen(szFile); - strcpy(w, type.pattern+1); - } - } -#endif - - // prompt to overwrite existing files - if (!open) - if (access (szFile, R_OK) == 0) - if (gtk_MessageBox (parent, "File already exists.\nOverwrite?", "GtkRadiant", MB_YESNO) == IDNO) - return NULL; - -#ifdef FILEDLG_DBG - // ... let's use a static filename - Sys_Printf("filename: %p\n", szFile); -#endif - - return szFile; -} - -char* WINAPI dir_dialog (void *parent, const char* title, const char* path) -{ - GtkWidget* file_sel; - char* filename = (char*)NULL; - int loop = 1; - bool success = false; - - file_sel = gtk_file_selection_new (title); - gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked", - GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDOK)); - gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked", - GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDCANCEL)); - gtk_signal_connect (GTK_OBJECT (file_sel), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (file_sel)); - - if (parent != NULL) - gtk_window_set_transient_for (GTK_WINDOW (file_sel), GTK_WINDOW (parent)); - - gtk_widget_hide (GTK_FILE_SELECTION (file_sel)->file_list->parent); - - g_object_set_data (G_OBJECT (file_sel), "loop", &loop); - g_object_set_data (G_OBJECT (file_sel), "filename", &filename); - g_object_set_data (G_OBJECT (file_sel), "success", &success); - - if (path != NULL) - gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_sel), path); - - gtk_grab_add (file_sel); - gtk_widget_show (file_sel); - - while (loop) - gtk_main_iteration (); - - filename = g_strdup(gtk_file_selection_get_filename (GTK_FILE_SELECTION (file_sel))); - - gtk_grab_remove (file_sel); - gtk_widget_destroy (file_sel); - - return filename; -} - -bool WINAPI color_dialog (void *parent, float *color, const char* title) -{ - GtkWidget* dlg; - double clr[3]; - int loop = 1, ret = IDCANCEL; - - clr[0] = color[0]; - clr[1] = color[1]; - clr[2] = color[2]; - - dlg = gtk_color_selection_dialog_new (title); - gtk_color_selection_set_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), clr); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", - GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); - gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->ok_button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); - gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->cancel_button), "clicked", - GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); - g_object_set_data (G_OBJECT (dlg), "loop", &loop); - g_object_set_data (G_OBJECT (dlg), "ret", &ret); - - if (parent != NULL) - gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (parent)); - - gtk_widget_show (dlg); - gtk_grab_add (dlg); - - while (loop) - gtk_main_iteration (); - - GdkColor gdkcolor; - gtk_color_selection_get_current_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), &gdkcolor); - clr[0] = gdkcolor.red / 65535.0; - clr[1] = gdkcolor.green / 65535.0; - clr[2] = gdkcolor.blue / 65535.0; - - gtk_grab_remove (dlg); - gtk_widget_destroy (dlg); - - if (ret == IDOK) - { - color[0] = (float)clr[0]; - color[1] = (float)clr[1]; - color[2] = (float)clr[2]; - - return true; - } - - return false; -} - -void OpenURL(const char *url) -{ - // let's put a little comment - Sys_Printf("OpenURL: %s\n", url); -#ifdef __linux__ - // \todo FIXME: the way we open URLs on *nix should be improved. A script is good (see how I do on RTCW) - char command[2*PATH_MAX]; - snprintf( command, sizeof(command), "%s/openurl.sh \"%s\" &", g_strAppPath.GetBuffer(), url ); - if (system (command) != 0) - gtk_MessageBox (g_pParentWnd->m_pWidget, "Failed to launch Netscape!"); -#endif -#ifdef __APPLE__ - char command[2*PATH_MAX]; - snprintf (command, sizeof(command), - "open \"%s\" &", url, url); - if (system (command) != 0) - gtk_MessageBox (g_pParentWnd->m_pWidget, "Unable to launch browser!"); -#endif -#ifdef _WIN32 - ShellExecute( (HWND)GDK_WINDOW_HWND (g_pParentWnd->m_pWidget->window), "open", url, NULL, NULL, SW_SHOW ); -#endif -} - -void CheckMenuSplitting (GtkWidget *&menu) -{ - GtkWidget *item,*menu2; - - GtkRequisition requisition; - gint screen_height; - - gtk_widget_size_request (GTK_WIDGET (menu), &requisition); - screen_height = gdk_screen_height (); - - if ((screen_height - requisition.height) < 20) - { - menu2 = gtk_menu_new (); - - // move the last 2 items to a submenu (3 because of win32) - for (int i = 0; i < 3; i++) - { - item = GTK_WIDGET (g_list_last (gtk_container_children (GTK_CONTAINER (menu)))->data); - gtk_widget_ref (item); - gtk_container_remove (GTK_CONTAINER (menu), item); - gtk_menu_append (GTK_MENU (menu2), item); - gtk_widget_unref (item); - } - - item = gtk_menu_item_new_with_label ("--------"); - gtk_widget_show (item); - gtk_container_add (GTK_CONTAINER (menu), item); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu2); - menu = menu2; - } -} +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// +// Small functions to help with GTK +// + +#include + +#if defined (__linux__) || defined (__APPLE__) +#include +#endif + +#include + + +#ifdef _WIN32 +#include +#define WIN32_LEAN_AND_MEAN +#include +#endif + + + +#ifdef _WIN32 +#include +#include +#define R_OK 04 +#endif +#include "stdafx.h" + +// ============================================================================= +// Misc stuff + +// NOTE TTimo window position saving has always been tricky +// it doesn't work the same between win32 and linux .. see below that code is fairly different +// it's also very poorly done, the save calls are a bit randomly disctributed in the OnDestroy + +void save_window_pos (GtkWidget *wnd, window_position_t& pos) +{ + if ((wnd == NULL) || (wnd->window == NULL)) + return; + + get_window_pos(wnd, &pos.x, &pos.y); + + pos.w = wnd->allocation.width; + pos.h = wnd->allocation.height; + +#ifdef DBG_WINDOWPOS + //Sys_Printf("save_window_pos 'Window %s'\n",buf); +#endif +} + +#ifdef _WIN32 +void win32_get_window_pos(GtkWidget *widget, gint *x, gint *y) +{ + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=913 + if ( g_PrefsDlg.m_bStartOnPrimMon ) { + RECT rc; + POINT point; + HWND xwnd = (HWND)GDK_WINDOW_HWND (widget->window); + const GdkRectangle primaryMonitorRect = g_pParentWnd->GetPrimaryMonitorRect(); + + GetClientRect(xwnd,&rc); + point.x=rc.left; + point.y=rc.top; + ClientToScreen(xwnd,&point); + + *x=point.x; + *y=point.y; + + *x=max(*x,-widget->allocation.width+10); + *x=min(*x,primaryMonitorRect.width-10); + *y=max(*y,-widget->allocation.height+10); + *y=min(*y,primaryMonitorRect.height-10); + } else { + // this is the same as the unix version of get_window_pos + gdk_window_get_root_origin (widget->window, x, y); + } +#ifdef DBG_WINDOWPOS + Sys_Printf("win32_get_window_pos %p %d,%d\n",widget,*x,*y); +#endif +} +#endif + +void load_window_pos (GtkWidget *wnd, window_position_t& pos) +{ +#ifdef _WIN32 + const GdkRectangle primaryMonitorRect = g_pParentWnd->GetPrimaryMonitorRect(); + + if(pos.x < primaryMonitorRect.x + || pos.y < primaryMonitorRect.y + || pos.x > primaryMonitorRect.x + primaryMonitorRect.width + || pos.y > primaryMonitorRect.y + primaryMonitorRect.height) + gtk_window_set_position(GTK_WINDOW(wnd), GTK_WIN_POS_CENTER_ON_PARENT); +#else + // FIXME: not multihead safe + if(pos.x < 0 + || pos.y < 0 + || pos.x > gdk_screen_width () + || pos.y > gdk_screen_height ()) + gtk_window_set_position(GTK_WINDOW(wnd), GTK_WIN_POS_CENTER_ON_PARENT); +#endif + else + gtk_window_move(GTK_WINDOW(wnd), pos.x, pos.y); + + gtk_window_set_default_size (GTK_WINDOW (wnd), pos.w, pos.h); +#ifdef DBG_WINDOWPOS + Sys_Printf("load_window_pos %p 'Window,%s'\n",wnd,windowData); +#endif +} + +gint widget_delete_hide (GtkWidget *widget) +{ + gtk_widget_hide (widget); + + return TRUE; +} + + +// Thanks to Mercury, Fingolfin - ETG +int readLongLE(FILE *file, unsigned long *m_bytesRead, int *value) +{ + byte buf[4]; + int len = fread(buf, 4, 1, file); + *m_bytesRead += 4; + if (len != 1) + return -1; + + *value = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24; + return 0; +} + +short readShortLE(FILE *file, unsigned long *m_bytesRead, short unsigned *value) +{ + byte buf[2]; + int len = fread(buf, 2, 1, file); + *m_bytesRead += 2; + if (len != 1) + return -1; + + *value = buf[0] | buf[1] << 8; + return 0; +} + +unsigned char *load_bitmap_file (const char* filename, guint16 *width, guint16 *height) +{ + int bmWidth, bmHeight; + short unsigned bmPlanes, bmBitsPixel; + typedef struct { + unsigned char rgbBlue; + unsigned char rgbGreen; + unsigned char rgbRed; + unsigned char rgbReserved; + } RGBQUAD; + unsigned char m1,m2; + int sizeimage; + short unsigned res1,res2; + int filesize, pixoff; + int bmisize, compression; + int xscale, yscale; + int colors, impcol; + unsigned long m_bytesRead = 0; + unsigned char *imagebits = NULL; + FILE *fp; + + *width = *height = 0; + + fp = fopen(filename,"rb"); + if (fp == NULL) + { + return NULL; + } + + size_t rc; + rc = fread(&m1, 1, 1, fp); + m_bytesRead++; + if (rc == -1) + { + fclose(fp); + return NULL; + } + + rc = fread(&m2, 1, 1, fp); + m_bytesRead++; + if ((m1!='B') || (m2!='M')) + { + fclose(fp); + return NULL; + } + + if (readLongLE(fp,&m_bytesRead,&filesize)) { + fclose(fp); + return NULL; + } + + if (readShortLE(fp,&m_bytesRead,&res1)) { + fclose(fp); + return NULL; + } + + if (readShortLE(fp,&m_bytesRead,&res2)) { + fclose(fp); + return NULL; + } + + if (readLongLE(fp,&m_bytesRead,&pixoff)) { + fclose(fp); + return NULL; + } + + if (readLongLE(fp,&m_bytesRead,&bmisize)) { + fclose(fp); + return NULL; + } + + if (readLongLE(fp,&m_bytesRead,&bmWidth)) { + fclose(fp); + return NULL; + } + + if (readLongLE(fp,&m_bytesRead,&bmHeight)) { + fclose(fp); + return NULL; + } + + if (readShortLE(fp,&m_bytesRead,&bmPlanes)) { + fclose(fp); + return NULL; + } + + if (readShortLE(fp,&m_bytesRead,&bmBitsPixel)) { + fclose(fp); + return NULL; + } + + if (readLongLE(fp,&m_bytesRead,&compression)) { + fclose(fp); + return NULL; + } + + if (readLongLE(fp,&m_bytesRead,&sizeimage)) { + fclose(fp); + return NULL; + } + + if (readLongLE(fp,&m_bytesRead,&xscale)) { + fclose(fp); + return NULL; + } + + if (readLongLE(fp,&m_bytesRead,&yscale)) { + fclose(fp); + return NULL; + } + + if (readLongLE(fp,&m_bytesRead,&colors)) { + fclose(fp); + return NULL; + } + + if (readLongLE(fp,&m_bytesRead,&impcol)) { + fclose(fp); + return NULL; + } + + if (colors == 0) + colors = 1 << bmBitsPixel; + + RGBQUAD *colormap = NULL; + if (bmBitsPixel != 24) + { + colormap = new RGBQUAD[colors]; + if (colormap == NULL) + { + fclose(fp); + return NULL; + } + + int i; + for (i = 0; i < colors; i++) + { + unsigned char r ,g, b, dummy; + + rc = fread(&b, 1, 1, fp); + m_bytesRead++; + if (rc!=1) + { + delete [] colormap; + fclose(fp); + return NULL; + } + + rc = fread(&g, 1, 1, fp); + m_bytesRead++; + if (rc!=1) + { + delete [] colormap; + fclose(fp); + return NULL; + } + + rc = fread(&r, 1, 1, fp); + m_bytesRead++; + if (rc != 1) + { + delete [] colormap; + fclose(fp); + return NULL; + } + + rc = fread(&dummy, 1, 1, fp); + m_bytesRead++; + if (rc != 1) + { + delete [] colormap; + fclose(fp); + return NULL; + } + + colormap[i].rgbRed=r; + colormap[i].rgbGreen=g; + colormap[i].rgbBlue=b; + } + } + + if ((long)m_bytesRead > pixoff) + { + delete [] colormap; + fclose(fp); + return NULL; + } + + while ((long)m_bytesRead < pixoff) + { + char dummy; + fread(&dummy,1,1,fp); + m_bytesRead++; + } + + int w = bmWidth; + int h = bmHeight; + + // set the output params + imagebits = (unsigned char *)malloc(w * h * 3); + long row_size = w * 3; + + if (imagebits != NULL) + { + *width = w; + *height = h; + unsigned char *outbuf = imagebits; + long row = 0; + long rowOffset = 0; + + if (compression == 0) // BI_RGB + { + // read rows in reverse order + for (row = bmHeight - 1; row >= 0; row--) + { + // which row are we working on? + rowOffset = (long unsigned)row * row_size; + + if (bmBitsPixel == 24) + { + for (int col=0;col> bit_count) & mask; + + // lookup the color from the colormap - stuff it in our buffer + // swap red and blue + *(outbuf + rowOffset + col * 3 + 2) = colormap[pix].rgbBlue; + *(outbuf + rowOffset + col * 3 + 1) = colormap[pix].rgbGreen; + *(outbuf + rowOffset + col * 3 + 0) = colormap[pix].rgbRed; + } + + // read DWORD padding + while ((m_bytesRead - pixoff) & 3) + { + char dummy; + if (fread(&dummy,1,1,fp)!=1) + { + free(imagebits); + if (colormap) + delete [] colormap; + fclose(fp); + return NULL; + } + m_bytesRead++; + } + } + } + } + else + { + int i, x = 0; + unsigned char c, c1 = 0, *pp; + row = 0; + pp = outbuf + (bmHeight - 1) * bmWidth * 3; + + if (bmBitsPixel == 8) + { + while (row < bmHeight) + { + c = getc(fp); + + if (c) + { + // encoded mode + c1 = getc(fp); + for (i = 0; i < c; x++, i++) + { + *pp = colormap[c1].rgbRed; pp++; + *pp = colormap[c1].rgbGreen; pp++; + *pp = colormap[c1].rgbBlue; pp++; + } + } + else + { + // c==0x00, escape codes + c = getc(fp); + if (c == 0x00) // end of line + { + row++; + x = 0; + pp = outbuf + (bmHeight - row - 1) * bmWidth * 3; + } + else if (c == 0x01) + break; // end of pic + else if (c == 0x02) // delta + { + c = getc(fp); + x += c; + c = getc(fp); + row += c; + pp = outbuf + x*3 + (bmHeight - row - 1) * bmWidth * 3; + } + else // absolute mode + { + for (i = 0; i < c; x++, i++) + { + c1 = getc(fp); + *pp = colormap[c1].rgbRed; pp++; + *pp = colormap[c1].rgbGreen; pp++; + *pp = colormap[c1].rgbBlue; pp++; + } + + if (c & 1) + getc(fp); // odd length run: read an extra pad byte + } + } + } + } + else if (bmBitsPixel == 4) + { + while (row < bmHeight) + { + c = getc(fp); + + if (c) + { + // encoded mode + c1 = getc(fp); + for (i = 0; i < c; x++, i++) + { + *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbRed; pp++; + *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbGreen; pp++; + *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbBlue; pp++; + } + } + else + { + // c==0x00, escape codes + c = getc(fp); + + if (c == 0x00) // end of line + { + row++; + x = 0; + pp = outbuf + (bmHeight - row - 1) * bmWidth * 3; + } + else if (c == 0x01) + break; // end of pic + else if (c == 0x02) // delta + { + c = getc(fp); + x += c; + c = getc(fp); + row += c; + pp = outbuf + x * 3 + (bmHeight - row - 1) * bmWidth * 3; + } + else // absolute mode + { + for (i = 0; i < c; x++, i++) + { + if ((i&1) == 0) + c1 = getc(fp); + *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbRed; pp++; + *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbGreen; pp++; + *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbBlue; pp++; + } + + if (((c & 3) == 1) || ((c & 3) == 2)) + getc(fp); // odd length run: read an extra pad byte + } + } + } + } + } + if (colormap) + delete [] colormap; + + fclose(fp); + } + return imagebits; +} + +void bmp_to_pixmap (const char* filename, GdkPixmap **pixmap, GdkBitmap **mask) +{ + guint16 width, height; + unsigned char *buf; + GdkWindow *window = gdk_get_default_root_window(); + GdkColormap *colormap; + GdkGC* gc = gdk_gc_new (window); + int i, j; + bool hasMask = false; + + *pixmap = *mask = NULL; + buf = load_bitmap_file (filename, &width, &height); + if (!buf) + return; + + colormap = gdk_drawable_get_colormap (window); + *pixmap = gdk_pixmap_new (window, width, height, -1); + + typedef struct + { + GdkColor c; + unsigned char *p; + } PAL; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + unsigned char *p = &buf[(i * width + j) * 3]; + PAL pe; + + pe.c.red = (gushort)(p[0] * 0xFF); + pe.c.green = (gushort)(p[1] * 0xFF); + pe.c.blue = (gushort)(p[2] * 0xFF); + gdk_colormap_alloc_color(colormap, &pe.c, FALSE, TRUE); + gdk_gc_set_foreground(gc, &pe.c); + gdk_draw_point(*pixmap, gc, j, i); + + if (p[0] == 0xFF && p[1] == 0x00 && p[2] == 0xFF) + hasMask = true; + } + } + + gdk_gc_unref (gc); + *mask = gdk_pixmap_new (window, width, height, 1); + gc = gdk_gc_new (*mask); + if (hasMask) + { + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + GdkColor mask_pattern; + + // pink is transparent + if ((buf[(i*width+j)*3] == 0xff) && + (buf[(i*width+j)*3+1] == 0x00) && + (buf[(i*width+j)*3+2] == 0xff)) + mask_pattern.pixel = 0; + else + mask_pattern.pixel = 1; + + gdk_gc_set_foreground (gc, &mask_pattern); + // possible Win32 Gtk bug here + //gdk_draw_point (*mask, gc, j, i); + gdk_draw_line (*mask, gc, j, i, j + 1, i); + } + } + } + else + { + GdkColor mask_pattern; + mask_pattern.pixel = 1; + gdk_gc_set_foreground (gc, &mask_pattern); + gdk_draw_rectangle (*mask, gc, 1, 0, 0, width, height); + } + gdk_gc_unref(gc); + free (buf); +} + +void load_pixmap (const char* filename, GtkWidget* widget, GdkPixmap **gdkpixmap, GdkBitmap **mask) +{ + CString str; + + str = g_strBitmapsPath; + str += filename; + + bmp_to_pixmap (str.GetBuffer (), gdkpixmap, mask); + if (*gdkpixmap == NULL) + { + printf("gdkpixmap was null\n"); + char *dummy[] = { "1 1 1 1", " c None", " " }; + printf("calling gdk_pixmap_create_from_xpm_d\n"); + *gdkpixmap = gdk_pixmap_create_from_xpm_d (gdk_get_default_root_window(), mask, NULL, dummy); + } +} + +// this is the same as above but used by the plugins +// GdkPixmap **gdkpixmap, GdkBitmap **mask +bool WINAPI load_plugin_bitmap (const char* filename, void **gdkpixmap, void **mask) +{ + CString str; + + str = g_strGameToolsPath; + str += g_strPluginsDir; + str += "bitmaps/"; + str += filename; + bmp_to_pixmap (str.GetBuffer (), (GdkPixmap **)gdkpixmap, (GdkBitmap **)mask); + + if (*gdkpixmap == NULL) + { + // look in the core plugins + str = g_strAppPath; + str += g_strPluginsDir; + str += "bitmaps/"; + str += filename; + bmp_to_pixmap (str.GetBuffer (), (GdkPixmap **)gdkpixmap, (GdkBitmap **)mask); + + if (*gdkpixmap == NULL) + { + + // look in core modules + str = g_strAppPath; + str += g_strModulesDir; + str += "bitmaps/"; + str += filename; + bmp_to_pixmap (str.GetBuffer (), (GdkPixmap **)gdkpixmap, (GdkBitmap **)mask); + + if (*gdkpixmap == NULL) + { + char *dummy[] = { "1 1 1 1", " c None", " " }; + *gdkpixmap = gdk_pixmap_create_from_xpm_d (gdk_get_default_root_window(), (GdkBitmap **)mask, NULL, dummy); + return false; + } + } + } + return true; +} + +// Load a xpm file and return a pixmap widget. +GtkWidget* new_pixmap (GtkWidget* widget, char* filename) +{ + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + + load_pixmap (filename, widget, &gdkpixmap, &mask); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + + gdk_drawable_unref (gdkpixmap); + gdk_drawable_unref (mask); + + return pixmap; +} + +// ============================================================================= +// Menu stuff + +GtkWidget* menu_separator (GtkWidget *menu) +{ + GtkWidget *menu_item = gtk_menu_item_new (); + gtk_menu_append (GTK_MENU (menu), menu_item); + gtk_widget_set_sensitive (menu_item, FALSE); + gtk_widget_show (menu_item); + return menu_item; +} + +GtkWidget* menu_tearoff (GtkWidget *menu) +{ + GtkWidget *menu_item = gtk_tearoff_menu_item_new (); + gtk_menu_append (GTK_MENU (menu), menu_item); +// gtk_widget_set_sensitive (menu_item, FALSE); -- controls whether menu is detachable + gtk_widget_show (menu_item); + return menu_item; +} + +GtkWidget* create_sub_menu_with_mnemonic (GtkWidget *bar, gchar *mnemonic) +{ + GtkWidget *item, *sub_menu; + + item = gtk_menu_item_new_with_mnemonic (mnemonic); + gtk_widget_show (item); + gtk_container_add (GTK_CONTAINER (bar), item); + + sub_menu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), sub_menu); + + return sub_menu; +} + +extern void AddMenuItem (GtkWidget* menu, unsigned int id); + +GtkWidget* create_menu_item_with_mnemonic (GtkWidget *menu, gchar *mnemonic, GtkSignalFunc func, int id) +{ + GtkWidget *item; + + item = gtk_menu_item_new_with_mnemonic (mnemonic); + + gtk_widget_show (item); + gtk_container_add (GTK_CONTAINER (menu), item); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (func), GINT_TO_POINTER (id)); + + AddMenuItem (item, id); + return item; +} + +GtkWidget* create_check_menu_item_with_mnemonic (GtkWidget *menu, gchar *mnemonic, GtkSignalFunc func, int id, gboolean active) +{ + GtkWidget *item; + + item = gtk_check_menu_item_new_with_mnemonic(mnemonic); + + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), active); + gtk_widget_show (item); + gtk_container_add (GTK_CONTAINER (menu), item); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (func), GINT_TO_POINTER (id)); + + AddMenuItem (item, id); + return item; +} + +GtkWidget* create_radio_menu_item_with_mnemonic (GtkWidget *menu, GtkWidget *last, gchar *mnemonic, GtkSignalFunc func, int id, gboolean state) +{ + GtkWidget *item; + GSList *group = (GSList*)NULL; + + if (last != NULL) + group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (last)); + item = gtk_radio_menu_item_new_with_mnemonic (group, mnemonic); + gtk_check_menu_item_set_state (GTK_CHECK_MENU_ITEM (item), state); + + gtk_widget_show (item); + gtk_container_add (GTK_CONTAINER (menu), item); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (func), GINT_TO_POINTER (id)); + + AddMenuItem (item, id); + return item; +} + +GtkWidget* create_menu_in_menu_with_mnemonic (GtkWidget *menu, const gchar *mnemonic) +{ + GtkWidget *item, *submenu; + + item = gtk_menu_item_new_with_mnemonic(mnemonic); + gtk_widget_show (item); + gtk_container_add (GTK_CONTAINER (menu), item); + + submenu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu); + + return submenu; +} + +// ============================================================================= +// Message Boxes + +void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} + +gint dialog_url_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + OpenURL((const char *)g_object_get_data (G_OBJECT (widget), "URL")); + + return TRUE; +} + +int WINAPI gtk_MessageBox (void *parent, const char* lpText, const char* lpCaption, guint32 uType, const char* URL) +{ + GtkWidget *window, *w, *vbox, *hbox; + GtkAccelGroup *accel; + int mode = (uType & MB_TYPEMASK), ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_window_set_title (GTK_WINDOW (window), lpCaption); + gtk_container_border_width (GTK_CONTAINER (window), 10); + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + gtk_widget_realize (window); + + gtk_window_set_policy(GTK_WINDOW (window),FALSE,FALSE,TRUE); + + if (parent != NULL) + gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (parent)); + + accel = gtk_accel_group_new (); + gtk_window_add_accel_group (GTK_WINDOW (window), accel); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + w = gtk_label_new (lpText); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + if (mode == MB_OK) + { + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_add_accelerator (w, "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0); + gtk_widget_add_accelerator (w, "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + ret = IDOK; + } + else if (mode == MB_OKCANCEL) + { + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_add_accelerator (w, "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_add_accelerator (w, "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0); + gtk_widget_show (w); + ret = IDCANCEL; + } + else if (mode == MB_YESNOCANCEL) + { + w = gtk_button_new_with_label ("Yes"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("No"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO)); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + } + else /* if (mode == MB_YESNO) */ + { + w = gtk_button_new_with_label ("Yes"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("No"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO)); + gtk_widget_show (w); + ret = IDNO; + } + + if (URL) + { + w = gtk_button_new_with_label ("Go to URL"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_url_callback), NULL); + g_object_set_data (G_OBJECT (w), "URL", (void *)URL); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + } + + + gtk_widget_show (window); + gtk_grab_add (window); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} + +// ============================================================================= +// File dialog + +// fenris #3078 WHENHELLISFROZENOVER + +//#define FILEDLG_DBG + +static void file_sel_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop; + bool *success; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + success = (bool*)g_object_get_data (G_OBJECT (parent), "success"); + + if ((int)data == IDOK) + *success = true; + +#ifdef FILEDLG_DBG + else + Sys_Printf("file_sel_callback != IDOK\n"); +#endif + + *loop = 0; +} + +#ifdef _WIN32 +#include +static OPENFILENAME ofn; /* common dialog box structure */ +static char szDirName[MAX_PATH]; /* directory string */ +static char szFile[MAX_PATH]; /* filename string */ +static char szFileTitle[MAX_PATH]; /* file title string */ +static int i, cbString; /* integer count variables */ +static HANDLE hf; /* file handle */ +#else +static char szFile[QER_MAX_NAMELEN]; +#endif + +#define FILEDLG_CUSTOM_FILTER_LENGTH 64 +// to be used with the advanced file selector + +class CFileType : public IFileTypeList +{ + struct filetype_copy_t + { + void operator=(const filetype_t& other) + { + m_name = other.name; + m_pattern = other.pattern; + } + string_t m_name; + string_t m_pattern; + }; +public: + CFileType() + { + m_nTypes = 0; + m_pTypes = NULL; + m_strWin32Filters = NULL; + m_pstrGTKMasks = NULL; + } + + virtual ~CFileType() + { + delete[] m_pTypes; + DestroyWin32Filters(); + DestroyGTKMasks(); + } + + void addType(filetype_t type) + { + filetype_copy_t* newTypes = new filetype_copy_t [m_nTypes+1]; + if(m_nTypes > 0) + { + for(int i=0; igetTypeList(pattern, &typelist); + +#ifdef FILEDLG_DBG + Sys_Printf("file_dialog: open = %d title = %s path = %s\n", open, title, path); + if (pattern) + { + Sys_Printf("Patterns:\n"); + char** p = typelist.m_pstrGTKMasks; + while(*p!=NULL) + Sys_Printf("%s\n", *p++); + } + else + Sys_Printf("no patterns\n"); +#endif + +#ifdef _WIN32 + // win32 dialog stores the selected "save as type" extension in the second null-terminated string + char customfilter[FILEDLG_CUSTOM_FILTER_LENGTH]; + + if (g_PrefsDlg.m_bNativeGUI) + { +#ifdef FILEDLG_DBG + Sys_Printf("Doing win32 file dialog..."); +#endif + // do that the native way + /* Place the terminating null character in the szFile. */ + szFile[0] = '\0'; + customfilter[0] = customfilter[1] = customfilter[2] = '\0'; + + /* Set the members of the OPENFILENAME structure. */ + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = (HWND)GDK_WINDOW_HWND (g_pParentWnd->m_pWidget->window); + if (pattern) + { + ofn.nFilterIndex = 0; + ofn.lpstrFilter = typelist.m_strWin32Filters; + } + else ofn.nFilterIndex = 1; + ofn.lpstrCustomFilter = customfilter; + ofn.nMaxCustFilter = sizeof(customfilter); + ofn.lpstrFile = szFile; + ofn.nMaxFile = sizeof(szFile); + ofn.lpstrFileTitle = NULL; // we don't need to get the name of the file + if(path) + { + // szDirName: Radiant uses unix convention for paths internally + // Win32 (of course) and Gtk (who would have thought) expect the '\\' convention + // copy path, replacing dir separators as appropriate + for(r=path, w=szDirName; *r!='\0'; r++) + *w++ = (*r=='/') ? '\\' : *r; + // terminate string + *w = '\0'; + ofn.lpstrInitialDir = szDirName; + } + else ofn.lpstrInitialDir = NULL; + ofn.lpstrTitle = title; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + + /* Display the Open dialog box. */ + // it's open or close depending on 'open' parameter + if (open) + { + if (!GetOpenFileName(&ofn)) + return NULL; // canceled + } + else + { + if (!GetSaveFileName(&ofn)) + return NULL; // canceled + } + + if(pattern != NULL) + type = typelist.GetTypeForWin32Filter(customfilter+1); + +#ifdef FILEDLG_DBG + Sys_Printf("Done.\n"); +#endif + } + else + { +#endif + // do that the Gtk way + if (title == NULL) + title = open ? "Open File" : "Save File"; + +#ifdef FILEDLG_DBG + Sys_Printf("Doing Gtk file dialog:\nBuilding new_path.."); +#endif + // we expect an actual path below, if the path is NULL we might crash + if (!path || path[0] == '\0') + { +#ifdef _WIN32 + path = "C:\\"; +#elif defined (__linux__) || defined (__APPLE__) + path = "/"; +#else + path = "/"; +#endif + } + + // alloc new path with extra char for dir separator + new_path = new char[strlen(path)+1+1]; + // copy path, replacing dir separators as appropriate + for(r=path, w=new_path; *r!='\0'; r++) + *w++ = (*r=='/') ? G_DIR_SEPARATOR : *r; + // add dir separator to end of path if required + if(*(w-1) != G_DIR_SEPARATOR) *w++ = G_DIR_SEPARATOR; + // terminate string + *w = '\0'; + +#ifdef FILEDLG_DBG + Sys_Printf("Done.\n"); + Sys_Printf("Calling gtk_file_selection_new with title: %s...", title); +#endif + + file_sel = gtk_file_selection_new (title); + +#ifdef FILEDLG_DBG + Sys_Printf("Done.\n"); + Sys_Printf("Set the masks..."); +#endif + +#if 0 //!\todo Add masks to GtkFileSelection in gtk-2.0 + // set the masks + if (pattern) + { + gtk_file_selection_clear_masks (GTK_FILE_SELECTION (file_sel)); + gtk_file_selection_set_masks (GTK_FILE_SELECTION (file_sel), const_cast(typelist.m_pstrGTKMasks)); + } +#endif + +#ifdef FILEDLG_DBG + Sys_Printf("Done.\n"); +#endif + + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked", + GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDOK)); + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked", + GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_signal_connect (GTK_OBJECT (file_sel), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (file_sel)); + + if (parent != NULL) + gtk_window_set_transient_for (GTK_WINDOW (file_sel), GTK_WINDOW (parent)); + +#ifdef FILEDLG_DBG + Sys_Printf("set_data..."); +#endif + bool success = false; + g_object_set_data (G_OBJECT (file_sel), "loop", &loop); + g_object_set_data (G_OBJECT (file_sel), "success", &success); +#ifdef FILEDLG_DBG + Sys_Printf("Done.\n"); +#endif + + if (!open) + { +#ifdef FILEDLG_DBG + Sys_Printf("set_data \"overwrite\" ..."); +#endif + g_object_set_data (G_OBJECT (file_sel), "overwrite", GINT_TO_POINTER (1)); +#ifdef FILEDLG_DBG + Sys_Printf("Done.\n"); +#endif + } + + if (new_path != NULL) + { +#ifdef FILEDLG_DBG + Sys_Printf("gtk_file_selection_set_filename... %p", file_sel); +#endif + gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_sel), new_path); + delete[] new_path; +#ifdef FILEDLG_DBG + Sys_Printf("Done.\n"); +#endif + } + + gtk_grab_add (file_sel); +#ifdef FILEDLG_DBG + Sys_Printf("gtk_widget_show... %p", file_sel); +#endif + gtk_widget_show (file_sel); +#ifdef FILEDLG_DBG + Sys_Printf("Done.\n"); +#endif + +#ifdef FILEDLG_DBG + Sys_Printf("gtk_main_iteration..."); +#endif + while (loop) + gtk_main_iteration (); + if(success) + { +#if 0 //!\todo Add masks to GtkFileSelection in gtk2 + if(pattern!=NULL) + type = typelist.GetTypeForGTKMask(GTK_FILE_SELECTION (file_sel)->mask); +#endif + strcpy(szFile, gtk_file_selection_get_filename (GTK_FILE_SELECTION (file_sel))); + } +#ifdef FILEDLG_DBG + Sys_Printf("Done.\n"); +#endif + + gtk_grab_remove (file_sel); + gtk_widget_destroy (file_sel); +#ifdef _WIN32 + } +#endif + + // don't return an empty filename + if(szFile[0] == '\0') return NULL; + + // convert back to unix format + for(w=szFile; *w!='\0'; w++) + if(*w=='\\') + *w = '/'; + +#if defined(WIN32) + if (g_PrefsDlg.m_bNativeGUI) // filetype mask not supported in gtk dialog yet + { + // when saving, force an extension depending on filetype + /* \todo SPoG - file_dialog should return filetype information separately.. not force file extension.. */ + if(!open && pattern != NULL) + { + // last ext separator + w = strrchr(szFile, '.'); + // no extension + w = (w!=NULL) ? w : szFile+strlen(szFile); + strcpy(w, type.pattern+1); + } + } +#endif + + // prompt to overwrite existing files + if (!open) + if (access (szFile, R_OK) == 0) + if (gtk_MessageBox (parent, "File already exists.\nOverwrite?", "GtkRadiant", MB_YESNO) == IDNO) + return NULL; + +#ifdef FILEDLG_DBG + // ... let's use a static filename + Sys_Printf("filename: %p\n", szFile); +#endif + + return szFile; +} + +char* WINAPI dir_dialog (void *parent, const char* title, const char* path) +{ + GtkWidget* file_sel; + char* filename = (char*)NULL; + int loop = 1; + bool success = false; + + file_sel = gtk_file_selection_new (title); + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked", + GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDOK)); + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked", + GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_signal_connect (GTK_OBJECT (file_sel), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (file_sel)); + + if (parent != NULL) + gtk_window_set_transient_for (GTK_WINDOW (file_sel), GTK_WINDOW (parent)); + + gtk_widget_hide (GTK_FILE_SELECTION (file_sel)->file_list->parent); + + g_object_set_data (G_OBJECT (file_sel), "loop", &loop); + g_object_set_data (G_OBJECT (file_sel), "filename", &filename); + g_object_set_data (G_OBJECT (file_sel), "success", &success); + + if (path != NULL) + gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_sel), path); + + gtk_grab_add (file_sel); + gtk_widget_show (file_sel); + + while (loop) + gtk_main_iteration (); + + filename = g_strdup(gtk_file_selection_get_filename (GTK_FILE_SELECTION (file_sel))); + + gtk_grab_remove (file_sel); + gtk_widget_destroy (file_sel); + + return filename; +} + +bool WINAPI color_dialog (void *parent, float *color, const char* title) +{ + GtkWidget* dlg; + double clr[3]; + int loop = 1, ret = IDCANCEL; + + clr[0] = color[0]; + clr[1] = color[1]; + clr[2] = color[2]; + + dlg = gtk_color_selection_dialog_new (title); + gtk_color_selection_set_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), clr); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->ok_button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->cancel_button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + if (parent != NULL) + gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (parent)); + + gtk_widget_show (dlg); + gtk_grab_add (dlg); + + while (loop) + gtk_main_iteration (); + + GdkColor gdkcolor; + gtk_color_selection_get_current_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), &gdkcolor); + clr[0] = gdkcolor.red / 65535.0; + clr[1] = gdkcolor.green / 65535.0; + clr[2] = gdkcolor.blue / 65535.0; + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + if (ret == IDOK) + { + color[0] = (float)clr[0]; + color[1] = (float)clr[1]; + color[2] = (float)clr[2]; + + return true; + } + + return false; +} + +void OpenURL(const char *url) +{ + // let's put a little comment + Sys_Printf("OpenURL: %s\n", url); +#ifdef __linux__ + // \todo FIXME: the way we open URLs on *nix should be improved. A script is good (see how I do on RTCW) + char command[2*PATH_MAX]; + snprintf( command, sizeof(command), "%s/openurl.sh \"%s\" &", g_strAppPath.GetBuffer(), url ); + if (system (command) != 0) + gtk_MessageBox (g_pParentWnd->m_pWidget, "Failed to launch Netscape!"); +#endif +#ifdef __APPLE__ + char command[2*PATH_MAX]; + snprintf (command, sizeof(command), + "open \"%s\" &", url, url); + if (system (command) != 0) + gtk_MessageBox (g_pParentWnd->m_pWidget, "Unable to launch browser!"); +#endif +#ifdef _WIN32 + ShellExecute( (HWND)GDK_WINDOW_HWND (g_pParentWnd->m_pWidget->window), "open", url, NULL, NULL, SW_SHOW ); +#endif +} + +void CheckMenuSplitting (GtkWidget *&menu) +{ + GtkWidget *item,*menu2; + + GtkRequisition requisition; + gint screen_height; + + gtk_widget_size_request (GTK_WIDGET (menu), &requisition); + screen_height = gdk_screen_height (); + + if ((screen_height - requisition.height) < 20) + { + menu2 = gtk_menu_new (); + + // move the last 2 items to a submenu (3 because of win32) + for (int i = 0; i < 3; i++) + { + item = GTK_WIDGET (g_list_last (gtk_container_children (GTK_CONTAINER (menu)))->data); + gtk_widget_ref (item); + gtk_container_remove (GTK_CONTAINER (menu), item); + gtk_menu_append (GTK_MENU (menu2), item); + gtk_widget_unref (item); + } + + item = gtk_menu_item_new_with_label ("--------"); + gtk_widget_show (item); + gtk_container_add (GTK_CONTAINER (menu), item); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu2); + menu = menu2; + } +} diff --git a/radiant/main.cpp b/radiant/main.cpp index a2e0e793..b6d1d41b 100644 --- a/radiant/main.cpp +++ b/radiant/main.cpp @@ -1,1246 +1,1246 @@ -/* -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 -*/ - -#if defined (__linux__) || defined (__APPLE__) - #include - #include - #include - #ifdef __linux__ - #include - #endif - #include - #include - #include - #include - #include -#endif - -#include -#include "stdafx.h" -#include -#include -#include - -#include - -#include "watchbsp.h" -#include "filters.h" - -bool g_bBuildList = false; -int g_argc; -char** g_argv; - -// ============================================================================= -// Splash screen - -// get rid of it when debugging -#if defined (_DEBUG) - #define SKIP_SPLASH -#endif - -static GtkWidget *splash_screen; - -// called based on a timer, or in particular cases when we don't want to keep it around -gint try_destroy_splash (gpointer data) -{ - if (splash_screen) - { - gtk_widget_destroy (splash_screen); - splash_screen = NULL; - } - return FALSE; -} - -static void create_splash () -{ - GtkWidget *alert_frame, *alert_frame1, *pixmap; - - splash_screen = gtk_window_new (GTK_WINDOW_POPUP); - gtk_window_position (GTK_WINDOW (splash_screen), GTK_WIN_POS_CENTER); - gtk_widget_realize (splash_screen); - - alert_frame1 = gtk_frame_new (NULL); - gtk_widget_show (alert_frame1); - gtk_container_add (GTK_CONTAINER (splash_screen), alert_frame1); - gtk_frame_set_shadow_type (GTK_FRAME (alert_frame1), GTK_SHADOW_OUT); - - alert_frame = gtk_frame_new (NULL); - gtk_widget_show (alert_frame); - - gtk_container_add (GTK_CONTAINER (alert_frame1), alert_frame); - gtk_frame_set_shadow_type (GTK_FRAME (alert_frame), GTK_SHADOW_IN); - gtk_container_border_width (GTK_CONTAINER (alert_frame), 3); - - pixmap = gtk_preview_new (GTK_PREVIEW_COLOR); - gtk_widget_show (pixmap); - gtk_container_add (GTK_CONTAINER (alert_frame), pixmap); - - CString str; - guint16 width, height; - unsigned char *buf; - - str = g_strGameToolsPath; - str += "bitmaps/splash.bmp"; - - unsigned char* load_bitmap_file (const char* filename, guint16* width, guint16* height); - buf = load_bitmap_file (str.GetBuffer (), &width, &height); - - if (!buf) - { - str = g_strBitmapsPath; - str += "splash.bmp"; - - buf = load_bitmap_file (str.GetBuffer (), &width, &height); - } - - if (buf) - { - GtkPreview *preview = GTK_PREVIEW (pixmap); - gtk_preview_size (preview, width, height); - for (int y = 0; y < height; y++) - gtk_preview_draw_row (preview, buf+y*width*3, 0, y, width); - } - - gtk_widget_show_all (splash_screen); - - while (gtk_events_pending ()) - gtk_main_iteration (); -} - -// ============================================================================= -// Loki stuff - -#if defined (__linux__) || defined (__APPLE__) - -/* A short game name, could be used as argv[0] */ -static char game_name[100] = ""; - -/* The directory where the data files can be found (run directory) */ -static char datapath[PATH_MAX]; - -char *loki_gethomedir(void) -{ - char *home = NULL; - - home = getenv("HOME"); - if ( home == NULL ) - { - uid_t id = getuid(); - struct passwd *pwd; - - setpwent(); - while ( (pwd = getpwent()) != NULL ) - { - if ( pwd->pw_uid == id ) - { - home = pwd->pw_dir; - break; - } - } - endpwent(); - } - return home; -} - -/* Must be called BEFORE loki_initialize */ -void loki_setgamename(const char *n) -{ - strncpy(game_name, n, sizeof(game_name)); -} - - #ifdef __linux__ -/* Code to determine the mount point of a CD-ROM */ -int loki_getmountpoint(const char *device, char *mntpt, int max_size) -{ - char devpath[PATH_MAX], mntdevpath[PATH_MAX]; - FILE * mountfp; - struct mntent *mntent; - int mounted; - - /* Nothing to do with no device file */ - if ( device == NULL ) - { - *mntpt = '\0'; - return -1; - } - - /* Get the fully qualified path of the CD-ROM device */ - if ( realpath(device, devpath) == NULL ) - { - perror("realpath() on your CD-ROM failed"); - return(-1); - } - - /* Get the mount point */ - mounted = -1; - memset(mntpt, 0, max_size); - mountfp = setmntent( _PATH_MNTTAB, "r" ); - if ( mountfp != NULL ) - { - mounted = 0; - while ( (mntent = getmntent( mountfp )) != NULL ) - { - char *tmp, mntdev[1024]; - - strcpy(mntdev, mntent->mnt_fsname); - if ( strcmp(mntent->mnt_type, "supermount") == 0 ) - { - tmp = strstr(mntent->mnt_opts, "dev="); - if ( tmp ) - { - strcpy(mntdev, tmp+strlen("dev=")); - tmp = strchr(mntdev, ','); - if ( tmp ) - { - *tmp = '\0'; - } - } - } - if ( strncmp(mntdev, "/dev", 4) || - realpath(mntdev, mntdevpath) == NULL ) - { - continue; - } - if ( strcmp( mntdevpath, devpath ) == 0 ) - { - mounted = 1; - assert((int)strlen( mntent->mnt_dir ) < max_size); - strncpy( mntpt, mntent->mnt_dir, max_size-1); - mntpt[max_size-1] = '\0'; - break; - } - } - endmntent( mountfp ); - } - return(mounted); -} - #endif - -/* - This function gets the directory containing the running program. - argv0 - the 0'th argument to the program -*/ -// FIXME TTimo -// I don't understand this function. It looks like something cut from another piece of software -// we somehow get the g_strAppPath from it, but it's done through a weird scan across $PATH env. var. -// even worse, it doesn't behave the same in all cases .. works well when ran through gdb and borks when ran from a shell -void loki_initpaths(char *argv0) -{ - char temppath[PATH_MAX]; //, env[100]; - char *home; //, *ptr, *data_env; - - home = loki_gethomedir(); - if ( home == NULL ) - { - home = "."; - } - - if (*game_name == 0) /* Game name defaults to argv[0] */ - loki_setgamename(argv0); - - strcpy(temppath, argv0); /* If this overflows, it's your own fault :) */ - if ( ! strrchr(temppath, '/') ) - { - char *path; - char *last; - int found; - - found = 0; - path = getenv("PATH"); - do - { - /* Initialize our filename variable */ - temppath[0] = '\0'; - - /* Get next entry from path variable */ - last = strchr(path, ':'); - if ( ! last ) - last = path+strlen(path); - - /* Perform tilde expansion */ - if ( *path == '~' ) - { - strcpy(temppath, home); - ++path; - } - - /* Fill in the rest of the filename */ - if ( last > (path+1) ) - { - strncat(temppath, path, (last-path)); - strcat(temppath, "/"); - } - strcat(temppath, "./"); - strcat(temppath, argv0); - - /* See if it exists, and update path */ - if ( access(temppath, X_OK) == 0 ) - { - ++found; - } - path = last+1; - - } while ( *last && !found ); - - } else - { - /* Increment argv0 to the basename */ - argv0 = strrchr(argv0, '/')+1; - } - - /* Now canonicalize it to a full pathname for the data path */ - if ( realpath(temppath, datapath) ) - { - /* There should always be '/' in the path */ - *(strrchr(datapath, '/')) = '\0'; - } -} - -char *loki_getdatapath(void) -{ - return(datapath); -} - -#endif - -// end of Loki stuff -// ============================================================================= - -void error_redirect (const gchar *domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) -{ - gboolean in_recursion; - gboolean is_fatal; - char buf[256]; - - in_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0; - is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0; - log_level = (GLogLevelFlags) (log_level & G_LOG_LEVEL_MASK); - - if (!message) - message = "(NULL) message"; - - if (domain) - strcpy (buf, domain); - else - strcpy (buf, "**"); - strcat (buf, "-"); - - switch (log_level) - { - case G_LOG_LEVEL_ERROR: - if (in_recursion) - strcat (buf, "ERROR (recursed) **: "); - else - strcat (buf, "ERROR **: "); - break; - case G_LOG_LEVEL_CRITICAL: - if (in_recursion) - strcat (buf, "CRITICAL (recursed) **: "); - else - strcat (buf, "CRITICAL **: "); - break; - case G_LOG_LEVEL_WARNING: - if (in_recursion) - strcat (buf, "WARNING (recursed) **: "); - else - strcat (buf, "WARNING **: "); - break; - case G_LOG_LEVEL_MESSAGE: - if (in_recursion) - strcat (buf, "Message (recursed): "); - else - strcat (buf, "Message: "); - break; - case G_LOG_LEVEL_INFO: - if (in_recursion) - strcat (buf, "INFO (recursed): "); - else - strcat (buf, "INFO: "); - break; - case G_LOG_LEVEL_DEBUG: - if (in_recursion) - strcat (buf, "DEBUG (recursed): "); - else - strcat (buf, "DEBUG: "); - break; - default: - /* we are used for a log level that is not defined by GLib itself, - * try to make the best out of it. - */ - if (in_recursion) - strcat (buf, "LOG (recursed:"); - else - strcat (buf, "LOG ("); - if (log_level) - { - gchar string[] = "0x00): "; - gchar *p = string + 2; - guint i; - - i = g_bit_nth_msf (log_level, -1); - *p = i >> 4; - p++; - *p = '0' + (i & 0xf); - if (*p > '9') - *p += 'A' - '9' - 1; - - strcat (buf, string); - } else - strcat (buf, "): "); - } - - strcat (buf, message); - if (is_fatal) - strcat (buf, "\naborting...\n"); - else - strcat (buf, "\n"); - - printf ("%s\n", buf); - Sys_FPrintf (SYS_WRN, buf); - // TTimo NOTE: in some cases it may be handy to log only to the file -// Sys_FPrintf (SYS_NOCON, buf); -} - -int main (int argc, char* argv[]) -{ - char *libgl, *ptr; - int i, j, k; - -#ifdef _WIN32 - libgl = "opengl32.dll"; -#endif - -#if defined (__linux__) - libgl = "libGL.so.1"; -#endif - -#ifdef __APPLE__ - libgl = "/usr/X11R6/lib/libGL.1.dylib"; -#endif - -#if defined (__linux__) || defined (__APPLE__) - // Give away unnecessary root privileges. - // Important: must be done before calling gtk_init(). - char *loginname; - struct passwd *pw; - seteuid(getuid()); - if (geteuid() == 0 && (loginname = getlogin()) != NULL && - (pw = getpwnam(loginname)) != NULL) - setuid(pw->pw_uid); -#endif - - gtk_disable_setlocale(); - - gtk_init(&argc, &argv); - - if ((ptr = getenv ("Q3R_LIBGL")) != NULL) - libgl = ptr; - - for (i = 1; i < argc; i++) - { - char* param = argv[i]; - - if (param[0] == '-' && param[1] == '-') - { - param += 2; - - if ((strcmp (param, "libgl") == 0) && (i != argc)) - { - libgl = argv[i+1]; - argv[i] = argv[i+1] = NULL; - i++; - } else if (strcmp (param, "builddefs") == 0) - { - g_bBuildList = true; - argv[i] = NULL; - } - } - } - - for (i = 1; i < argc; i++) - { - for (k = i; k < argc; k++) - if (argv[k] != NULL) - break; - - if (k > i) - { - k -= i; - for (j = i + k; j < argc; j++) - argv[j-k] = argv[j]; - argc -= k; - } - } - - g_argc = argc; - g_argv = argv; - - g_strPluginsDir = "plugins/"; - g_strModulesDir = "modules/"; - -#ifdef _WIN32 - // get path to the editor - char* pBuffer = g_strAppPath.GetBufferSetLength(_MAX_PATH + 1); - GetModuleFileName(NULL, pBuffer, _MAX_PATH); - pBuffer[g_strAppPath.ReverseFind('\\') + 1] = '\0'; - QE_ConvertDOSToUnixName(pBuffer, pBuffer); - g_strAppPath.ReleaseBuffer(); - - g_strBitmapsPath = g_strAppPath; - g_strBitmapsPath += "bitmaps/"; - -#if 0 - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=639 - // now check if we are running from a network installation - // use a dummy file as the flag - FILE *f_netrun; - CString strNetrun; - strNetrun = g_strAppPath; strNetrun += NETRUN_FILENAME; - f_netrun = fopen(strNetrun.GetBuffer(), "r"); - if (f_netrun) - { - fclose(f_netrun); - g_PrefsDlg.m_bUseHomePath = true; - } -#endif - CGameDialog::UpdateNetrun(false); // read the netrun configuration - - if (CGameDialog::GetNetrun()) - { - // we have to find a per-user g_strTempPath - // this behaves the same as on Linux - g_strTempPath = getenv("USERPROFILE"); - if (!g_strTempPath.GetLength()) - { - CString msg; - msg = "Radiant is configured to run from a network installation.\n"; - msg += "I couldn't find the environement variable USERPROFILE\n"; - msg += "I'm going to use C:\\RadiantSettings. Please set USERPROFILE\n"; - gtk_MessageBox (NULL, msg, "Radiant - Network mode", MB_OK); - g_strTempPath = "C:\\"; - } - g_strTempPath += "\\RadiantSettings\\"; - Q_mkdir(g_strTempPath.GetBuffer(), 0755); - g_strTempPath += RADIANT_VERSION; - g_strTempPath += "\\"; - Q_mkdir(g_strTempPath.GetBuffer(), 0755); - } - else - { - // use the core path as temp (to save commandlist.txt, and do the .pid files) - g_strTempPath = g_strAppPath; - } - -#endif - -#if defined (__linux__) || defined (__APPLE__) - Str home; - home = g_get_home_dir (); - AddSlash (home); - home += ".radiant/"; - Q_mkdir (home.GetBuffer (), 0775); - home += RADIANT_VERSION; - Q_mkdir (home.GetBuffer (), 0775); - g_strTempPath = home.GetBuffer (); - AddSlash (g_strTempPath); - - loki_initpaths(argv[0]); - - // NOTE: we build g_strAppPath with a '/' (or '\' on WIN32) - // it's a general convention in Radiant to have the slash at the end of directories - char real[PATH_MAX]; - realpath (loki_getdatapath(), real); - if (real[strlen(real)-1] != '/') - strcat(real, "/"); - - g_strAppPath = real; - -#if 0 - printf("g_strAppPath: %s\n", g_strAppPath.GetBuffer()); -#endif - - // radiant is installed in the parent dir of "tools/" - // NOTE: this is not very easy for debugging - // maybe add options to lookup in several places? - // (for now I had to create symlinks) - g_strBitmapsPath = g_strAppPath; - g_strBitmapsPath += "bitmaps/"; -#if 0 - printf("g_strBitmapsPath: %s\n", g_strBitmapsPath.GetBuffer()); -#endif - - // we will set this right after the game selection is done - g_strGameToolsPath = g_strAppPath; - -#endif - - // init the DTD path - g_strDTDPath = g_strAppPath; - g_strDTDPath += "dtds/"; - - /*! - the global prefs loading / game selection dialog might fail for any reason we don't know about - we need to catch when it happens, to cleanup the stateful prefs which might be killing it - and to turn on console logging for lookup of the problem - this is the first part of the two step .pid system - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=297 - */ - g_pidFile = g_strTempPath.GetBuffer (); - g_pidFile += "radiant.pid"; - - FILE *pid; - pid = fopen (g_pidFile.GetBuffer(), "r"); - if (pid != NULL) - { - fclose (pid); - CString msg; - - if (remove (g_pidFile.GetBuffer ()) == -1) - { - msg = "WARNING: Could not delete "; msg += g_pidFile; - gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR ); - } - - // in debug, never prompt to clean registry, turn console logging auto after a failed start -#if !defined(_DEBUG) - msg = "Found the file "; - msg += g_pidFile; - msg += ".\nThis indicates that Radiant failed during the game selection startup last time it was run.\n" - "Choose YES to clean Radiant's registry settings and shut down Radiant.\n" - "WARNING: the global prefs will be lost if you choose YES."; - - if (gtk_MessageBox (NULL, msg, "Radiant - Reset global startup?", MB_YESNO | MB_ICONQUESTION) == IDYES) - { - // remove global prefs and shutdown - g_PrefsDlg.mGamesDialog.Reset(); - // remove the prefs file (like a full reset of the registry) - //remove (g_PrefsDlg.m_inipath->str); - gtk_MessageBox(NULL, "Removed global settings, choose OK to close Radiant.", "Radiant", MB_OK ); - _exit(-1); - } - msg = "Logging console output to "; - msg += g_strTempPath; - msg += "radiant.log\nRefer to the log if Radiant fails to start again."; - - gtk_MessageBox (NULL, msg, "Radiant - Console Log", MB_OK); -#endif - - // set without saving, the class is not in a coherent state yet - // just do the value change and call to start logging, CGamesDialog will pickup when relevant - g_PrefsDlg.mGamesDialog.m_bLogConsole = true; - g_PrefsDlg.mGamesDialog.m_bForceLogConsole = true; - Sys_LogFile(); - } - - // create a primary .pid for global init run - pid = fopen (g_pidFile.GetBuffer(), "w"); - if (pid) - fclose (pid); - - // a safe check to avoid people running broken installations - // (otherwise, they run it, crash it, and blame us for not forcing them hard enough to pay attention while installing) - // make something idiot proof and someone will make better idiots, this may be overkill - // let's leave it disabled in debug mode in any case - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=431 -#ifndef _DEBUG -#define CHECK_VERSION -#endif -#ifdef CHECK_VERSION - // locate and open RADIANT_MAJOR and RADIANT_MINOR - qboolean bVerIsGood = true; - Str ver_file_name; - ver_file_name = g_strAppPath; - ver_file_name += "RADIANT_MAJOR"; - FILE *ver_file = fopen (ver_file_name.GetBuffer(), "r"); - if (ver_file) - { - char buf[10]; - int chomp; - fread(buf, 1, 10, ver_file); - // chomp it (the hard way) - chomp = 0; - while(buf[chomp] >= '0' && buf[chomp] <= '9') - chomp++; - buf[chomp] = '\0'; - if (strcmp(buf, RADIANT_MAJOR_VERSION)) - { - Sys_Printf("ERROR: file RADIANT_MAJOR doesn't match ('%s')\n", buf); - bVerIsGood = false; - } - } - else - { - Sys_Printf("ERROR: can't find RADIANT_MAJOR in '%s'\n", ver_file_name.GetBuffer()); - bVerIsGood = false; - } - ver_file_name = g_strAppPath; - ver_file_name += "RADIANT_MINOR"; - ver_file = fopen (ver_file_name.GetBuffer(), "r"); - if (ver_file) - { - char buf[10]; - int chomp; - fread(buf, 1, 10, ver_file); - // chomp it (the hard way) - chomp = 0; - while(buf[chomp] >= '0' && buf[chomp] <= '9') - chomp++; - buf[chomp] = '\0'; - if (strcmp(buf, RADIANT_MINOR_VERSION)) - { - Sys_Printf("ERROR: file RADIANT_MINOR doesn't match ('%s')\n", buf); - bVerIsGood = false; - } - } - else - { - Sys_Printf("ERROR: can't find RADIANT_MINOR in '%s'\n", ver_file_name.GetBuffer()); - bVerIsGood = false; - } - if (!bVerIsGood) - { - CString msg; - msg = "This editor binary (" RADIANT_VERSION ") doesn't match what the latest setup has configured in this directory\n"; - msg += "Make sure you run the right/latest editor binary you installed\n"; - msg += g_strAppPath; msg += "\n"; - msg += "Check http://www.qeradiant.com/faq/index.cgi?file=219 for more information"; - gtk_MessageBox(NULL, msg.GetBuffer(), "Radiant", MB_OK, "http://www.qeradiant.com/faq/index.cgi?file=219"); - _exit(-1); - } -#endif - - g_qeglobals.disable_ini = false; - g_PrefsDlg.Init (); - - // close the primary - if (remove (g_pidFile.GetBuffer ()) == -1) - { - CString msg; - msg = "WARNING: Could not delete "; msg += g_pidGameFile; - gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR ); - } - - /*! - now the secondary game dependant .pid file - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=297 - */ - g_pidGameFile = g_PrefsDlg.m_rc_path->str; - g_pidGameFile += "radiant-game.pid"; - - pid = fopen (g_pidGameFile.GetBuffer(), "r"); - if (pid != NULL) - { - fclose (pid); - CString msg; - if (remove (g_pidGameFile.GetBuffer ()) == -1) - { - msg = "WARNING: Could not delete "; msg += g_pidGameFile; - gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR ); - } - - msg = "Found the file "; - msg += g_pidGameFile; - msg += ".\nThis indicates that Radiant failed to load the last time it was run.\n" - "Choose YES to clean Radiant's registry settings and shut down Radiant.\n" - "WARNING: preferences will be lost if you choose YES."; - - // in debug, never prompt to clean registry, turn console logging auto after a failed start -#if !defined(_DEBUG) - //bleh - if (gtk_MessageBox (NULL, msg, "Radiant - Clean Registry?", MB_YESNO | MB_ICONQUESTION) == IDYES) - { - // remove the game prefs files - remove (g_PrefsDlg.m_inipath->str); - char buf[PATH_MAX]; - sprintf(buf, "%sSavedInfo.bin", g_PrefsDlg.m_rc_path->str); - remove(buf); - // remove the global pref too - g_PrefsDlg.mGamesDialog.Reset(); - gtk_MessageBox(NULL, "Cleaned registry settings, choose OK to close Radiant.\nThe next time Radiant runs it will use default settings.", "Radiant", MB_OK ); - _exit(-1); - } - msg = "Logging console output to "; - msg += g_strTempPath; - msg += "radiant.log\nRefer to the log if Radiant fails to start again."; - - gtk_MessageBox (NULL, msg, "Radiant - Console Log", MB_OK); -#endif - - // force console logging on! (will go in prefs too) - g_PrefsDlg.mGamesDialog.m_bLogConsole = true; - g_PrefsDlg.mGamesDialog.SavePrefs(); - Sys_LogFile(); - - g_PrefsDlg.LoadPrefs(); - - } else - { - // create one, will remove right after entering message loop - pid = fopen (g_pidGameFile.GetBuffer(), "w"); - if (pid) - fclose (pid); - - g_PrefsDlg.LoadPrefs(); - -#ifndef _DEBUG // I can't be arsed about that prompt in debug mode - // if console logging is on in the prefs, warn about performance hit - if (g_PrefsDlg.mGamesDialog.m_bLogConsole) - { - if (gtk_MessageBox (NULL, "Preferences indicate that console logging is on. This affects performance.\n" - "Turn it off?", "Radiant", MB_YESNO | MB_ICONQUESTION) == IDYES) - { - g_PrefsDlg.mGamesDialog.m_bLogConsole = false; - g_PrefsDlg.mGamesDialog.SavePrefs(); - } - } -#endif - // toggle console logging if necessary - Sys_LogFile(); - } - - // FIXME http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=639 - // we should search in g_strTempPath, then move over to look at g_strAppPath? -#ifdef _WIN32 - // fine tune the look of the app using a gtk rc file - // we try to load an RC file placed in the application directory - // build the full path - Str sRCFile; - sRCFile = g_strAppPath; - sRCFile += "radiantgtkrc"; - // we load that file with g_new in gtk_rc_parse_file (gtkrc.c), change the '/' into '\\' - pBuffer = (char *)sRCFile.GetBuffer(); - for (i=0; i 0) - Map_LoadFile(g_PrefsDlg.m_strLastMap.GetBuffer()); - else - Map_New(); - - // load up shaders now that we have the map loaded - // eviltypeguy - Texture_ShowStartupShaders (); - -#ifndef SKIP_SPLASH - gdk_window_raise (splash_screen->window); - gtk_window_set_transient_for (GTK_WINDOW (splash_screen), GTK_WINDOW (g_pParentWnd->m_pWidget)); - gtk_timeout_add (1000, try_destroy_splash, NULL); -#endif - - g_pParentWnd->GetSynapseServer().DumpActiveClients(); - - //++timo: temporary debug - g_pParentWnd->DoWatchBSP(); - - gtk_main (); - - // close the log file if any - // NOTE: don't save prefs past this point! - g_PrefsDlg.mGamesDialog.m_bLogConsole = false; - // set the console window to NULL to avoid Sys_Printf crashing - g_qeglobals_gui.d_edit = NULL; - Sys_LogFile(); - - // NOTE TTimo not sure what this _exit(0) call is worth - // restricting it to linux build -#ifdef __linux__ - _exit (0); -#endif - return 0; -} - -// ydnar: quick and dirty fix, just make the buffer bigger -#define BIG_PATH_MAX 4096 - -// TTimo: decompose the BSP command into several steps so we can monitor them eventually -void QE_ExpandBspString (char *bspaction, GPtrArray *out_array, char *mapname) -{ - const char *in; - char *out; - char src[BIG_PATH_MAX]; - char rsh[BIG_PATH_MAX]; - char base[BIG_PATH_MAX]; - - strcpy(src, mapname); - strlwr(src); - in = strstr(src, "maps/"); - if (!in) - { - in = strstr(src, "maps/"); - } - if (in) - { - in += 5; - strcpy(base, in); - out = base; - while (*out) - { - if (*out == '\\') - { - *out = '/'; - } - out++; - } - } else - { - ExtractFileName (mapname, base); - } - - // this important step alters the map name to add fs_game - // NOTE: it used to add fs_basepath too - // the fs_basepath addition moved to being in the project file during the bug fixing rush - // but it may not have been the right thing to do - - // HACK: halflife compiler tools don't support -fs_game - // HACK: neither does JKII/SoF2/ etc.. - // do we use & have fs_game? - - if (g_pGameDescription->mGameFile != "hl.game" && - *ValueForKey(g_qeglobals.d_project_entity,"gamename") != '\0') - { - // set with fs_game - sprintf(src, "-fs_game %s \"%s\"", ValueForKey(g_qeglobals.d_project_entity,"gamename"), mapname); - } - else - { - sprintf(src, "\"%s\"", mapname); - } - - rsh[0] = 0; - - QE_ConvertDOSToUnixName(src, src); - - // initialise the first step - out = new char[BIG_PATH_MAX]; //% PATH_MAX - g_ptr_array_add( out_array, out ); - - in = ValueForKey( g_qeglobals.d_project_entity, bspaction ); - while (*in) - { - if (in[0] == '!') - { - strcpy (out, rsh); - out += strlen(rsh); - in++; - continue; - } - if (in[0] == '#') - { - char tmp[2048]; - // we process these only if monitoring - if (g_PrefsDlg.m_bWatchBSP) - { - // -connect global option (the only global option so far anyway) - strcpy (tmp, " -connect 127.0.0.1:39000 "); - strcpy (out, tmp); - out += strlen(tmp); - } - in++; - continue; - } - if (in[0] == '$') - { - // $ expansion - strcpy (out, src); - out += strlen(src); - in++; - continue; - } - if (in[0] == '@') - { - *out++ = '"'; - in++; - continue; - } - if (in[0] == '&') - if (in[1] == '&') - { - // start a new step - *out = 0; - in = in + 2; - out = new char[BIG_PATH_MAX]; //% PATH_MAX - g_ptr_array_add( out_array, out ); - } - *out++ = *in++; - } - *out = 0; -} - -void FindReplace(CString& strContents, const char* pTag, const char* pValue) -{ - if (strcmp(pTag, pValue) == 0) - return; - for (int nPos = strContents.Find(pTag); nPos >= 0; nPos = strContents.Find(pTag)) - { - int nRightLen = strContents.GetLength() - strlen(pTag) - nPos; - CString strLeft = strContents.Left(nPos); - CString strRight = strContents.Right(nRightLen); - strLeft += pValue; - strLeft += strRight; - strContents = strLeft; - } -} - -// save the map, deals with regioning -void SaveWithRegion(char *name) -{ - strcpy (name, currentmap); - if (region_active) - { - // temporary cut the region to save regular map - region_active = false; - Map_SaveFile (name, false); - region_active = true; - StripExtension (name); - strcat (name, ".reg"); - } - - Map_SaveFile (name, region_active); -} - -void RunBsp (char *command) -{ - GPtrArray *sys; - char batpath[BIG_PATH_MAX]; //% PATH_MAX - char temppath[BIG_PATH_MAX]; //% PATH_MAX - char name[BIG_PATH_MAX]; //% PATH_MAX - char cWork[BIG_PATH_MAX]; //% PATH_MAX - FILE *hFile; - unsigned int i; - - SetInspectorMode(W_CONSOLE); - - strcpy (temppath, g_strTempPath.GetBuffer ()); - - SaveWithRegion(name); - - const char *rsh = ValueForKey(g_qeglobals.d_project_entity, "rshcmd"); - if (rsh == NULL) - { - CString strPath, strFile; - - ExtractPath_and_Filename(name, strPath, strFile); - AddSlash(strPath); - strncpy(cWork, strPath, 1024); - strcat(cWork, strFile); - } else - { - strcpy(cWork, name); - } - - // get the array ready - //++timo TODO: free the array, free the strings ourselves with delete[] - sys = g_ptr_array_new(); - - QE_ExpandBspString (command, sys, cWork); - - if (g_PrefsDlg.m_bWatchBSP) - { - // grab the file name for engine running - char *bspname = new char[1024]; - ExtractFileName( currentmap, bspname ); - StripExtension( bspname ); - g_pParentWnd->GetWatchBSP()->DoMonitoringLoop( sys, bspname ); - } else - { - // write all the steps in a single BAT / .sh file and run it, don't bother monitoring it - CString strSys; - for (i=0; i < sys->len; i++ ) - { - strSys += (char *)g_ptr_array_index( sys, i); -#ifdef _WIN32 // write temp\junk.txt in win32... NOTE: stops output to shell prompt window - if (i==0) - strSys += " >"; - else - strSys += " >>"; - strSys += "\""; - strSys += temppath; - strSys += "junk.txt\""; -#endif - strSys += "\n"; - }; - -#if defined (__linux__) || defined (__APPLE__) - - // write qe3bsp.sh - sprintf (batpath, "%sqe3bsp.sh", temppath); - Sys_Printf("Writing the compile script to '%s'\n", batpath); - Sys_Printf("The build output will be saved in '%sjunk.txt'\n", temppath); - hFile = fopen(batpath, "w"); - if (!hFile) - Error ("Can't write to %s", batpath); - fprintf (hFile, "#!/bin/sh \n\n"); - fprintf (hFile, strSys.GetBuffer()); - fclose (hFile); - chmod (batpath, 0744); -#endif - -#ifdef _WIN32 - sprintf (batpath, "%sqe3bsp.bat", temppath); - Sys_Printf("Writing the compile script to '%s'\n", batpath); - Sys_Printf("The build output will be saved in '%sjunk.txt'\n", temppath); - hFile = fopen(batpath, "w"); - if (!hFile) - Error ("Can't write to %s", batpath); - fprintf (hFile, strSys.GetBuffer()); - fclose (hFile); -#endif - - Pointfile_Delete (); - -#if defined (__linux__) || defined (__APPLE__) - - pid_t pid; - - pid = fork (); - switch (pid) - { - case -1: - Error ("CreateProcess failed"); - break; - case 0: - execlp (batpath, batpath, NULL); - printf ("execlp error !"); - _exit (0); - break; - default: - break; - } -#endif - -#ifdef _WIN32 - Sys_Printf ("Running bsp command...\n"); - Sys_Printf ("\n%s\n", strSys.GetBuffer()); - - WinExec( batpath, SW_SHOWNORMAL ); -#endif - } -#ifdef _DEBUG - // yeah, do it .. but not now right before 1.1-TA-beta release - Sys_Printf("TODO: erase GPtrArray\n"); -#endif -} - -#if 0 - -#ifdef _WIN32 - -int WINAPI QEW_SetupPixelFormat(HDC hDC, qboolean zbuffer ) -{ - static PIXELFORMATDESCRIPTOR pfd = { - sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd - 1, // version number - PFD_DRAW_TO_WINDOW | // support window - PFD_SUPPORT_OPENGL | // support OpenGL - PFD_DOUBLEBUFFER, // double buffered - PFD_TYPE_RGBA, // RGBA type - 24, // 24-bit color depth - 0, 0, 0, 0, 0, 0, // color bits ignored - 0, // no alpha buffer - 0, // shift bit ignored - 0, // no accumulation buffer - 0, 0, 0, 0, // accum bits ignored - 32, // depth bits - 0, // no stencil buffer - 0, // no auxiliary buffer - PFD_MAIN_PLANE, // main layer - 0, // reserved - 0, 0, 0 // layer masks ignored - }; // - int pixelformat = 0; - - zbuffer = true; - if ( !zbuffer ) - pfd.cDepthBits = 0; - - if ( (pixelformat = ChoosePixelFormat(hDC, &pfd)) == 0 ) - { - LPVOID lpMsgBuf; - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPTSTR) &lpMsgBuf, - 0, - NULL - ); - Sys_FPrintf (SYS_WRN, "GetLastError: %s", lpMsgBuf); - Error ("ChoosePixelFormat failed"); - } - - if (!SetPixelFormat(hDC, pixelformat, &pfd)) - Error ("SetPixelFormat failed"); - - return pixelformat; -} - -#endif - -#endif +/* +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 +*/ + +#if defined (__linux__) || defined (__APPLE__) + #include + #include + #include + #ifdef __linux__ + #include + #endif + #include + #include + #include + #include + #include +#endif + +#include +#include "stdafx.h" +#include +#include +#include + +#include + +#include "watchbsp.h" +#include "filters.h" + +bool g_bBuildList = false; +int g_argc; +char** g_argv; + +// ============================================================================= +// Splash screen + +// get rid of it when debugging +#if defined (_DEBUG) + #define SKIP_SPLASH +#endif + +static GtkWidget *splash_screen; + +// called based on a timer, or in particular cases when we don't want to keep it around +gint try_destroy_splash (gpointer data) +{ + if (splash_screen) + { + gtk_widget_destroy (splash_screen); + splash_screen = NULL; + } + return FALSE; +} + +static void create_splash () +{ + GtkWidget *alert_frame, *alert_frame1, *pixmap; + + splash_screen = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_position (GTK_WINDOW (splash_screen), GTK_WIN_POS_CENTER); + gtk_widget_realize (splash_screen); + + alert_frame1 = gtk_frame_new (NULL); + gtk_widget_show (alert_frame1); + gtk_container_add (GTK_CONTAINER (splash_screen), alert_frame1); + gtk_frame_set_shadow_type (GTK_FRAME (alert_frame1), GTK_SHADOW_OUT); + + alert_frame = gtk_frame_new (NULL); + gtk_widget_show (alert_frame); + + gtk_container_add (GTK_CONTAINER (alert_frame1), alert_frame); + gtk_frame_set_shadow_type (GTK_FRAME (alert_frame), GTK_SHADOW_IN); + gtk_container_border_width (GTK_CONTAINER (alert_frame), 3); + + pixmap = gtk_preview_new (GTK_PREVIEW_COLOR); + gtk_widget_show (pixmap); + gtk_container_add (GTK_CONTAINER (alert_frame), pixmap); + + CString str; + guint16 width, height; + unsigned char *buf; + + str = g_strGameToolsPath; + str += "bitmaps/splash.bmp"; + + unsigned char* load_bitmap_file (const char* filename, guint16* width, guint16* height); + buf = load_bitmap_file (str.GetBuffer (), &width, &height); + + if (!buf) + { + str = g_strBitmapsPath; + str += "splash.bmp"; + + buf = load_bitmap_file (str.GetBuffer (), &width, &height); + } + + if (buf) + { + GtkPreview *preview = GTK_PREVIEW (pixmap); + gtk_preview_size (preview, width, height); + for (int y = 0; y < height; y++) + gtk_preview_draw_row (preview, buf+y*width*3, 0, y, width); + } + + gtk_widget_show_all (splash_screen); + + while (gtk_events_pending ()) + gtk_main_iteration (); +} + +// ============================================================================= +// Loki stuff + +#if defined (__linux__) || defined (__APPLE__) + +/* A short game name, could be used as argv[0] */ +static char game_name[100] = ""; + +/* The directory where the data files can be found (run directory) */ +static char datapath[PATH_MAX]; + +char *loki_gethomedir(void) +{ + char *home = NULL; + + home = getenv("HOME"); + if ( home == NULL ) + { + uid_t id = getuid(); + struct passwd *pwd; + + setpwent(); + while ( (pwd = getpwent()) != NULL ) + { + if ( pwd->pw_uid == id ) + { + home = pwd->pw_dir; + break; + } + } + endpwent(); + } + return home; +} + +/* Must be called BEFORE loki_initialize */ +void loki_setgamename(const char *n) +{ + strncpy(game_name, n, sizeof(game_name)); +} + + #ifdef __linux__ +/* Code to determine the mount point of a CD-ROM */ +int loki_getmountpoint(const char *device, char *mntpt, int max_size) +{ + char devpath[PATH_MAX], mntdevpath[PATH_MAX]; + FILE * mountfp; + struct mntent *mntent; + int mounted; + + /* Nothing to do with no device file */ + if ( device == NULL ) + { + *mntpt = '\0'; + return -1; + } + + /* Get the fully qualified path of the CD-ROM device */ + if ( realpath(device, devpath) == NULL ) + { + perror("realpath() on your CD-ROM failed"); + return(-1); + } + + /* Get the mount point */ + mounted = -1; + memset(mntpt, 0, max_size); + mountfp = setmntent( _PATH_MNTTAB, "r" ); + if ( mountfp != NULL ) + { + mounted = 0; + while ( (mntent = getmntent( mountfp )) != NULL ) + { + char *tmp, mntdev[1024]; + + strcpy(mntdev, mntent->mnt_fsname); + if ( strcmp(mntent->mnt_type, "supermount") == 0 ) + { + tmp = strstr(mntent->mnt_opts, "dev="); + if ( tmp ) + { + strcpy(mntdev, tmp+strlen("dev=")); + tmp = strchr(mntdev, ','); + if ( tmp ) + { + *tmp = '\0'; + } + } + } + if ( strncmp(mntdev, "/dev", 4) || + realpath(mntdev, mntdevpath) == NULL ) + { + continue; + } + if ( strcmp( mntdevpath, devpath ) == 0 ) + { + mounted = 1; + assert((int)strlen( mntent->mnt_dir ) < max_size); + strncpy( mntpt, mntent->mnt_dir, max_size-1); + mntpt[max_size-1] = '\0'; + break; + } + } + endmntent( mountfp ); + } + return(mounted); +} + #endif + +/* + This function gets the directory containing the running program. + argv0 - the 0'th argument to the program +*/ +// FIXME TTimo +// I don't understand this function. It looks like something cut from another piece of software +// we somehow get the g_strAppPath from it, but it's done through a weird scan across $PATH env. var. +// even worse, it doesn't behave the same in all cases .. works well when ran through gdb and borks when ran from a shell +void loki_initpaths(char *argv0) +{ + char temppath[PATH_MAX]; //, env[100]; + char *home; //, *ptr, *data_env; + + home = loki_gethomedir(); + if ( home == NULL ) + { + home = "."; + } + + if (*game_name == 0) /* Game name defaults to argv[0] */ + loki_setgamename(argv0); + + strcpy(temppath, argv0); /* If this overflows, it's your own fault :) */ + if ( ! strrchr(temppath, '/') ) + { + char *path; + char *last; + int found; + + found = 0; + path = getenv("PATH"); + do + { + /* Initialize our filename variable */ + temppath[0] = '\0'; + + /* Get next entry from path variable */ + last = strchr(path, ':'); + if ( ! last ) + last = path+strlen(path); + + /* Perform tilde expansion */ + if ( *path == '~' ) + { + strcpy(temppath, home); + ++path; + } + + /* Fill in the rest of the filename */ + if ( last > (path+1) ) + { + strncat(temppath, path, (last-path)); + strcat(temppath, "/"); + } + strcat(temppath, "./"); + strcat(temppath, argv0); + + /* See if it exists, and update path */ + if ( access(temppath, X_OK) == 0 ) + { + ++found; + } + path = last+1; + + } while ( *last && !found ); + + } else + { + /* Increment argv0 to the basename */ + argv0 = strrchr(argv0, '/')+1; + } + + /* Now canonicalize it to a full pathname for the data path */ + if ( realpath(temppath, datapath) ) + { + /* There should always be '/' in the path */ + *(strrchr(datapath, '/')) = '\0'; + } +} + +char *loki_getdatapath(void) +{ + return(datapath); +} + +#endif + +// end of Loki stuff +// ============================================================================= + +void error_redirect (const gchar *domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) +{ + gboolean in_recursion; + gboolean is_fatal; + char buf[256]; + + in_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0; + is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0; + log_level = (GLogLevelFlags) (log_level & G_LOG_LEVEL_MASK); + + if (!message) + message = "(NULL) message"; + + if (domain) + strcpy (buf, domain); + else + strcpy (buf, "**"); + strcat (buf, "-"); + + switch (log_level) + { + case G_LOG_LEVEL_ERROR: + if (in_recursion) + strcat (buf, "ERROR (recursed) **: "); + else + strcat (buf, "ERROR **: "); + break; + case G_LOG_LEVEL_CRITICAL: + if (in_recursion) + strcat (buf, "CRITICAL (recursed) **: "); + else + strcat (buf, "CRITICAL **: "); + break; + case G_LOG_LEVEL_WARNING: + if (in_recursion) + strcat (buf, "WARNING (recursed) **: "); + else + strcat (buf, "WARNING **: "); + break; + case G_LOG_LEVEL_MESSAGE: + if (in_recursion) + strcat (buf, "Message (recursed): "); + else + strcat (buf, "Message: "); + break; + case G_LOG_LEVEL_INFO: + if (in_recursion) + strcat (buf, "INFO (recursed): "); + else + strcat (buf, "INFO: "); + break; + case G_LOG_LEVEL_DEBUG: + if (in_recursion) + strcat (buf, "DEBUG (recursed): "); + else + strcat (buf, "DEBUG: "); + break; + default: + /* we are used for a log level that is not defined by GLib itself, + * try to make the best out of it. + */ + if (in_recursion) + strcat (buf, "LOG (recursed:"); + else + strcat (buf, "LOG ("); + if (log_level) + { + gchar string[] = "0x00): "; + gchar *p = string + 2; + guint i; + + i = g_bit_nth_msf (log_level, -1); + *p = i >> 4; + p++; + *p = '0' + (i & 0xf); + if (*p > '9') + *p += 'A' - '9' - 1; + + strcat (buf, string); + } else + strcat (buf, "): "); + } + + strcat (buf, message); + if (is_fatal) + strcat (buf, "\naborting...\n"); + else + strcat (buf, "\n"); + + printf ("%s\n", buf); + Sys_FPrintf (SYS_WRN, buf); + // TTimo NOTE: in some cases it may be handy to log only to the file +// Sys_FPrintf (SYS_NOCON, buf); +} + +int main (int argc, char* argv[]) +{ + char *libgl, *ptr; + int i, j, k; + +#ifdef _WIN32 + libgl = "opengl32.dll"; +#endif + +#if defined (__linux__) + libgl = "libGL.so.1"; +#endif + +#ifdef __APPLE__ + libgl = "/usr/X11R6/lib/libGL.1.dylib"; +#endif + +#if defined (__linux__) || defined (__APPLE__) + // Give away unnecessary root privileges. + // Important: must be done before calling gtk_init(). + char *loginname; + struct passwd *pw; + seteuid(getuid()); + if (geteuid() == 0 && (loginname = getlogin()) != NULL && + (pw = getpwnam(loginname)) != NULL) + setuid(pw->pw_uid); +#endif + + gtk_disable_setlocale(); + + gtk_init(&argc, &argv); + + if ((ptr = getenv ("Q3R_LIBGL")) != NULL) + libgl = ptr; + + for (i = 1; i < argc; i++) + { + char* param = argv[i]; + + if (param[0] == '-' && param[1] == '-') + { + param += 2; + + if ((strcmp (param, "libgl") == 0) && (i != argc)) + { + libgl = argv[i+1]; + argv[i] = argv[i+1] = NULL; + i++; + } else if (strcmp (param, "builddefs") == 0) + { + g_bBuildList = true; + argv[i] = NULL; + } + } + } + + for (i = 1; i < argc; i++) + { + for (k = i; k < argc; k++) + if (argv[k] != NULL) + break; + + if (k > i) + { + k -= i; + for (j = i + k; j < argc; j++) + argv[j-k] = argv[j]; + argc -= k; + } + } + + g_argc = argc; + g_argv = argv; + + g_strPluginsDir = "plugins/"; + g_strModulesDir = "modules/"; + +#ifdef _WIN32 + // get path to the editor + char* pBuffer = g_strAppPath.GetBufferSetLength(_MAX_PATH + 1); + GetModuleFileName(NULL, pBuffer, _MAX_PATH); + pBuffer[g_strAppPath.ReverseFind('\\') + 1] = '\0'; + QE_ConvertDOSToUnixName(pBuffer, pBuffer); + g_strAppPath.ReleaseBuffer(); + + g_strBitmapsPath = g_strAppPath; + g_strBitmapsPath += "bitmaps/"; + +#if 0 + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=639 + // now check if we are running from a network installation + // use a dummy file as the flag + FILE *f_netrun; + CString strNetrun; + strNetrun = g_strAppPath; strNetrun += NETRUN_FILENAME; + f_netrun = fopen(strNetrun.GetBuffer(), "r"); + if (f_netrun) + { + fclose(f_netrun); + g_PrefsDlg.m_bUseHomePath = true; + } +#endif + CGameDialog::UpdateNetrun(false); // read the netrun configuration + + if (CGameDialog::GetNetrun()) + { + // we have to find a per-user g_strTempPath + // this behaves the same as on Linux + g_strTempPath = getenv("USERPROFILE"); + if (!g_strTempPath.GetLength()) + { + CString msg; + msg = "Radiant is configured to run from a network installation.\n"; + msg += "I couldn't find the environement variable USERPROFILE\n"; + msg += "I'm going to use C:\\RadiantSettings. Please set USERPROFILE\n"; + gtk_MessageBox (NULL, msg, "Radiant - Network mode", MB_OK); + g_strTempPath = "C:\\"; + } + g_strTempPath += "\\RadiantSettings\\"; + Q_mkdir(g_strTempPath.GetBuffer(), 0755); + g_strTempPath += RADIANT_VERSION; + g_strTempPath += "\\"; + Q_mkdir(g_strTempPath.GetBuffer(), 0755); + } + else + { + // use the core path as temp (to save commandlist.txt, and do the .pid files) + g_strTempPath = g_strAppPath; + } + +#endif + +#if defined (__linux__) || defined (__APPLE__) + Str home; + home = g_get_home_dir (); + AddSlash (home); + home += ".radiant/"; + Q_mkdir (home.GetBuffer (), 0775); + home += RADIANT_VERSION; + Q_mkdir (home.GetBuffer (), 0775); + g_strTempPath = home.GetBuffer (); + AddSlash (g_strTempPath); + + loki_initpaths(argv[0]); + + // NOTE: we build g_strAppPath with a '/' (or '\' on WIN32) + // it's a general convention in Radiant to have the slash at the end of directories + char real[PATH_MAX]; + realpath (loki_getdatapath(), real); + if (real[strlen(real)-1] != '/') + strcat(real, "/"); + + g_strAppPath = real; + +#if 0 + printf("g_strAppPath: %s\n", g_strAppPath.GetBuffer()); +#endif + + // radiant is installed in the parent dir of "tools/" + // NOTE: this is not very easy for debugging + // maybe add options to lookup in several places? + // (for now I had to create symlinks) + g_strBitmapsPath = g_strAppPath; + g_strBitmapsPath += "bitmaps/"; +#if 0 + printf("g_strBitmapsPath: %s\n", g_strBitmapsPath.GetBuffer()); +#endif + + // we will set this right after the game selection is done + g_strGameToolsPath = g_strAppPath; + +#endif + + // init the DTD path + g_strDTDPath = g_strAppPath; + g_strDTDPath += "dtds/"; + + /*! + the global prefs loading / game selection dialog might fail for any reason we don't know about + we need to catch when it happens, to cleanup the stateful prefs which might be killing it + and to turn on console logging for lookup of the problem + this is the first part of the two step .pid system + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=297 + */ + g_pidFile = g_strTempPath.GetBuffer (); + g_pidFile += "radiant.pid"; + + FILE *pid; + pid = fopen (g_pidFile.GetBuffer(), "r"); + if (pid != NULL) + { + fclose (pid); + CString msg; + + if (remove (g_pidFile.GetBuffer ()) == -1) + { + msg = "WARNING: Could not delete "; msg += g_pidFile; + gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR ); + } + + // in debug, never prompt to clean registry, turn console logging auto after a failed start +#if !defined(_DEBUG) + msg = "Found the file "; + msg += g_pidFile; + msg += ".\nThis indicates that Radiant failed during the game selection startup last time it was run.\n" + "Choose YES to clean Radiant's registry settings and shut down Radiant.\n" + "WARNING: the global prefs will be lost if you choose YES."; + + if (gtk_MessageBox (NULL, msg, "Radiant - Reset global startup?", MB_YESNO | MB_ICONQUESTION) == IDYES) + { + // remove global prefs and shutdown + g_PrefsDlg.mGamesDialog.Reset(); + // remove the prefs file (like a full reset of the registry) + //remove (g_PrefsDlg.m_inipath->str); + gtk_MessageBox(NULL, "Removed global settings, choose OK to close Radiant.", "Radiant", MB_OK ); + _exit(-1); + } + msg = "Logging console output to "; + msg += g_strTempPath; + msg += "radiant.log\nRefer to the log if Radiant fails to start again."; + + gtk_MessageBox (NULL, msg, "Radiant - Console Log", MB_OK); +#endif + + // set without saving, the class is not in a coherent state yet + // just do the value change and call to start logging, CGamesDialog will pickup when relevant + g_PrefsDlg.mGamesDialog.m_bLogConsole = true; + g_PrefsDlg.mGamesDialog.m_bForceLogConsole = true; + Sys_LogFile(); + } + + // create a primary .pid for global init run + pid = fopen (g_pidFile.GetBuffer(), "w"); + if (pid) + fclose (pid); + + // a safe check to avoid people running broken installations + // (otherwise, they run it, crash it, and blame us for not forcing them hard enough to pay attention while installing) + // make something idiot proof and someone will make better idiots, this may be overkill + // let's leave it disabled in debug mode in any case + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=431 +#ifndef _DEBUG +#define CHECK_VERSION +#endif +#ifdef CHECK_VERSION + // locate and open RADIANT_MAJOR and RADIANT_MINOR + qboolean bVerIsGood = true; + Str ver_file_name; + ver_file_name = g_strAppPath; + ver_file_name += "RADIANT_MAJOR"; + FILE *ver_file = fopen (ver_file_name.GetBuffer(), "r"); + if (ver_file) + { + char buf[10]; + int chomp; + fread(buf, 1, 10, ver_file); + // chomp it (the hard way) + chomp = 0; + while(buf[chomp] >= '0' && buf[chomp] <= '9') + chomp++; + buf[chomp] = '\0'; + if (strcmp(buf, RADIANT_MAJOR_VERSION)) + { + Sys_Printf("ERROR: file RADIANT_MAJOR doesn't match ('%s')\n", buf); + bVerIsGood = false; + } + } + else + { + Sys_Printf("ERROR: can't find RADIANT_MAJOR in '%s'\n", ver_file_name.GetBuffer()); + bVerIsGood = false; + } + ver_file_name = g_strAppPath; + ver_file_name += "RADIANT_MINOR"; + ver_file = fopen (ver_file_name.GetBuffer(), "r"); + if (ver_file) + { + char buf[10]; + int chomp; + fread(buf, 1, 10, ver_file); + // chomp it (the hard way) + chomp = 0; + while(buf[chomp] >= '0' && buf[chomp] <= '9') + chomp++; + buf[chomp] = '\0'; + if (strcmp(buf, RADIANT_MINOR_VERSION)) + { + Sys_Printf("ERROR: file RADIANT_MINOR doesn't match ('%s')\n", buf); + bVerIsGood = false; + } + } + else + { + Sys_Printf("ERROR: can't find RADIANT_MINOR in '%s'\n", ver_file_name.GetBuffer()); + bVerIsGood = false; + } + if (!bVerIsGood) + { + CString msg; + msg = "This editor binary (" RADIANT_VERSION ") doesn't match what the latest setup has configured in this directory\n"; + msg += "Make sure you run the right/latest editor binary you installed\n"; + msg += g_strAppPath; msg += "\n"; + msg += "Check http://www.qeradiant.com/faq/index.cgi?file=219 for more information"; + gtk_MessageBox(NULL, msg.GetBuffer(), "Radiant", MB_OK, "http://www.qeradiant.com/faq/index.cgi?file=219"); + _exit(-1); + } +#endif + + g_qeglobals.disable_ini = false; + g_PrefsDlg.Init (); + + // close the primary + if (remove (g_pidFile.GetBuffer ()) == -1) + { + CString msg; + msg = "WARNING: Could not delete "; msg += g_pidGameFile; + gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR ); + } + + /*! + now the secondary game dependant .pid file + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=297 + */ + g_pidGameFile = g_PrefsDlg.m_rc_path->str; + g_pidGameFile += "radiant-game.pid"; + + pid = fopen (g_pidGameFile.GetBuffer(), "r"); + if (pid != NULL) + { + fclose (pid); + CString msg; + if (remove (g_pidGameFile.GetBuffer ()) == -1) + { + msg = "WARNING: Could not delete "; msg += g_pidGameFile; + gtk_MessageBox (NULL, msg, "Radiant", MB_OK | MB_ICONERROR ); + } + + msg = "Found the file "; + msg += g_pidGameFile; + msg += ".\nThis indicates that Radiant failed to load the last time it was run.\n" + "Choose YES to clean Radiant's registry settings and shut down Radiant.\n" + "WARNING: preferences will be lost if you choose YES."; + + // in debug, never prompt to clean registry, turn console logging auto after a failed start +#if !defined(_DEBUG) + //bleh + if (gtk_MessageBox (NULL, msg, "Radiant - Clean Registry?", MB_YESNO | MB_ICONQUESTION) == IDYES) + { + // remove the game prefs files + remove (g_PrefsDlg.m_inipath->str); + char buf[PATH_MAX]; + sprintf(buf, "%sSavedInfo.bin", g_PrefsDlg.m_rc_path->str); + remove(buf); + // remove the global pref too + g_PrefsDlg.mGamesDialog.Reset(); + gtk_MessageBox(NULL, "Cleaned registry settings, choose OK to close Radiant.\nThe next time Radiant runs it will use default settings.", "Radiant", MB_OK ); + _exit(-1); + } + msg = "Logging console output to "; + msg += g_strTempPath; + msg += "radiant.log\nRefer to the log if Radiant fails to start again."; + + gtk_MessageBox (NULL, msg, "Radiant - Console Log", MB_OK); +#endif + + // force console logging on! (will go in prefs too) + g_PrefsDlg.mGamesDialog.m_bLogConsole = true; + g_PrefsDlg.mGamesDialog.SavePrefs(); + Sys_LogFile(); + + g_PrefsDlg.LoadPrefs(); + + } else + { + // create one, will remove right after entering message loop + pid = fopen (g_pidGameFile.GetBuffer(), "w"); + if (pid) + fclose (pid); + + g_PrefsDlg.LoadPrefs(); + +#ifndef _DEBUG // I can't be arsed about that prompt in debug mode + // if console logging is on in the prefs, warn about performance hit + if (g_PrefsDlg.mGamesDialog.m_bLogConsole) + { + if (gtk_MessageBox (NULL, "Preferences indicate that console logging is on. This affects performance.\n" + "Turn it off?", "Radiant", MB_YESNO | MB_ICONQUESTION) == IDYES) + { + g_PrefsDlg.mGamesDialog.m_bLogConsole = false; + g_PrefsDlg.mGamesDialog.SavePrefs(); + } + } +#endif + // toggle console logging if necessary + Sys_LogFile(); + } + + // FIXME http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=639 + // we should search in g_strTempPath, then move over to look at g_strAppPath? +#ifdef _WIN32 + // fine tune the look of the app using a gtk rc file + // we try to load an RC file placed in the application directory + // build the full path + Str sRCFile; + sRCFile = g_strAppPath; + sRCFile += "radiantgtkrc"; + // we load that file with g_new in gtk_rc_parse_file (gtkrc.c), change the '/' into '\\' + pBuffer = (char *)sRCFile.GetBuffer(); + for (i=0; i 0) + Map_LoadFile(g_PrefsDlg.m_strLastMap.GetBuffer()); + else + Map_New(); + + // load up shaders now that we have the map loaded + // eviltypeguy + Texture_ShowStartupShaders (); + +#ifndef SKIP_SPLASH + gdk_window_raise (splash_screen->window); + gtk_window_set_transient_for (GTK_WINDOW (splash_screen), GTK_WINDOW (g_pParentWnd->m_pWidget)); + gtk_timeout_add (1000, try_destroy_splash, NULL); +#endif + + g_pParentWnd->GetSynapseServer().DumpActiveClients(); + + //++timo: temporary debug + g_pParentWnd->DoWatchBSP(); + + gtk_main (); + + // close the log file if any + // NOTE: don't save prefs past this point! + g_PrefsDlg.mGamesDialog.m_bLogConsole = false; + // set the console window to NULL to avoid Sys_Printf crashing + g_qeglobals_gui.d_edit = NULL; + Sys_LogFile(); + + // NOTE TTimo not sure what this _exit(0) call is worth + // restricting it to linux build +#ifdef __linux__ + _exit (0); +#endif + return 0; +} + +// ydnar: quick and dirty fix, just make the buffer bigger +#define BIG_PATH_MAX 4096 + +// TTimo: decompose the BSP command into several steps so we can monitor them eventually +void QE_ExpandBspString (char *bspaction, GPtrArray *out_array, char *mapname) +{ + const char *in; + char *out; + char src[BIG_PATH_MAX]; + char rsh[BIG_PATH_MAX]; + char base[BIG_PATH_MAX]; + + strcpy(src, mapname); + strlwr(src); + in = strstr(src, "maps/"); + if (!in) + { + in = strstr(src, "maps/"); + } + if (in) + { + in += 5; + strcpy(base, in); + out = base; + while (*out) + { + if (*out == '\\') + { + *out = '/'; + } + out++; + } + } else + { + ExtractFileName (mapname, base); + } + + // this important step alters the map name to add fs_game + // NOTE: it used to add fs_basepath too + // the fs_basepath addition moved to being in the project file during the bug fixing rush + // but it may not have been the right thing to do + + // HACK: halflife compiler tools don't support -fs_game + // HACK: neither does JKII/SoF2/ etc.. + // do we use & have fs_game? + + if (g_pGameDescription->mGameFile != "hl.game" && + *ValueForKey(g_qeglobals.d_project_entity,"gamename") != '\0') + { + // set with fs_game + sprintf(src, "-fs_game %s \"%s\"", ValueForKey(g_qeglobals.d_project_entity,"gamename"), mapname); + } + else + { + sprintf(src, "\"%s\"", mapname); + } + + rsh[0] = 0; + + QE_ConvertDOSToUnixName(src, src); + + // initialise the first step + out = new char[BIG_PATH_MAX]; //% PATH_MAX + g_ptr_array_add( out_array, out ); + + in = ValueForKey( g_qeglobals.d_project_entity, bspaction ); + while (*in) + { + if (in[0] == '!') + { + strcpy (out, rsh); + out += strlen(rsh); + in++; + continue; + } + if (in[0] == '#') + { + char tmp[2048]; + // we process these only if monitoring + if (g_PrefsDlg.m_bWatchBSP) + { + // -connect global option (the only global option so far anyway) + strcpy (tmp, " -connect 127.0.0.1:39000 "); + strcpy (out, tmp); + out += strlen(tmp); + } + in++; + continue; + } + if (in[0] == '$') + { + // $ expansion + strcpy (out, src); + out += strlen(src); + in++; + continue; + } + if (in[0] == '@') + { + *out++ = '"'; + in++; + continue; + } + if (in[0] == '&') + if (in[1] == '&') + { + // start a new step + *out = 0; + in = in + 2; + out = new char[BIG_PATH_MAX]; //% PATH_MAX + g_ptr_array_add( out_array, out ); + } + *out++ = *in++; + } + *out = 0; +} + +void FindReplace(CString& strContents, const char* pTag, const char* pValue) +{ + if (strcmp(pTag, pValue) == 0) + return; + for (int nPos = strContents.Find(pTag); nPos >= 0; nPos = strContents.Find(pTag)) + { + int nRightLen = strContents.GetLength() - strlen(pTag) - nPos; + CString strLeft = strContents.Left(nPos); + CString strRight = strContents.Right(nRightLen); + strLeft += pValue; + strLeft += strRight; + strContents = strLeft; + } +} + +// save the map, deals with regioning +void SaveWithRegion(char *name) +{ + strcpy (name, currentmap); + if (region_active) + { + // temporary cut the region to save regular map + region_active = false; + Map_SaveFile (name, false); + region_active = true; + StripExtension (name); + strcat (name, ".reg"); + } + + Map_SaveFile (name, region_active); +} + +void RunBsp (char *command) +{ + GPtrArray *sys; + char batpath[BIG_PATH_MAX]; //% PATH_MAX + char temppath[BIG_PATH_MAX]; //% PATH_MAX + char name[BIG_PATH_MAX]; //% PATH_MAX + char cWork[BIG_PATH_MAX]; //% PATH_MAX + FILE *hFile; + unsigned int i; + + SetInspectorMode(W_CONSOLE); + + strcpy (temppath, g_strTempPath.GetBuffer ()); + + SaveWithRegion(name); + + const char *rsh = ValueForKey(g_qeglobals.d_project_entity, "rshcmd"); + if (rsh == NULL) + { + CString strPath, strFile; + + ExtractPath_and_Filename(name, strPath, strFile); + AddSlash(strPath); + strncpy(cWork, strPath, 1024); + strcat(cWork, strFile); + } else + { + strcpy(cWork, name); + } + + // get the array ready + //++timo TODO: free the array, free the strings ourselves with delete[] + sys = g_ptr_array_new(); + + QE_ExpandBspString (command, sys, cWork); + + if (g_PrefsDlg.m_bWatchBSP) + { + // grab the file name for engine running + char *bspname = new char[1024]; + ExtractFileName( currentmap, bspname ); + StripExtension( bspname ); + g_pParentWnd->GetWatchBSP()->DoMonitoringLoop( sys, bspname ); + } else + { + // write all the steps in a single BAT / .sh file and run it, don't bother monitoring it + CString strSys; + for (i=0; i < sys->len; i++ ) + { + strSys += (char *)g_ptr_array_index( sys, i); +#ifdef _WIN32 // write temp\junk.txt in win32... NOTE: stops output to shell prompt window + if (i==0) + strSys += " >"; + else + strSys += " >>"; + strSys += "\""; + strSys += temppath; + strSys += "junk.txt\""; +#endif + strSys += "\n"; + }; + +#if defined (__linux__) || defined (__APPLE__) + + // write qe3bsp.sh + sprintf (batpath, "%sqe3bsp.sh", temppath); + Sys_Printf("Writing the compile script to '%s'\n", batpath); + Sys_Printf("The build output will be saved in '%sjunk.txt'\n", temppath); + hFile = fopen(batpath, "w"); + if (!hFile) + Error ("Can't write to %s", batpath); + fprintf (hFile, "#!/bin/sh \n\n"); + fprintf (hFile, strSys.GetBuffer()); + fclose (hFile); + chmod (batpath, 0744); +#endif + +#ifdef _WIN32 + sprintf (batpath, "%sqe3bsp.bat", temppath); + Sys_Printf("Writing the compile script to '%s'\n", batpath); + Sys_Printf("The build output will be saved in '%sjunk.txt'\n", temppath); + hFile = fopen(batpath, "w"); + if (!hFile) + Error ("Can't write to %s", batpath); + fprintf (hFile, strSys.GetBuffer()); + fclose (hFile); +#endif + + Pointfile_Delete (); + +#if defined (__linux__) || defined (__APPLE__) + + pid_t pid; + + pid = fork (); + switch (pid) + { + case -1: + Error ("CreateProcess failed"); + break; + case 0: + execlp (batpath, batpath, NULL); + printf ("execlp error !"); + _exit (0); + break; + default: + break; + } +#endif + +#ifdef _WIN32 + Sys_Printf ("Running bsp command...\n"); + Sys_Printf ("\n%s\n", strSys.GetBuffer()); + + WinExec( batpath, SW_SHOWNORMAL ); +#endif + } +#ifdef _DEBUG + // yeah, do it .. but not now right before 1.1-TA-beta release + Sys_Printf("TODO: erase GPtrArray\n"); +#endif +} + +#if 0 + +#ifdef _WIN32 + +int WINAPI QEW_SetupPixelFormat(HDC hDC, qboolean zbuffer ) +{ + static PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd + 1, // version number + PFD_DRAW_TO_WINDOW | // support window + PFD_SUPPORT_OPENGL | // support OpenGL + PFD_DOUBLEBUFFER, // double buffered + PFD_TYPE_RGBA, // RGBA type + 24, // 24-bit color depth + 0, 0, 0, 0, 0, 0, // color bits ignored + 0, // no alpha buffer + 0, // shift bit ignored + 0, // no accumulation buffer + 0, 0, 0, 0, // accum bits ignored + 32, // depth bits + 0, // no stencil buffer + 0, // no auxiliary buffer + PFD_MAIN_PLANE, // main layer + 0, // reserved + 0, 0, 0 // layer masks ignored + }; // + int pixelformat = 0; + + zbuffer = true; + if ( !zbuffer ) + pfd.cDepthBits = 0; + + if ( (pixelformat = ChoosePixelFormat(hDC, &pfd)) == 0 ) + { + LPVOID lpMsgBuf; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + Sys_FPrintf (SYS_WRN, "GetLastError: %s", lpMsgBuf); + Error ("ChoosePixelFormat failed"); + } + + if (!SetPixelFormat(hDC, pixelformat, &pfd)) + Error ("SetPixelFormat failed"); + + return pixelformat; +} + +#endif + +#endif diff --git a/radiant/mainframe.cpp b/radiant/mainframe.cpp index 3aedadda..c1010f9f 100644 --- a/radiant/mainframe.cpp +++ b/radiant/mainframe.cpp @@ -1,7785 +1,7785 @@ -/* -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 -*/ - -// -// Main Window for Q3Radiant -// -// Leonardo Zide (leo@lokigames.com) -// - -#include "stdafx.h" -#ifdef _WIN32 -extern "C" { -#include -#define COMPILE_MULTIMON_STUBS -#include -} -#endif -#include -#include -#include -#include -#if defined (__linux__) || defined (__APPLE__) - #include -#endif -#include "gtkmisc.h" -#include "groupdialog.h" -#include "patchdialog.h" -#include "filters.h" - -// use this to verbose what happens with the beyboard -#ifdef _DEBUG -// #define DBG_KBD -#endif - -// globals -CString g_strAppPath; ///< holds the full path of the executable -CString g_strDTDPath; ///< path to the DTD files -/*! -see http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=297 for the two below -*/ -CString g_pidFile; ///< the global .pid file (only for global part of the startup) -CString g_pidGameFile; ///< the game-specific .pid file -CString g_strBitmapsPath; // directory where the bitmaps are stored - -/*! -points to the game tools directory, for instance -C:\Program Files\Quake III Arena\GtkRadiant -(or other games) -this is one of the main variables that are configured by the game selection on startup -/plugins -/modules -and also q3map, bspc -*/ -CString g_strGameToolsPath; ///< this is set by g_PrefsDlg.mGamesDialog -CGameDescription *g_pGameDescription; ///< shortcut to g_PrefsDlg.mGamesDialog.m_pCurrentDescription -CString g_strPluginsDir; ///< name of plugins directory, always sub-directory of toolspath -CString g_strModulesDir; ///< name of modules directory, always sub-directory of toolspath - -/*! -directory for temp files -NOTE: on *nix this is were we check for .pid -*/ -CString g_strTempPath; -MainFrame* g_pParentWnd = NULL; // used to precast to CMainFrame -PrefsDlg g_Preferences; // global prefs instance -PrefsDlg& g_PrefsDlg = g_Preferences; // reference used throughout -int g_nUpdateBits = 0; // window update flags -bool g_bScreenUpdates = true; // whether window painting is active, used in a few places - // to disable updates for speed reasons - // both of the above should be made members of CMainFrame -int g_bIgnoreCommands; // Used to ignore commands when checking menus/toolbars -GSList *g_BSPFrontendCommands; // List of commands in the BSP menu - -const int CMD_TEXTUREWAD_END = CMD_TEXTUREWAD + MAX_TEXTUREDIRS - 1; -const int CMD_BSPCOMMAND_END = CMD_BSPCOMMAND + 127; - -extern bool g_bCrossHairs; -extern int g_argc; -extern char** g_argv; -extern PatchDialog g_PatchDialog; - -GtkAccelGroup* global_accel; - -void Select_Ungroup (); - -// command mapping stuff -// -// m_strCommand is the command string -// m_nKey is the GDK_??? equivelant -// m_nModifiers are key states as follows -// bit -// 1 - shift -// 2 - alt -// 4 - control -// 8 - press only -// -#define SPEED_MOVE 32 -#define SPEED_TURN 22.5 - -// NOTE: the menu item field is REQUIRED, Gtk uses it to bind the keyboard shortcut -// - if you add a command here and you don't want a menu item, use the "hidden" menu -// - if you decide to add a menu item, check if it's not in the "hidden" menu already -SCommandInfo g_Commands[] = -{ - {"CycleOutlineStyle", 'J', 0x00, ID_SELECTION_OUTLINESTYLE, "menu_selection_outlinestyle"}, - {"CSGMerge", 'U', 0x04, ID_SELECTION_CSGMERGE, "menu_selection_csgmerge"}, - {"CSGSubtract", 'U', 0x01, ID_SELECTION_CSGSUBTRACT, "menu_selection_csgsubstract"}, - // {"ViewGroups", 'G', 0x00, ID_VIEW_GROUPS, "menu_view_groups"}, (temporary disabled) - {"HideSelected", 'H', 0x00, ID_VIEW_HIDESHOW_HIDESELECTED, "menu_view_hideshow_hideselected"}, - {"ShowHidden", 'H', 0x01, ID_VIEW_HIDESHOW_SHOWHIDDEN, "menu_view_hideshow_showhidden"}, - {"BendMode", 'B', 0x00, ID_PATCH_BEND, "menu_patch_bend"}, - {"FitTexture", 'B', 0x01, IDC_BTN_FACEFIT, "menu_idc_btn_facefit"}, - {"ViewTextures", 'T', 0, ID_VIEW_TEXTURE, "menu_view_texture"}, - {"ThickenPatch", 'T', 0x04, ID_CURVE_THICKEN, "menu_curve_thicken"}, - {"MakeOverlayPatch", 'Y', 0, ID_CURVE_OVERLAY_SET, "menu_curve_overlay_set"}, - {"ClearPatchOverlays", 'L', 0x04, ID_CURVE_OVERLAY_CLEAR, "menu_curve_overlay_clear"}, - {"SurfaceInspector", 'S', 0, ID_TEXTURES_INSPECTOR, "menu_textures_inspector"}, - {"PatchInspector", 'S', 0x01, ID_PATCH_INSPECTOR, "menu_patch_inspector"}, - {"RedisperseRows", 'E', 0x04, ID_CURVE_REDISPERSE_ROWS, "menu_curve_redisperse_rows"}, - {"RedisperseIntermediateCols", 'E', 0x05, ID_CURVE_REDISPERSE_INTERMEDIATE_COLS, "menu_curve_redisperse_cols"}, - {"InvertCurveTextureX", 'I', 0x05, ID_CURVE_NEGATIVETEXTUREY, "menu_curve_negativetexturey"}, - {"InvertCurveTextureY", 'I', 0x01, ID_CURVE_NEGATIVETEXTUREX, "menu_curve_negativetexturex"}, - {"InvertCurve", 'I', 0x04, ID_CURVE_NEGATIVE, "menu_curve_negative"}, - {"IncPatchColumn", GDK_KP_Add, 0x05, ID_CURVE_INSERTCOLUMN, "menu_curve_insertcolumn"}, - {"IncPatchRow", GDK_KP_Add, 0x04, ID_CURVE_INSERTROW, "menu_curve_insertrow"}, - {"DecPatchColumn", GDK_KP_Subtract, 0x05, ID_CURVE_DELETECOLUMN, "menu_curve_deletecolumn"}, - {"DecPatchRow", GDK_KP_Subtract, 0x04, ID_CURVE_DELETEROW, "menu_curve_deleterow"}, - {"Patch TAB", GDK_Tab, 0x00, ID_PATCH_TAB, "menu_patch_tab"}, - {"Patch TAB", GDK_Tab, 0x01, ID_PATCH_TAB, "menu_patch_tab"}, - {"SelectNudgeDown", GDK_Down, 0x02, ID_SELECTION_SELECT_NUDGEDOWN, "menu_selection_select_nudgedown"}, - {"EntityColor",'K', 0, ID_MISC_SELECTENTITYCOLOR, "menu_misc_select_entitycolor"}, - {"CameraForward", GDK_Up, 0, ID_CAMERA_FORWARD, "menu_camera_forward"}, - {"CameraBack", GDK_Down, 0, ID_CAMERA_BACK, "menu_camera_back"}, - {"CameraLeft", GDK_Left, 0, ID_CAMERA_LEFT, "menu_camera_left"}, - {"CameraRight", GDK_Right, 0, ID_CAMERA_RIGHT, "menu_camera_right"}, - {"CameraUp", 'D', 0, ID_CAMERA_UP, "menu_camera_up"}, - {"CameraDown", 'C', 0, ID_CAMERA_DOWN, "menu_camera_down"}, - {"CameraAngleUp", 'A', 0, ID_CAMERA_ANGLEUP, "menu_camera_angleup"}, - {"CameraAngleDown", 'Z', 0, ID_CAMERA_ANGLEDOWN, "menu_camera_angledown"}, - {"CameraStrafeRight", GDK_period, 0, ID_CAMERA_STRAFERIGHT, "menu_camera_straferight"}, - {"CameraStrafeLeft", GDK_comma, 0, ID_CAMERA_STRAFELEFT, "menu_camera_strafeleft"}, - {"ToggleGrid", '0', 0, ID_GRID_TOGGLE, "menu_grid_toggle"}, - {"SetGrid1", '1', 0, ID_GRID_1, "menu_grid_1"}, - {"SetGrid2", '2', 0, ID_GRID_2, "menu_grid_2"}, - {"SetGrid4", '3', 0, ID_GRID_4, "menu_grid_4"}, - {"SetGrid8", '4', 0, ID_GRID_8, "menu_grid_8"}, - {"SetGrid16", '5', 0, ID_GRID_16, "menu_grid_16"}, - {"SetGrid32", '6', 0, ID_GRID_32, "menu_grid_32"}, - {"SetGrid64", '7', 0, ID_GRID_64, "menu_grid_64"}, - {"SetGrid128", '8', 0, ID_GRID_128, "menu_grid_128"}, - {"SetGrid256", '9', 0, ID_GRID_256, "menu_grid_256"}, - {"DragEdges", 'E', 0, ID_SELECTION_DRAGEDGES, "menu_selection_dragedges"}, - {"DragVertices", 'V', 0, ID_SELECTION_DRAGVERTECIES, "menu_selection_dragvertecies"}, - {"ViewEntityInfo", 'N', 0, ID_VIEW_ENTITY, "menu_view_entity"}, - // {"ViewConsole", 'O', 0, ID_VIEW_CONSOLE, "menu_0,"}, - {"CloneSelection", GDK_space, 0, ID_SELECTION_CLONE, "menu_selection_clone"}, - {"DeleteSelection", GDK_BackSpace, 0, ID_SELECTION_DELETE, "menu_selection_delete"}, - {"UnSelectSelection", GDK_Escape, 0, ID_SELECTION_DESELECT, "menu_selection_deselect"}, - {"CenterView", GDK_End, 0, ID_VIEW_CENTER, "menu_view_center"}, - {"ZoomOut", GDK_Insert, 0, ID_VIEW_ZOOMOUT, "menu_view_zoomout"}, - {"ZoomIn", GDK_Delete, 0, ID_VIEW_ZOOMIN, "menu_view_zoomin"}, - {"UpFloor", GDK_Prior, 0, ID_VIEW_UPFLOOR, "menu_view_upfloor"}, - {"DownFloor", GDK_Next, 0, ID_VIEW_DOWNFLOOR, "menu_view_downfloor"}, - {"ToggleClipper", 'X', 0, ID_VIEW_CLIPPER, "menu_view_clipper"}, - {"ToggleCrosshairs", 'X', 0x01, ID_VIEW_CROSSHAIR, "menu_view_crosshair"}, - {"TogTexLock", 'T', 0x01, ID_TOGGLE_LOCK, "menu_toggle_lock"}, - {"TogTexRotLock", 'R', 0x01, ID_TOGGLE_ROTATELOCK, "menu_toggle_rotatelock"}, - {"ToggleRealtime", 'R', 0x04, ID_VIEW_CAMERAUPDATE, "menu_view_cameraupdate"}, - {"EntityList", 'L', 0, ID_EDIT_ENTITYINFO, "menu_edit_entityinfo"}, - {"Preferences", 'P', 0, ID_PREFS, "menu_prefs"}, - {"ToggleCamera", 'C', 0x05, ID_TOGGLECAMERA, "menu_togglecamera"}, - {"ToggleConsole", 'O', 0, ID_TOGGLECONSOLE, "menu_toggleconsole"}, - {"ToggleView", 'V', 0x05, ID_TOGGLEVIEW, "menu_toggleview"}, - {"ToggleZ", 'Z', 0x05, ID_TOGGLEZ, "menu_togglez"}, - {"ConnectSelection", 'K', 0x04, ID_SELECTION_CONNECT, "menu_selection_connect"}, - {"Brush3Sided", '3', 0x04, ID_BRUSH_3SIDED, "menu_brush_3sided"}, - {"Brush4Sided", '4', 0x04, ID_BRUSH_4SIDED, "menu_brush_4sided"}, - {"Brush5Sided", '5', 0x04, ID_BRUSH_5SIDED, "menu_brush_5sided"}, - {"Brush6Sided", '6', 0x04, ID_BRUSH_6SIDED, "menu_brush_6sided"}, - {"Brush7Sided", '7', 0x04, ID_BRUSH_7SIDED, "menu_brush_7sided"}, - {"Brush8Sided", '8', 0x04, ID_BRUSH_8SIDED, "menu_brush_8sided"}, - {"Brush9Sided", '9', 0x04, ID_BRUSH_9SIDED, "menu_brush_9sided"}, - {"MatrixTranspose", 'M', 0x05, ID_CURVE_MATRIX_TRANSPOSE, "menu_curve_matrix_transpose"}, - {"MakeDetail", 'M', 0x04, ID_SELECTION_MAKE_DETAIL, "menu_selection_make_detail"}, - {"MapInfo", 'M', 0, ID_EDIT_MAPINFO, "menu_edit_mapinfo"}, - {"NextLeakSpot", 'K', 0x05, ID_MISC_NEXTLEAKSPOT, "menu_misc_nextleakspot"}, - {"PrevLeakSpot", 'L', 0x05, ID_MISC_PREVIOUSLEAKSPOT, "menu_misc_previousleakspot"}, - {"FileOpen", 'O', 0x04, ID_FILE_OPEN, "menu_file_open"}, - {"FileSave", 'S', 0x04, ID_FILE_SAVE, "menu_file_save"}, - //% {"Exit", 'X', 0x04, ID_FILE_EXIT, "menu_file_exit"}, // ydnar: Ctrl+X should be cut - {"CenterXYView", GDK_Tab, 0x05, ID_VIEW_CENTERVIEW, "menu_view_centerview"}, - {"NextView", GDK_Tab, 0x04, ID_VIEW_NEXTVIEW, "menu_view_nextview"}, - {"ClipSelected", GDK_Return, 0x00, ID_CLIP_SELECTED, "menu_clip_selected"}, - {"SplitSelected", GDK_Return, 0x01, ID_SPLIT_SELECTED, "menu_split_selected"}, - {"FlipClip", GDK_Return, 0x04, ID_FLIP_CLIP, "menu_flip_clip"}, - {"MouseRotate", 'R', 0x00, ID_SELECT_MOUSEROTATE, "menu_select_mouserotate"}, - {"Copy", 'C', 0x04, ID_EDIT_COPYBRUSH, "menu_edit_copybrush"}, - {"Paste", 'V', 0x04, ID_EDIT_PASTEBRUSH, "menu_edit_pastebrush"}, - {"PasteToCamera", 'V', RAD_ALT, ID_EDIT_PASTEBRUSHTOCAMERA, "menu_edit_pastebrushtocamera"}, - {"Undo", 'Z', 0x04, ID_EDIT_UNDO, "menu_edit_undo"}, - {"Redo", 'Y', 0x04, ID_EDIT_REDO, "menu_edit_redo"}, - {"ZZoomOut", GDK_Insert, 0x04, ID_VIEW_ZZOOMOUT, "menu_view_zzoomout"}, - {"ZZoomIn", GDK_Delete, 0x04, ID_VIEW_ZZOOMIN, "menu_view_zzoomin"}, - {"TexRotateClock", GDK_Next, 0x01, ID_SELECTION_TEXTURE_ROTATECLOCK, "menu_selection_texture_rotateclock"}, - {"TexRotateCounter", GDK_Prior, 0x01, ID_SELECTION_TEXTURE_ROTATECOUNTER, "menu_selection_texture_rotatecounter"}, - {"TexScaleUp", GDK_Up, 0x04, ID_SELECTION_TEXTURE_SCALEUP, "menu_selection_texture_scaleup"}, - {"TexScaleDown", GDK_Down, 0x04, ID_SELECTION_TEXTURE_SCALEDOWN, "menu_selection_texture_scaledown"}, - {"TexShiftLeft", GDK_Left, 0x01, ID_SELECTION_TEXTURE_SHIFTLEFT, "menu_selection_texture_shiftleft"}, - {"TexShiftRight", GDK_Right, 0x01, ID_SELECTION_TEXTURE_SHIFTRIGHT, "menu_selection_texture_shiftright"}, - {"TexShiftUp", GDK_Up, 0x01, ID_SELECTION_TEXTURE_SHIFTUP, "menu_selection_texture_shiftup"}, - {"TexShiftDown", GDK_Down, 0x01, ID_SELECTION_TEXTURE_SHIFTDOWN, "menu_selection_texture_shiftdown"}, - {"GridDown", '[', 0x00, ID_GRID_PREV, "menu_grid_prev"}, - {"GridUp", ']', 0x00, ID_GRID_NEXT, "menu_grid_next"}, - {"TexScaleLeft", GDK_Left, 0x04, ID_SELECTION_TEXTURE_SCALELEFT, "menu_selection_texture_scaleleft"}, - {"TexScaleRight", GDK_Right, 0x04, ID_SELECTION_TEXTURE_SCALERIGHT, "menu_selection_texture_scaleright"}, - {"CubicClipZoomOut", ']', 0x04, ID_VIEW_CUBEOUT, "menu_view_cubeout"}, - {"CubicClipZoomIn", '[', 0x04, ID_VIEW_CUBEIN, "menu_view_cubein"}, - {"ToggleCubicClip", '\\', 0x04, ID_VIEW_CUBICCLIPPING, "menu_view_cubicclipping"}, - {"MoveSelectionDOWN", GDK_KP_Subtract, 0x00, ID_SELECTION_MOVEDOWN, "menu_selection_movedown"}, - {"MoveSelectionUP", GDK_KP_Add, 0x00, ID_SELECTION_MOVEUP, "menu_selection_moveup"}, - {"DumpSelectedBrush", 'D', 0x01, ID_SELECTION_PRINT, "menu_selection_print"}, - {"ToggleSizePaint", 'Q', 0x00, ID_SELECTION_TOGGLESIZEPAINT, "menu_selection_togglesizepaint"}, - {"SelectNudgeLeft", GDK_Left, 0x02, ID_SELECTION_SELECT_NUDGELEFT, "menu_selection_select_nudgeleft"}, - {"SelectNudgeRight", GDK_Right, 0x02, ID_SELECTION_SELECT_NUDGERIGHT, "menu_selection_select_nudgeright"}, - {"SelectNudgeUp", GDK_Up, 0x02, ID_SELECTION_SELECT_NUDGEUP, "menu_selection_select_nudgeup"}, - {"CycleCapTexturePatch", 'N', 0x05, ID_CURVE_CYCLECAP, "menu_curve_cyclecap"}, - {"NaturalizePatch", 'N', 0x04, ID_PATCH_NATURALIZE, "menu_patch_naturalize"}, - {"SnapToGrid", 'G', 0x04, ID_SELECT_SNAPTOGRID, "menu_select_snaptogrid"}, - {"ShowAllTextures", 'A', 0x04, ID_TEXTURES_SHOWALL, "menu_textures_showall"}, - {"SelectAllOfType", 'A', 0x01, ID_SELECT_ALL, "menu_select_all"}, - {"CapCurrentCurve", 'C', 0x01, ID_CURVE_CAP, "menu_curve_cap"}, - {"MakeStructural", 'S', 0x05, ID_SELECTION_MAKE_STRUCTURAL, "menu_selection_make_structural"}, - {"RegionSetSelection", 'R', 0x05, ID_REGION_SETSELECTION, "menu_region_setselection"}, - {"ShowInUse", 'U', 0, ID_TEXTURES_SHOWINUSE, "menu_textures_showinuse"}, - {"InvertSelection", 'I', 0, ID_SELECTION_INVERT, "menu_selection_invert"}, - {"Sleep", 'P', 0x05, ID_FILE_SLEEP, "menu_file_sleep"}, - {"SimplePatchMesh", 'P', 0x01, ID_CURVE_SIMPLEPATCHMESH, "menu_simplepatchmesh"}, - {"FilterWorldBrushes", '1', RAD_ALT, ID_FILTER_WORLD, "menu_filter_world"}, - {"FilterEntities", '2', RAD_ALT, ID_FILTER_ENTITIES, "menu_filter_entities"}, - {"FilterAreaportals", '3', RAD_ALT, ID_FILTER_AREAPORTALS, "menu_filter_areaportals"}, - {"FilterTranslucent", '4', RAD_ALT, ID_FILTER_TRANSLUCENT, "menu_filter_translucent"}, - {"FilterLiquids", '5', RAD_ALT, ID_FILTER_LIQUIDS, "menu_filter_liquids"}, - {"FilterCaulk", '6', RAD_ALT , ID_FILTER_CAULK, "menu_filter_caulk"}, - {"FilterClips", '7', RAD_ALT, ID_FILTER_CLIPS, "menu_filter_clips"}, - {"FilterBotClips", 'M', RAD_ALT, ID_FILTER_BOTCLIPS, "menu_filter_botclips"}, - {"FilterPaths", '8', RAD_ALT, ID_FILTER_PATHS, "menu_filter_paths"}, - {"FilterClusterportals", '9', RAD_ALT, ID_FILTER_CLUSTERPORTALS, "menu_filter_clusterportals"}, - {"FilterLights", '0', RAD_ALT, ID_FILTER_LIGHTS, "menu_filter_lights"}, - {"FilterPatches", 'P', RAD_CONTROL, ID_FILTER_PATCHES, "menu_filter_patches"}, - {"FilterDetails", 'D', RAD_CONTROL, ID_FILTER_DETAILS, "menu_filter_details"}, - {"FilterStructural", 'D', RAD_CONTROL|RAD_SHIFT, ID_FILTER_STRUCTURAL, "menu_filter_structural"}, - {"FilterHintsSkips", 'H', RAD_CONTROL, ID_FILTER_HINTSSKIPS, "menu_filter_hintsskips"}, - {"FilterModels", 'M', RAD_SHIFT, ID_FILTER_MODELS, "menu_filter_models"}, - {"FilterTriggers", 'T', RAD_CONTROL|RAD_SHIFT, ID_FILTER_TRIGGERS, "menu_filter_triggers"}, - {"LoadPointfile", 'L', RAD_SHIFT, ID_FILE_POINTFILE, "menu_load_pointfile"}, - {"TextureWindowScaledown", GDK_Insert, RAD_ALT, ID_TEXTUREWINDOW_SCALEDOWN, "menu_texturewindow_scaledown"}, - {"TextureWindowScaleup", GDK_Delete, RAD_ALT, ID_TEXTUREWINDOW_SCALEUP, "menu_texturewindow_scaleup"}, -}; - -int g_nCommandCount = sizeof(g_Commands) / sizeof(SCommandInfo); - -SKeyInfo g_Keys[] = -{ - {"Space", GDK_space}, - {"Backspace", GDK_BackSpace}, - {"Escape", GDK_Escape}, - {"End", GDK_End}, - {"Insert", GDK_Insert}, - {"Delete", GDK_Delete}, - {"PageUp", GDK_Prior}, - {"PageDown", GDK_Next}, - {"Up", GDK_Up}, - {"Down", GDK_Down}, - {"Left", GDK_Left}, - {"Right", GDK_Right}, - {"F1", GDK_F1}, - {"F2", GDK_F2}, - {"F3", GDK_F3}, - {"F4", GDK_F4}, - {"F5", GDK_F5}, - {"F6", GDK_F6}, - {"F7", GDK_F7}, - {"F8", GDK_F8}, - {"F9", GDK_F9}, - {"F10", GDK_F10}, - {"F11", GDK_F11}, - {"F12", GDK_F12}, - {"Tab", GDK_Tab}, - {"Return", GDK_Return}, - {"Comma", GDK_comma}, - {"Period", GDK_period}, - {"Plus", GDK_KP_Add}, - {"Multiply", GDK_multiply}, - {"Subtract", GDK_KP_Subtract}, - {"NumPad0", GDK_KP_0}, - {"NumPad1", GDK_KP_1}, - {"NumPad2", GDK_KP_2}, - {"NumPad3", GDK_KP_3}, - {"NumPad4", GDK_KP_4}, - {"NumPad5", GDK_KP_5}, - {"NumPad6", GDK_KP_6}, - {"NumPad7", GDK_KP_7}, - {"NumPad8", GDK_KP_8}, - {"NumPad9", GDK_KP_9}, - {"[", 219}, - {"]", 221}, - {"\\", 220}, - {"Home", GDK_Home} -}; - -int g_nKeyCount = sizeof(g_Keys) / sizeof(SKeyInfo); - -// ============================================================================= -// global functions - -void WINAPI Sys_UpdateWindows (int nBits) -{ - g_nUpdateBits |= nBits; -} - -// ============================================================================= -// Static functions - -// Gef: Separate handling for keyup events -void HandleKeyUp (GtkWidget *widget, gpointer data) -{ - int id = GPOINTER_TO_INT (data); -#ifdef DBG_KBD - Sys_Printf("HandleKeyUp: %d\n", id); -#endif - - if(g_bIgnoreCommands) - return; - - switch (id) - { - case ID_CAMERA_FORWARD: g_pParentWnd->OnCameraForward (FALSE); break; - case ID_CAMERA_BACK: g_pParentWnd->OnCameraBack (FALSE); break; - case ID_CAMERA_LEFT: g_pParentWnd->OnCameraLeft (FALSE); break; - case ID_CAMERA_RIGHT: g_pParentWnd->OnCameraRight (FALSE); break; - case ID_CAMERA_STRAFELEFT: g_pParentWnd->OnCameraStrafeleft (FALSE); break; - case ID_CAMERA_STRAFERIGHT: g_pParentWnd->OnCameraStraferight (FALSE); break; - } -} - -gint HandleCommand (GtkWidget *widget, gpointer data) -{ - int id = GPOINTER_TO_INT (data); -#ifdef DBG_KBD - Sys_Printf("HandleCommand %d\n", id); -#endif - - if ( g_bIgnoreCommands ) { -#ifdef DBG_KBD - Sys_Printf( "g_bIgnoreCommands %d, returning FALSE\n", g_bIgnoreCommands ); -#endif - return FALSE; - } - - if (id >= CMD_TEXTUREWAD && id <= CMD_TEXTUREWAD_END) g_pParentWnd->OnTextureWad (id); - else if (id >= CMD_BSPCOMMAND && id <= CMD_BSPCOMMAND_END) g_pParentWnd->OnBspCommand (id); - else if (id >= ID_FILE_RECENT1 && id <= ID_FILE_RECENT4) g_pParentWnd->OnMru (id); - else if (id >= ID_VIEW_NEAREST && id <= ID_TEXTURES_FLATSHADE) - { - if (GTK_CHECK_MENU_ITEM (widget)->active) - g_pParentWnd->OnViewNearest (id); - } else if (id >= ID_GRID_025 && id <= ID_GRID_256) g_pParentWnd->OnGrid (id); - else if (id >= ID_PLUGIN_START && id <= ID_PLUGIN_END) - { - char *str; - gtk_label_get (GTK_LABEL (GTK_BIN (widget)->child), &str); - g_pParentWnd->OnPlugIn (id, str); - } else if (id >= ID_ENTITY_START && id <= ID_ENTITY_END) - { - char *str; - gtk_label_get (GTK_LABEL (GTK_BIN (widget)->child), &str); - g_pParentWnd->ActiveXY()->OnEntityCreate (str); - } - else switch (id) - { - case ID_FILE_NEW: g_pParentWnd->OnFileNew (); break; - case ID_FILE_SLEEP: g_pParentWnd->OnSleep(); break; - case ID_FILE_OPEN: g_pParentWnd->OnFileOpen (); break; - case ID_FILE_SAVE: g_pParentWnd->OnFileSave (); break; - case ID_FILE_SAVEAS: g_pParentWnd->OnFileSaveas (); break; - case ID_FILE_EXPORTMAP: g_pParentWnd->OnFileExportmap (); break; - case ID_FILE_SAVEREGION: g_pParentWnd->OnFileSaveregion (); break; - case ID_FILE_NEWPROJECT: g_pParentWnd->OnFileNewproject (); break; - case ID_FILE_LOADPROJECT: g_pParentWnd->OnFileLoadproject (); break; - case ID_FILE_PROJECTSETTINGS: g_pParentWnd->OnFileProjectsettings (); break; - case ID_FILE_POINTFILE: g_pParentWnd->OnFilePointfile (); break; - case ID_FILE_CHECKUPDATE: g_pParentWnd->OnFileCheckUpdate (); break; - case ID_FILE_EXIT: g_pParentWnd->OnFileExit (); break; - case ID_FILE_IMPORTMAP: g_pParentWnd->OnFileImportmap (); break; - case ID_EDIT_UNDO: g_pParentWnd->OnEditUndo (); break; - case ID_EDIT_REDO: g_pParentWnd->OnEditRedo (); break; - case ID_EDIT_COPYBRUSH: g_pParentWnd->OnEditCopybrush (); break; - case ID_EDIT_PASTEBRUSH: g_pParentWnd->OnEditPastebrush (); break; - case ID_EDIT_PASTEBRUSHTOCAMERA: g_pParentWnd->OnEditPastebrushToCamera (); break; - case ID_SELECTION_DELETE: g_pParentWnd->OnSelectionDelete (); break; - case ID_EDIT_MAPINFO: g_pParentWnd->OnEditMapinfo (); break; - case ID_EDIT_ENTITYINFO: g_pParentWnd->OnEditEntityinfo (); break; - case ID_BRUSH_SCRIPTS: g_pParentWnd->OnBrushScripts (); break; - case ID_EDIT_LOADPREFAB: g_pParentWnd->OnEditLoadprefab (); break; - case ID_EDIT_SAVEPREFAB: g_pParentWnd->OnEditSaveprefab (); break; - case ID_PREFS: g_pParentWnd->OnPrefs (); break; - case ID_TOGGLECAMERA: g_pParentWnd->OnTogglecamera (); break; - case ID_TOGGLECONSOLE: g_pParentWnd->OnToggleconsole (); break; - case ID_VIEW_ENTITY: g_pParentWnd->OnViewEntity (); break; - case ID_VIEW_GROUPS: g_pParentWnd->OnViewGroups (); break; - case ID_TOGGLEVIEW: g_pParentWnd->OnToggleview (); break; - case ID_TOGGLEVIEW_YZ: g_pParentWnd->OnToggleviewYz (); break; - case ID_TOGGLEVIEW_XZ: g_pParentWnd->OnToggleviewXz (); break; - case ID_TOGGLEZ: g_pParentWnd->OnTogglez (); break; - case ID_VIEW_CENTER: g_pParentWnd->OnViewCenter (); break; - case ID_VIEW_UPFLOOR: g_pParentWnd->OnViewUpfloor (); break; - case ID_VIEW_DOWNFLOOR: g_pParentWnd->OnViewDownfloor (); break; - case ID_VIEW_CENTERVIEW: g_pParentWnd->OnViewCenterview (); break; - case ID_VIEW_NEXTVIEW: g_pParentWnd->OnViewNextview (); break; - case ID_VIEW_XY: g_pParentWnd->OnViewXy (); break; - case ID_VIEW_SIDE: g_pParentWnd->OnViewSide (); break; - case ID_VIEW_FRONT: g_pParentWnd->OnViewFront (); break; - case ID_VIEW_100: g_pParentWnd->OnView100 (); break; - case ID_VIEW_ZOOMIN: g_pParentWnd->OnViewZoomin (); break; - case ID_VIEW_ZOOMOUT: g_pParentWnd->OnViewZoomout (); break; - case ID_VIEW_Z100: g_pParentWnd->OnViewZ100 (); break; - case ID_VIEW_ZZOOMIN: g_pParentWnd->OnViewZzoomin (); break; - case ID_VIEW_ZZOOMOUT: g_pParentWnd->OnViewZzoomout (); break; - case ID_VIEW_CUBEIN: g_pParentWnd->OnViewCubein (); break; - case ID_VIEW_CUBEOUT: g_pParentWnd->OnViewCubeout (); break; - case ID_VIEW_SHOWNAMES: g_pParentWnd->OnViewShownames (); break; - case ID_VIEW_SHOWBLOCKS: g_pParentWnd->OnViewShowblocks (); break; - case ID_VIEW_SHOWCOORDINATES: g_pParentWnd->OnViewShowcoordinates (); break; - case ID_VIEW_SHOWOUTLINE: g_pParentWnd->OnViewShowOutline (); break; - case ID_VIEW_SHOWAXES: g_pParentWnd->OnViewShowAxes (); break; - case ID_VIEW_SHOWWORKZONE: g_pParentWnd->OnViewShowWorkzone (); break; - case ID_VIEW_SHOWANGLES: g_pParentWnd->OnViewShowAngles (); break; - case ID_VIEW_HIDESHOW_HIDESELECTED: g_pParentWnd->OnViewHideshowHideselected (); break; - case ID_VIEW_HIDESHOW_SHOWHIDDEN: g_pParentWnd->OnViewHideshowShowhidden (); break; - case ID_VIEW_ENTITIESAS_BOUNDINGBOX: - case ID_VIEW_ENTITIESAS_WIREFRAME: - case ID_VIEW_ENTITIESAS_SELECTEDWIREFRAME: - case ID_VIEW_ENTITIESAS_SELECTEDSKINNED: - case ID_VIEW_ENTITIESAS_SKINNED: - case ID_VIEW_ENTITIESAS_SKINNEDANDBOXED: - g_pParentWnd->OnEntitiesSetViewAs(id); - break; - case ID_VIEW_CUBICCLIPPING: g_pParentWnd->OnViewCubicclipping (); break; - case ID_VIEW_OPENGLLIGHTING: g_pParentWnd->OnViewOpengllighting (); break; - case ID_SELECTION_DRAGEDGES: g_pParentWnd->OnSelectionDragedges (); break; - case ID_SELECTION_DRAGVERTECIES: g_pParentWnd->OnSelectionDragvertecies (); break; - case ID_SELECTION_CLONE: g_pParentWnd->OnSelectionClone (); break; - case ID_SELECTION_DESELECT: g_pParentWnd->OnSelectionDeselect (); break; - case ID_BRUSH_FLIPX: g_pParentWnd->OnBrushFlipx (); break; - case ID_BRUSH_FLIPY: g_pParentWnd->OnBrushFlipy (); break; - case ID_BRUSH_FLIPZ: g_pParentWnd->OnBrushFlipz (); break; - case ID_BRUSH_ROTATEX: g_pParentWnd->OnBrushRotatex (); break; - case ID_BRUSH_ROTATEY: g_pParentWnd->OnBrushRotatey (); break; - case ID_BRUSH_ROTATEZ: g_pParentWnd->OnBrushRotatez (); break; - case ID_SELECTION_ARBITRARYROTATION: g_pParentWnd->OnSelectionArbitraryrotation (); break; - case ID_SELECT_SCALE: g_pParentWnd->OnSelectScale (); break; - case ID_SELECTION_MAKEHOLLOW: g_pParentWnd->OnSelectionMakehollow (); break; - case ID_SELECTION_CSGSUBTRACT: g_pParentWnd->OnSelectionCsgsubtract (); break; - case ID_SELECTION_CSGMERGE: g_pParentWnd->OnSelectionCsgmerge (); break; - case ID_SELECTION_NOOUTLINE: g_pParentWnd->OnSelectionNoOutline (); break; - case ID_SELECTION_OUTLINESTYLE: g_pParentWnd->OnSelectionOutlineStyle (); break; - case ID_SELECTION_SELECTCOMPLETETALL: g_pParentWnd->OnSelectionSelectcompletetall (); break; - case ID_SELECTION_SELECTTOUCHING: g_pParentWnd->OnSelectionSelecttouching (); break; - case ID_SELECTION_SELECTPARTIALTALL: g_pParentWnd->OnSelectionSelectpartialtall (); break; - case ID_SELECTION_SELECTINSIDE: g_pParentWnd->OnSelectionSelectinside (); break; - case ID_SELECTION_SELECT_NUDGELEFT: g_pParentWnd->OnSelectionSelectNudgeleft (); break; - case ID_SELECTION_SELECT_NUDGERIGHT: g_pParentWnd->OnSelectionSelectNudgeright (); break; - case ID_SELECTION_SELECT_NUDGEUP: g_pParentWnd->OnSelectionSelectNudgeup (); break; - case ID_SELECTION_SELECT_NUDGEDOWN: g_pParentWnd->OnSelectionSelectNudgedown (); break; - case ID_VIEW_CLIPPER: g_pParentWnd->OnViewClipper (); break; - case ID_CLIP_SELECTED: g_pParentWnd->OnClipSelected (); break; - case ID_SPLIT_SELECTED: g_pParentWnd->OnSplitSelected (); break; - case ID_FLIP_CLIP: g_pParentWnd->OnFlipClip (); break; - case ID_SELECTION_CONNECT: g_pParentWnd->OnSelectionConnect (); break; - case ID_SELECTION_UNGROUPENTITY: g_pParentWnd->OnSelectionUngroupentity (); break; - case ID_SELECTION_MERGE: Select_MergeEntity(); break; - case ID_SELECTION_SEPERATE: Select_Seperate(); break; - case ID_SELECTION_MAKE_DETAIL: g_pParentWnd->OnSelectionMakeDetail (); break; - case ID_SELECTION_MAKE_STRUCTURAL: g_pParentWnd->OnSelectionMakeStructural (); break; - case ID_SNAPTOGRID: g_pParentWnd->OnSnaptogrid (); break; - case ID_TEXTURES_SHOWINUSE: g_pParentWnd->OnTexturesShowinuse (); break; - case ID_TEXTURES_SHOWALL: g_pParentWnd->OnTexturesShowall (); break; - case ID_TEXTURES_INSPECTOR: g_pParentWnd->OnTexturesInspector (); break; - case ID_TEXTURE_REPLACEALL: g_pParentWnd->OnTextureReplaceall (); break; - case ID_TOGGLE_LOCK: g_pParentWnd->OnToggleLock (); break; - case ID_TOGGLE_ROTATELOCK: g_pParentWnd->OnToggleRotatelock (); break; - case ID_TEXTURES_LOAD: g_pParentWnd->OnTexturesLoad (); break; - case ID_TEXTURES_RELOADSHADERS: g_pParentWnd->OnTexturesReloadshaders (); break; - case ID_TEXTURES_SHADERS_SHOW: g_pParentWnd->OnTexturesShadersShow (); break; - case ID_TEXTURES_TEXTUREWINDOWSCALE_200: - case ID_TEXTURES_TEXTUREWINDOWSCALE_100: - case ID_TEXTURES_TEXTUREWINDOWSCALE_50: - case ID_TEXTURES_TEXTUREWINDOWSCALE_25: - case ID_TEXTURES_TEXTUREWINDOWSCALE_10: - g_pParentWnd->SetTextureScale (id); - break; - case ID_TEXTURES_LOADLIST: g_pParentWnd->OnTexturesLoadlist (); break; - case ID_TEXTURES_SHADERLISTONLY: g_pParentWnd->OnTexturesShaderlistonly (); break; - case ID_TEXTUREWINDOW_SCALEUP: g_pParentWnd->OnTexturewindowScaleup (); break; - case ID_TEXTUREWINDOW_SCALEDOWN: g_pParentWnd->OnTexturewindowScaledown (); break; - case ID_MISC_BENCHMARK: g_pParentWnd->OnMiscBenchmark (); break; - case ID_COLOR_SETORIGINAL: g_pParentWnd->OnColorSetoriginal (); break; - case ID_COLOR_SETQER: g_pParentWnd->OnColorSetqer (); break; - case ID_COLOR_SETBLACK: g_pParentWnd->OnColorSetblack (); break; - case ID_COLOR_SETYDNAR: g_pParentWnd->OnColorSetydnar (); break; /* ydnar */ - case ID_TEXTUREBK: g_pParentWnd->OnTexturebk (); break; - case ID_COLORS_XYBK: g_pParentWnd->OnColorsXybk (); break; - case ID_COLORS_MAJOR: g_pParentWnd->OnColorsMajor (); break; - case ID_COLORS_MINOR: g_pParentWnd->OnColorsMinor (); break; - case ID_COLORS_GRIDTEXT: g_pParentWnd->OnColorsGridtext (); break; - case ID_COLORS_GRIDBLOCK: g_pParentWnd->OnColorsGridblock (); break; - case ID_COLORS_CAMERABACK: g_pParentWnd->OnColorsCameraBack (); break; - case ID_COLORS_BRUSH: g_pParentWnd->OnColorsBrush (); break; - case ID_COLORS_SELECTEDBRUSH: g_pParentWnd->OnColorsSelectedbrush (); break; - case ID_COLORS_SELECTEDBRUSH3D: g_pParentWnd->OnColorsSelectedbrush3D (); break; - case ID_COLORS_CLIPPER: g_pParentWnd->OnColorsClipper (); break; - case ID_COLORS_VIEWNAME: g_pParentWnd->OnColorsViewname (); break; - case ID_MISC_GAMMA: g_pParentWnd->OnMiscGamma (); break; - case ID_MISC_FINDBRUSH: g_pParentWnd->OnMiscFindbrush (); break; - case ID_MISC_NEXTLEAKSPOT: g_pParentWnd->OnMiscNextleakspot (); break; - case ID_MISC_PREVIOUSLEAKSPOT: g_pParentWnd->OnMiscPreviousleakspot (); break; - case ID_MISC_PRINTXY: g_pParentWnd->OnMiscPrintxy (); break; - case ID_MISC_SELECTENTITYCOLOR: g_pParentWnd->OnMiscSelectentitycolor (); break; - case ID_CONVERTCURVES: g_pParentWnd->OnConvertcurves (); break; - case ID_REGION_OFF: g_pParentWnd->OnRegionOff (); break; - case ID_REGION_SETXY: g_pParentWnd->OnRegionSetxy (); break; - case ID_REGION_SETTALLBRUSH: g_pParentWnd->OnRegionSettallbrush (); break; - case ID_REGION_SETBRUSH: g_pParentWnd->OnRegionSetbrush (); break; - case ID_REGION_SETSELECTION: g_pParentWnd->OnRegionSetselection (); break; - case ID_BRUSH_3SIDED: g_pParentWnd->OnBrush3sided (); break; - case ID_BRUSH_4SIDED: g_pParentWnd->OnBrush4sided (); break; - case ID_BRUSH_5SIDED: g_pParentWnd->OnBrush5sided (); break; - case ID_BRUSH_6SIDED: g_pParentWnd->OnBrush6sided (); break; - case ID_BRUSH_7SIDED: g_pParentWnd->OnBrush7sided (); break; - case ID_BRUSH_8SIDED: g_pParentWnd->OnBrush8sided (); break; - case ID_BRUSH_9SIDED: g_pParentWnd->OnBrush9sided (); break; - case ID_BRUSH_ARBITRARYSIDED: g_pParentWnd->OnBrushArbitrarysided (); break; - case ID_BRUSH_MAKECONE: g_pParentWnd->OnBrushMakecone (); break; - case ID_BRUSH_PRIMITIVES_SPHERE: g_pParentWnd->OnBrushPrimitivesSphere (); break; - case ID_CURVE_PATCHTUBE: g_pParentWnd->OnCurvePatchtube (); break; - case ID_CURVE_PATCHDENSETUBE: g_pParentWnd->OnCurvePatchdensetube (); break; - case ID_CURVE_PATCHVERYDENSETUBE: g_pParentWnd->OnCurvePatchverydensetube (); break; - case ID_CURVE_PATCHSQUARE: g_pParentWnd->OnCurvePatchsquare (); break; - case ID_CURVE_PATCHENDCAP: g_pParentWnd->OnCurvePatchendcap (); break; - case ID_CURVE_PATCHBEVEL: g_pParentWnd->OnCurvePatchbevel (); break; - case ID_CURVE_MOREENDCAPSBEVELS_SQUAREBEVEL: g_pParentWnd->OnCurveMoreendcapsbevelsSquarebevel (); break; - case ID_CURVE_MOREENDCAPSBEVELS_SQUAREENDCAP: g_pParentWnd->OnCurveMoreendcapsbevelsSquareendcap();break; - case ID_CURVE_PATCHCONE: g_pParentWnd->OnCurvePatchcone (); break; - case ID_CURVE_SIMPLEPATCHMESH: g_pParentWnd->OnCurveSimplepatchmesh (); break; - case ID_CURVE_INSERT_INSERTCOLUMN: g_pParentWnd->OnCurveInsertInsertcolumn (); break; - case ID_CURVE_INSERT_ADDCOLUMN: g_pParentWnd->OnCurveInsertAddcolumn (); break; - case ID_CURVE_INSERT_INSERTROW: g_pParentWnd->OnCurveInsertInsertrow (); break; - case ID_CURVE_INSERT_ADDROW: g_pParentWnd->OnCurveInsertAddrow (); break; - case ID_CURVE_DELETE_FIRSTCOLUMN: g_pParentWnd->OnCurveDeleteFirstcolumn (); break; - case ID_CURVE_DELETE_LASTCOLUMN: g_pParentWnd->OnCurveDeleteLastcolumn (); break; - case ID_CURVE_DELETE_FIRSTROW: g_pParentWnd->OnCurveDeleteFirstrow (); break; - case ID_CURVE_DELETE_LASTROW: g_pParentWnd->OnCurveDeleteLastrow (); break; - case ID_CURVE_NEGATIVE: g_pParentWnd->OnCurveNegative (); break; - case ID_CURVE_REDISPERSE_ROWS: g_pParentWnd->OnCurveRedisperseRows (); break; - case ID_CURVE_REDISPERSE_INTERMEDIATE_COLS: g_pParentWnd->OnCurveRedisperseIntermediateCols (); break; - case ID_CURVE_REDISPERSE_INTERMEDIATE_ROWS: g_pParentWnd->OnCurveRedisperseIntermediateRows (); break; - case ID_CURVE_MATRIX_TRANSPOSE: g_pParentWnd->OnCurveMatrixTranspose (); break; - case ID_CURVE_CAP: g_pParentWnd->OnCurveCap (); break; - case ID_CURVE_CYCLECAP: g_pParentWnd->OnCurveCyclecap (); break; - case ID_CURVE_OVERLAY_SET: g_pParentWnd->OnCurveOverlaySet (); break; - case ID_CURVE_OVERLAY_CLEAR: g_pParentWnd->OnCurveOverlayClear (); break; - case ID_CURVE_THICKEN: g_pParentWnd->OnCurveThicken (); break; - case ID_PLUGINS_REFRESH: g_pParentWnd->OnPluginsRefresh (); break; - case ID_HELP: g_pParentWnd->OnHelp (); break; - case ID_HELP_LINKS: g_pParentWnd->OnHelpLinks(); break; - case ID_HELP_BUGREPORT: g_pParentWnd->OnHelpBugreport(); break; - case ID_HELP_COMMANDLIST: g_pParentWnd->OnHelpCommandlist (); break; - case ID_HELP_ABOUT: g_pParentWnd->OnHelpAbout (); break; - case ID_DONTSELECTMODEL: g_pParentWnd->OnDontselectmodel (); break; - case ID_FILTER_AREAPORTALS: g_pParentWnd->OnFilterAreaportals (); break; - case ID_FILTER_CAULK: g_pParentWnd->OnFilterCaulk (); break; - case ID_FILTER_STRUCTURAL: g_pParentWnd->OnFilterStructural (); break; - case ID_FILTER_CLIPS: g_pParentWnd->OnFilterClips (); break; - case ID_FILTER_BOTCLIPS: g_pParentWnd->OnFilterBotClips (); break; - case ID_FILTER_DETAILS: g_pParentWnd->OnFilterDetails (); break; - case ID_FILTER_ENTITIES: g_pParentWnd->OnFilterEntities (); break; - case ID_FILTER_HINTSSKIPS: g_pParentWnd->OnFilterHintsskips (); break; - case ID_FILTER_LIGHTS: g_pParentWnd->OnFilterLights (); break; - case ID_FILTER_LIQUIDS: g_pParentWnd->OnFilterLiquids (); break; - case ID_FILTER_MODELS: g_pParentWnd->OnFilterModels (); break; - case ID_FILTER_PATCHES: g_pParentWnd->OnFilterPatches (); break; - case ID_FILTER_TRANSLUCENT: g_pParentWnd->OnFilterTranslucent (); break; - case ID_FILTER_TRIGGERS: g_pParentWnd->OnFilterTriggers (); break; - case ID_FILTER_WORLD: g_pParentWnd->OnFilterWorld (); break; - case ID_FILTER_PATHS: g_pParentWnd->OnFilterPaths (); break; - case ID_FILTER_CLUSTERPORTALS: g_pParentWnd->OnFilterClusterportals (); break; - case ID_FILTER_LIGHTGRID: g_pParentWnd->OnFilterLightgrid (); break; - - case ID_POPUP_SELECTION: g_pParentWnd->OnPopupSelection (); break; - case ID_VIEW_CHANGE: g_pParentWnd->OnViewChange (); break; - case ID_TEXTURES_POPUP: g_pParentWnd->OnTexturesPopup (); break; - case ID_VIEW_CAMERATOGGLE: g_pParentWnd->ToggleCamera (); break; - case ID_VIEW_CAMERAUPDATE: g_pParentWnd->OnViewCameraupdate (); break; - case ID_SELECT_MOUSEROTATE: g_pParentWnd->OnSelectMouserotate (); break; - case ID_SELECT_MOUSESCALE: g_pParentWnd->OnSelectMousescale (); break; - case ID_SCALELOCKX: g_pParentWnd->OnScalelockx (); break; - case ID_SCALELOCKY: g_pParentWnd->OnScalelocky (); break; - case ID_SCALELOCKZ: g_pParentWnd->OnScalelockz (); break; - case ID_DONTSELECTCURVE: g_pParentWnd->OnDontselectcurve (); break; - case ID_PATCH_SHOWBOUNDINGBOX: g_pParentWnd->OnPatchToggleBox (); break; - case ID_PATCH_WIREFRAME: g_pParentWnd->OnPatchWireframe (); break; - case ID_PATCH_BEND: g_pParentWnd->OnPatchBend (); break; - case ID_PATCH_WELD: g_pParentWnd->OnPatchWeld (); break; - case ID_PATCH_DRILLDOWN: g_pParentWnd->OnPatchDrilldown (); break; - case ID_DROP_GROUP_NAME: g_pParentWnd->OnDropGroupName (); break; - case ID_DROP_GROUP_NEWGROUP: g_pParentWnd->OnDropGroupNewgroup (); break; - case ID_DROP_GROUP_REMOVE: g_pParentWnd->OnDropGroupRemove (); break; - case ID_SHOW_ENTITIES: g_pParentWnd->OnShowEntities (); break; - - case IDC_BTN_FACEFIT: g_pParentWnd->OnFaceFit (); break; - case ID_VIEW_TEXTURE: g_pParentWnd->OnViewTexture (); break; - case ID_PATCH_INSPECTOR: g_pParentWnd->OnPatchInspector (); break; - case ID_CURVE_NEGATIVETEXTUREX: g_pParentWnd->OnCurveNegativeTextureX (); break; - case ID_CURVE_NEGATIVETEXTUREY: g_pParentWnd->OnCurveNegativeTextureY (); break; - case ID_CURVE_INSERTCOLUMN: g_pParentWnd->OnCurveInsertcolumn (); break; - case ID_CURVE_INSERTROW: g_pParentWnd->OnCurveInsertrow (); break; - case ID_CURVE_DELETECOLUMN: g_pParentWnd->OnCurveDeletecolumn (); break; - case ID_CURVE_DELETEROW: g_pParentWnd->OnCurveDeleterow (); break; - case ID_PATCH_TAB: g_pParentWnd->OnPatchTab (); break; - case ID_CAMERA_FORWARD: g_pParentWnd->OnCameraForward (TRUE); break; - case ID_CAMERA_BACK: g_pParentWnd->OnCameraBack (TRUE); break; - case ID_CAMERA_LEFT: g_pParentWnd->OnCameraLeft (TRUE); break; - case ID_CAMERA_RIGHT: g_pParentWnd->OnCameraRight (TRUE); break; - case ID_CAMERA_UP: g_pParentWnd->OnCameraUp (); break; - case ID_CAMERA_DOWN: g_pParentWnd->OnCameraDown (); break; - case ID_CAMERA_ANGLEUP: g_pParentWnd->OnCameraAngleup (); break; - case ID_CAMERA_ANGLEDOWN: g_pParentWnd->OnCameraAngledown (); break; - case ID_CAMERA_STRAFELEFT: g_pParentWnd->OnCameraStrafeleft (TRUE); break; - case ID_CAMERA_STRAFERIGHT: g_pParentWnd->OnCameraStraferight (TRUE); break; - case ID_GRID_TOGGLE: g_pParentWnd->OnGridToggle (); break; - case ID_VIEW_CONSOLE: g_pParentWnd->OnViewConsole (); break; - case ID_VIEW_CROSSHAIR: g_pParentWnd->OnViewCrosshair (); break; - case ID_SELECTION_TEXTURE_FIT: g_pParentWnd->OnSelectionTextureFit (); break; - case ID_SELECTION_TEXTURE_ROTATECLOCK: g_pParentWnd->OnSelectionTextureRotateclock (); break; - case ID_SELECTION_TEXTURE_ROTATECOUNTER: g_pParentWnd->OnSelectionTextureRotatecounter (); break; - case ID_SELECTION_TEXTURE_SCALEUP: g_pParentWnd->OnSelectionTextureScaleup (); break; - case ID_SELECTION_TEXTURE_SCALEDOWN: g_pParentWnd->OnSelectionTextureScaledown (); break; - case ID_SELECTION_TEXTURE_SHIFTLEFT: g_pParentWnd->OnSelectionTextureShiftleft (); break; - case ID_SELECTION_TEXTURE_SHIFTRIGHT: g_pParentWnd->OnSelectionTextureShiftright (); break; - case ID_SELECTION_TEXTURE_SHIFTUP: g_pParentWnd->OnSelectionTextureShiftup (); break; - case ID_SELECTION_TEXTURE_SHIFTDOWN: g_pParentWnd->OnSelectionTextureShiftdown (); break; - case ID_GRID_PREV: g_pParentWnd->OnGridPrev (); break; - case ID_GRID_NEXT: g_pParentWnd->OnGridNext (); break; - case ID_SELECTION_TEXTURE_SCALELEFT: g_pParentWnd->OnSelectionTextureScaleLeft (); break; - case ID_SELECTION_TEXTURE_SCALERIGHT: g_pParentWnd->OnSelectionTextureScaleRight (); break; - case ID_SELECTION_MOVEDOWN: g_pParentWnd->OnSelectionMovedown (); break; - case ID_SELECTION_MOVEUP: g_pParentWnd->OnSelectionMoveup (); break; - case ID_SELECTION_PRINT: g_pParentWnd->OnSelectionPrint (); break; - case ID_SELECTION_TOGGLESIZEPAINT: g_pParentWnd->OnSelectionTogglesizepaint (); break; - case ID_PATCH_NATURALIZE: g_pParentWnd->OnPatchNaturalize (); break; - case ID_SELECT_SNAPTOGRID: g_pParentWnd->OnSnapToGrid (); break; - case ID_SELECT_ALL: g_pParentWnd->OnSelectAll (); break; - case ID_SELECTION_INVERT: g_pParentWnd->OnSelectionInvert (); break; - } - - return TRUE; -} - -static gint timer (gpointer data) -{ - MainFrame *wnd = (MainFrame*)data; - wnd->OnTimer (); - return TRUE; -} - -static gint mainframe_delete (GtkWidget *widget, GdkEvent *event, gpointer data) -{ - MainFrame *wnd = (MainFrame*)data; - - wnd->OnDelete(); - - if (ConfirmModified()) - return FALSE; - - g_qeglobals_gui.d_edit = NULL; - - return TRUE; -} - -static void mainframe_destroy (GtkWidget *widget, gpointer data) -{ - MainFrame *wnd = (MainFrame*)data; - - // avoid saving prefs when the app is minimized - if (g_pParentWnd->IsSleeping()) - { - Sys_Printf("Shutdown while sleeping, not saving prefs\n"); - g_qeglobals.disable_ini = true; - } - - // NOTE TTimo this is very clumsy, in MainFrame::OnDestroy we might call SavePrefs again - // we will do more stuff in OnDestroy for window position saving too, so I guess this call is still relevant? - g_PrefsDlg.SavePrefs (); - - wnd->OnDestroy (); - - // shutdown modules - // NOTE: I've decided to do this before SavePrefs in case we broadcast some shutdown info - // and modules / plugins decide to save some stuff - g_pParentWnd->GetPlugInMgr().Shutdown(); - - delete wnd; - - QGL_Shutdown(); - g_PrefsDlg.Destroy (); - g_dlgSurface.Destroy (); - g_dlgFind.Destroy (); - g_PatchDialog.Destroy (); - - gtk_main_quit (); -} - -static gint mainframe_keypress (GtkWidget* widget, GdkEventKey* event, gpointer data) -{ - unsigned int code = gdk_keyval_to_upper(event->keyval); - - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=924 - if(code == GDK_ISO_Left_Tab) { - code = GDK_Tab; - } - -#ifdef DBG_KBD - Sys_Printf("key: %d (keyval: %d) (ctrl: %d)\n", code, event->keyval, event->state & GDK_CONTROL_MASK); -#endif - - // BUG: http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=865 - // return only if Texture Viewport is in main window, otherwise if Tex viewport is in it's own window - // the Filter GtkEntry won't release focus - if ( g_pParentWnd->GetTexWnd()->m_pFilter == gtk_window_get_focus(GTK_WINDOW(widget)) ) - if ( gtk_widget_is_focus( g_pParentWnd->GetTexWnd()->m_pFilter ) ) - return FALSE; - -#ifdef DBG_KBD - Sys_Printf("mainframe_keypress processing into a command\n"); -#endif - for (int i = 0; i < g_nCommandCount; i++) - { - if (g_Commands[i].m_nKey == code) // find a match? - { - // check modifiers - unsigned int nState = 0; - if (Sys_AltDown ()) - nState |= RAD_ALT; - if ((event->state & GDK_CONTROL_MASK) != 0) - nState |= RAD_CONTROL; - if ((event->state & GDK_SHIFT_MASK) != 0) - nState |= RAD_SHIFT; - if ((g_Commands[i].m_nModifiers & 0x7) == nState) - { - HandleCommand (NULL, GINT_TO_POINTER (g_Commands[i].m_nCommand)); - gtk_signal_emit_stop_by_name (GTK_OBJECT(widget), "key_press_event"); - return FALSE; - } - } - } - - return TRUE; -} - -static gint mainframe_keyrelease (GtkWidget* widget, GdkEventKey* event, gpointer data) -{ - unsigned int code = gdk_keyval_to_upper(event->keyval); - - if (gtk_accelerator_valid (event->keyval, (GdkModifierType)0)) - return TRUE; - - for (int i = 0; i < g_nCommandCount; i++) - { - if (g_Commands[i].m_nKey == code) // find a match? - { - if(!g_Commands[i].m_nModifiers) - { - // Gef: Only call the handler if it's a key that needs keyup events - switch (g_Commands[i].m_nCommand) - { - case ID_CAMERA_FORWARD: - case ID_CAMERA_BACK: - case ID_CAMERA_LEFT: - case ID_CAMERA_RIGHT: - case ID_CAMERA_STRAFELEFT: - case ID_CAMERA_STRAFERIGHT: - { - HandleKeyUp (NULL, GINT_TO_POINTER (g_Commands[i].m_nCommand)); - gtk_signal_emit_stop_by_name (GTK_OBJECT(widget), "key_release_event"); - } - - } - return FALSE; - } - } - } - - return TRUE; -} - - -// ============================================================================= -// Window creation functions - -void AddMenuItem (GtkWidget* item, unsigned int id) -{ - for (int i = 0; i < g_nCommandCount; i++) - if (g_Commands[i].m_nCommand == id) - { - g_object_set_data (G_OBJECT (g_pParentWnd->m_pWidget), g_Commands[i].m_strMenu, item); - break; - } -} - -void MainFrame::handle_help_command(int id) -{ - OpenURL(mHelpURLs[id]->GetBuffer()); -} - -/*! -needed for hooking in Gtk+ -*/ -void HandleHelpCommand (GtkWidget *widget, gpointer data) -{ - int id = GPOINTER_TO_INT (data); - g_pParentWnd->handle_help_command(id); -} - -void MainFrame::process_xlink (Str &FileName, char *menu_name, const char *base_url, GtkWidget *menu, GtkAccelGroup *accel) -{ - xmlDocPtr pDoc; - pDoc = xmlParseFile(FileName.GetBuffer()); - if (pDoc) - { - Sys_Printf("Processing .xlink file '%s'\n", FileName.GetBuffer()); - // create sub menu - GtkWidget* menu_in_menu = create_menu_in_menu_with_mnemonic(menu, menu_name); - // start walking the nodes, find the 'links' one - xmlNodePtr pNode = pDoc->children; - while (pNode && strcmp((const char*)pNode->name, "links")) - pNode=pNode->next; - if (pNode) - { - pNode = pNode->children; - while(pNode) - { - if (!strcmp((const char*)pNode->name, "item")) - { - // process the URL - Str *url; - if (strstr((char *)xmlGetProp(pNode, (xmlChar *)"url"), "http://")) - { - // complete URL - url = new Str; - *url = (char *)xmlGetProp(pNode, (xmlChar *)"url"); - } - else - { - // relative URL - url = new Str; - *url = base_url; - *url += (char *)xmlGetProp(pNode, (xmlChar *)"url"); - } - mHelpURLs.push_back(url); - create_menu_item_with_mnemonic (menu_in_menu, (char *)xmlGetProp(pNode, (xmlChar *)"name"), GTK_SIGNAL_FUNC(HandleHelpCommand), mHelpURLs.size()-1); - } - pNode=pNode->next; - } - } - xmlFreeDoc(pDoc); - } - else - { - Sys_Printf("'%s' not found / parse failed\n", FileName.GetBuffer()); - } -} - -void MainFrame::create_game_help_menu (GtkWidget *menu, GtkAccelGroup *accel) -{ - Str FileName; - list::iterator iGame; - - // start in the global dir - FileName = g_strAppPath; - FileName += "global.xlink"; - process_xlink(FileName, "General", g_strAppPath.GetBuffer(), menu, accel); - - for (iGame = g_PrefsDlg.mGamesDialog.mGames.begin(); iGame != g_PrefsDlg.mGamesDialog.mGames.end(); iGame++) - { - FileName = (*iGame)->mGameToolsPath; - FileName += "game.xlink"; - process_xlink(FileName, (*iGame)->mGameName, (*iGame)->mGameToolsPath.GetBuffer(), menu, accel); - } -} - -void MainFrame::create_main_menu (GtkWidget *window, GtkWidget *vbox) -{ - GtkWidget *handle_box, *menu_bar, *menu, *menu_in_menu, *menu_3, *item; - GtkAccelGroup *accel; - - g_bIgnoreCommands++; - accel = gtk_accel_group_new (); - global_accel = accel; - gtk_window_add_accel_group (GTK_WINDOW (window), accel); - - handle_box = gtk_handle_box_new (); - gtk_box_pack_start (GTK_BOX (vbox), handle_box, FALSE, FALSE, 0); - gtk_widget_show (handle_box); - - menu_bar = gtk_menu_bar_new (); - gtk_container_add (GTK_CONTAINER (handle_box), menu_bar); - gtk_widget_show (menu_bar); - - // File menu - menu = create_sub_menu_with_mnemonic (menu_bar, "_File"); - if (g_PrefsDlg.m_bDetachableMenus) - menu_tearoff (menu); - - create_menu_item_with_mnemonic (menu, "_New Map", - GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_NEW); - menu_separator (menu); - - //++timo temporary experimental stuff for sleep mode.. - item = create_menu_item_with_mnemonic (menu, "_Sleep", - GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_SLEEP); - g_object_set_data (G_OBJECT (window), "menu_file_sleep", item ); - menu_separator (menu); - // end experimental - - item = create_menu_item_with_mnemonic (menu, "_Open...", - GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_OPEN); - g_object_set_data (G_OBJECT (window), "menu_file_open", item); - create_menu_item_with_mnemonic (menu, "_Import...", // Hydra: give it it's proper name - GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_IMPORTMAP); - item = create_menu_item_with_mnemonic (menu, "_Save", - GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_SAVE); - g_object_set_data (G_OBJECT (window), "menu_file_save", item); - create_menu_item_with_mnemonic (menu, "Save _as...", - GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_SAVEAS); - create_menu_item_with_mnemonic (menu, "Save s_elected...", - GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_EXPORTMAP); - menu_separator (menu); - item = create_menu_item_with_mnemonic (menu, "Save re_gion...", - GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_SAVEREGION); - g_object_set_data (G_OBJECT (window), "menu_file_saveregion", item); - menu_separator (menu); - create_menu_item_with_mnemonic (menu, "New p_roject...", - GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_NEWPROJECT); - create_menu_item_with_mnemonic (menu, "Load _project...", - GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_LOADPROJECT); - create_menu_item_with_mnemonic (menu, "Pro_ject settings...", - GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_PROJECTSETTINGS); - menu_separator (menu); - create_menu_item_with_mnemonic (menu, "_Pointfile...", - GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_POINTFILE); - menu_separator (menu); - item = create_menu_item_with_mnemonic (menu, "Recent Files", - GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_RECENT1); - g_object_set_data (G_OBJECT (item), "accel", accel); - gtk_widget_set_sensitive (item, FALSE); - MRU_AddWidget (item, 0); - item = create_menu_item_with_mnemonic (menu, "2", - GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_RECENT2); - gtk_widget_hide (item); - MRU_AddWidget (item, 1); - item = create_menu_item_with_mnemonic (menu, "3", - GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_RECENT3); - gtk_widget_hide (item); - MRU_AddWidget (item, 2); - item = create_menu_item_with_mnemonic (menu, "4", - GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_RECENT4); - gtk_widget_hide (item); - MRU_AddWidget (item, 3); - menu_separator (menu); - create_menu_item_with_mnemonic (menu, "Check for GtkRadiant update (web)", - GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_CHECKUPDATE); - - create_menu_item_with_mnemonic (menu, "E_xit", - GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_EXIT); - - // Edit menu - menu = create_sub_menu_with_mnemonic (menu_bar, "_Edit"); - if (g_PrefsDlg.m_bDetachableMenus) - menu_tearoff (menu); - item = create_menu_item_with_mnemonic (menu, "_Undo", - GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_UNDO); - g_object_set_data (G_OBJECT (window), "menu_edit_undo", item); - item = create_menu_item_with_mnemonic (menu, "_Redo", - GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_REDO); - g_object_set_data (G_OBJECT (window), "menu_edit_redo", item); - menu_separator (menu); - item = create_menu_item_with_mnemonic (menu, "_Copy", GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_COPYBRUSH); - item = create_menu_item_with_mnemonic (menu, "_Paste", GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_PASTEBRUSH); - item = create_menu_item_with_mnemonic (menu, "P_aste To Camera", GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_PASTEBRUSHTOCAMERA); - item = create_menu_item_with_mnemonic (menu, "_Delete", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_DELETE); - g_object_set_data (G_OBJECT (window), "menu_selection_delete", item); - menu_separator (menu); - create_menu_item_with_mnemonic (menu, "Map Info...", GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_MAPINFO); - create_menu_item_with_mnemonic (menu, "Entity Info...", GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_ENTITYINFO); - menu_separator (menu); - create_menu_item_with_mnemonic (menu, "Brush Scripts...", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_SCRIPTS); - menu_separator (menu); - create_menu_item_with_mnemonic (menu, "Load Pre_fab...", GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_LOADPREFAB); - create_menu_item_with_mnemonic (menu, "Save Selection as Prefab...", GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_SAVEPREFAB); - menu_separator (menu); - create_menu_item_with_mnemonic (menu, "Preferences...", GTK_SIGNAL_FUNC (HandleCommand), ID_PREFS); - - // View menu - menu = create_sub_menu_with_mnemonic (menu_bar, "_View"); - if (g_PrefsDlg.m_bDetachableMenus) - menu_tearoff (menu); - - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Toggle"); - create_menu_item_with_mnemonic (menu_in_menu, "Camera View", GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLECAMERA); - create_menu_item_with_mnemonic (menu_in_menu, "Console View", GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLECONSOLE); - item = create_menu_item_with_mnemonic (menu_in_menu, "Entity View", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ENTITY); - g_object_set_data (G_OBJECT (window), "menu_view_entity", item); - // create_menu_item_with_mnemonic (menu_in_menu, "Groups View", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_GROUPS); - create_menu_item_with_mnemonic (menu_in_menu, "XY (Top)", GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLEVIEW); - create_menu_item_with_mnemonic (menu_in_menu, "YZ (Side)", GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLEVIEW_YZ); - create_menu_item_with_mnemonic (menu_in_menu, "XZ (Front)", GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLEVIEW_XZ); - create_menu_item_with_mnemonic (menu_in_menu, "Z View", GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLEZ); - menu_separator (menu); - item = create_menu_item_with_mnemonic (menu, "_Center", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CENTER); - item = create_menu_item_with_mnemonic (menu, "_Center 2d", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CENTERVIEW); - item = create_menu_item_with_mnemonic (menu, "_Up Floor", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_UPFLOOR); - item = create_menu_item_with_mnemonic (menu, "_Down Floor", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_DOWNFLOOR); - menu_separator (menu); - item = create_menu_item_with_mnemonic (menu, "_Next (XY, YZ, XY)", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_NEXTVIEW); - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Layout"); - create_menu_item_with_mnemonic (menu_in_menu, "XY (Top)", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_XY); - create_menu_item_with_mnemonic (menu_in_menu, "YZ", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SIDE); - create_menu_item_with_mnemonic (menu_in_menu, "XZ", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_FRONT); - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Zoom"); - create_menu_item_with_mnemonic (menu_in_menu, "_XY 100%", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_100); - item = create_menu_item_with_mnemonic (menu_in_menu, "XY Zoom _In", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ZOOMIN); - item = create_menu_item_with_mnemonic (menu_in_menu, "XY Zoom _Out", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ZOOMOUT); - menu_separator (menu_in_menu); - create_menu_item_with_mnemonic (menu_in_menu, "_Z 100%", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_Z100); - item = create_menu_item_with_mnemonic (menu_in_menu, "Z Zoo_m In", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ZZOOMIN); - g_object_set_data (G_OBJECT (window), "menu_view_zzoomin", item); - item = create_menu_item_with_mnemonic (menu_in_menu, "Z Zoom O_ut", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ZZOOMOUT); - g_object_set_data (G_OBJECT (window), "menu_view_zzoomout", item); - menu_separator (menu_in_menu); - item = create_menu_item_with_mnemonic (menu_in_menu, "Cubic Clip Zoom In", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CUBEIN); - item = create_menu_item_with_mnemonic (menu_in_menu, "Cubic Clip Zoom Out", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CUBEOUT); - menu_separator (menu); - - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Show"); - item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show _Angles", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SHOWANGLES, FALSE); - g_object_set_data (G_OBJECT (window), "menu_view_showangles", item); - item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show _Names", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SHOWNAMES, TRUE); - g_object_set_data (G_OBJECT (window), "menu_view_shownames", item); - item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show Blocks", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SHOWBLOCKS, FALSE); - g_object_set_data (G_OBJECT (window), "menu_view_showblocks", item); - item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show C_oordinates", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SHOWCOORDINATES, TRUE); - g_object_set_data (G_OBJECT (window), "menu_view_showcoordinates", item); - item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show Window Outline", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SHOWOUTLINE, TRUE); - g_object_set_data (G_OBJECT (window), "menu_view_showoutline", item); - item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show ZBuffered Outline", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_NOOUTLINE, TRUE); - g_object_set_data (G_OBJECT (window), "menu_selection_nooutline", item); - item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show Axes", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SHOWAXES, TRUE); - g_object_set_data (G_OBJECT (window), "menu_view_showaxes", item); - item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show Workzone", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SHOWWORKZONE, FALSE); - g_object_set_data (G_OBJECT (window), "menu_view_showworkzone", item); - - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Filter"); - create_check_menu_item_with_mnemonic (menu_in_menu, "World", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_WORLD, FALSE); - create_check_menu_item_with_mnemonic (menu_in_menu, "Entities", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_ENTITIES, FALSE); - create_check_menu_item_with_mnemonic (menu_in_menu, "Areaportals", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_AREAPORTALS, FALSE); - create_check_menu_item_with_mnemonic (menu_in_menu, "Translucent", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_TRANSLUCENT, FALSE); - create_check_menu_item_with_mnemonic (menu_in_menu, "Liquids", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_LIQUIDS, FALSE); - create_check_menu_item_with_mnemonic (menu_in_menu, "Caulk", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_CAULK, FALSE); - create_check_menu_item_with_mnemonic (menu_in_menu, "Clips", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_CLIPS, FALSE); - create_check_menu_item_with_mnemonic (menu_in_menu, "Paths", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_PATHS, FALSE); - create_check_menu_item_with_mnemonic (menu_in_menu, "Clusterportals", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_CLUSTERPORTALS, FALSE); - create_check_menu_item_with_mnemonic (menu_in_menu, "Lights", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_LIGHTS, FALSE); - create_check_menu_item_with_mnemonic (menu_in_menu, "Structural", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_STRUCTURAL, FALSE); - item = create_check_menu_item_with_mnemonic (menu_in_menu, "Lightgrid", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_LIGHTGRID, FALSE); - g_object_set_data (G_OBJECT (window), "menu_filter_lightgrid", item); - create_check_menu_item_with_mnemonic (menu_in_menu, "Patches", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_PATCHES, FALSE); - create_check_menu_item_with_mnemonic (menu_in_menu, "Details", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_DETAILS, FALSE); - create_check_menu_item_with_mnemonic (menu_in_menu, "Hints", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_HINTSSKIPS, FALSE); - create_check_menu_item_with_mnemonic (menu_in_menu, "Models", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_MODELS, FALSE); - create_check_menu_item_with_mnemonic (menu_in_menu, "Triggers", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_TRIGGERS, FALSE); - create_check_menu_item_with_mnemonic (menu_in_menu, "Botclips", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_BOTCLIPS, FALSE); - - menu_separator (menu); - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Hide/Show"); - create_menu_item_with_mnemonic (menu_in_menu, "Hide Selected", - GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_HIDESHOW_HIDESELECTED); - create_menu_item_with_mnemonic (menu_in_menu, "Show Hidden", - GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_HIDESHOW_SHOWHIDDEN); - menu_separator (menu); - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Entities as"); - g_object_set_data (G_OBJECT (window), "view_entitiesas_menu", menu_in_menu); - item = create_radio_menu_item_with_mnemonic (menu_in_menu, NULL, "Bounding box", - GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ENTITIESAS_BOUNDINGBOX,FALSE); - g_object_set_data (G_OBJECT (window), "menu_view_entitiesas_boundingbox", item); - item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "Wireframe", - GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ENTITIESAS_WIREFRAME,FALSE); - g_object_set_data (G_OBJECT (window), "menu_view_entitiesas_wireframe", item); - item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "Selected Wireframe", - GTK_SIGNAL_FUNC (HandleCommand),ID_VIEW_ENTITIESAS_SELECTEDWIREFRAME,FALSE); - g_object_set_data (G_OBJECT (window), "menu_view_entitiesas_selectedwireframe", item); - item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "Selected Skinned", - GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ENTITIESAS_SELECTEDSKINNED,FALSE); - g_object_set_data (G_OBJECT (window), "menu_view_entitiesas_selectedskinned", item); - item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "Skinned", - GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ENTITIESAS_SKINNED,FALSE); - g_object_set_data (G_OBJECT (window), "menu_view_entitiesas_skinned", item); - item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "Skinned and Boxed", - GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ENTITIESAS_SKINNEDANDBOXED,FALSE); - g_object_set_data (G_OBJECT (window), "menu_view_entitiesas_skinnedandboxed", item); - menu_separator (menu); - item = create_check_menu_item_with_mnemonic (menu, "Cubic Clipping", - GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CUBICCLIPPING, TRUE); - g_object_set_data (G_OBJECT (window), "menu_view_cubicclipping", item); - menu_separator (menu); - item = create_check_menu_item_with_mnemonic (menu, "OpenGL Lighting", - GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_OPENGLLIGHTING, FALSE); - g_object_set_data (G_OBJECT (window), "menu_view_opengllighting", item); - - // Selection menu - menu = create_sub_menu_with_mnemonic (menu_bar, "_Selection"); - if (g_PrefsDlg.m_bDetachableMenus) - menu_tearoff (menu); - - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Drag"); - create_menu_item_with_mnemonic (menu_in_menu, "Drag _Edges", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_DRAGEDGES); - create_menu_item_with_mnemonic (menu_in_menu, "Drag _Vertices", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_DRAGVERTECIES); - menu_separator (menu); - create_menu_item_with_mnemonic (menu, "_Clone", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_CLONE); - item = create_menu_item_with_mnemonic (menu, "Deselect", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_DESELECT); - item = create_menu_item_with_mnemonic (menu, "Invert", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_INVERT); -#ifndef QUAKE3 - create_menu_item_with_mnemonic (menu, "_Delete", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_DELETE); -#endif - menu_separator (menu); - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Flip"); - create_menu_item_with_mnemonic (menu_in_menu, "Flip _X", - GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_FLIPX); - create_menu_item_with_mnemonic (menu_in_menu, "Flip _Y", - GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_FLIPY); - create_menu_item_with_mnemonic (menu_in_menu, "Flip _Z", - GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_FLIPZ); - menu_separator (menu); - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Rotate"); - create_menu_item_with_mnemonic (menu_in_menu, "Rotate X", - GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_ROTATEX); - create_menu_item_with_mnemonic (menu_in_menu, "Rotate Y", - GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_ROTATEY); - create_menu_item_with_mnemonic (menu_in_menu, "Rotate Z", - GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_ROTATEZ); - create_menu_item_with_mnemonic (menu_in_menu, "Arbitrary rotation...", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_ARBITRARYROTATION); - menu_separator (menu); - create_menu_item_with_mnemonic (menu, "Scale...", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECT_SCALE); - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "CSG"); - create_menu_item_with_mnemonic (menu_in_menu, "Make _Hollow", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MAKEHOLLOW); - create_menu_item_with_mnemonic (menu_in_menu, "CSG _Subtract", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_CSGSUBTRACT); - create_menu_item_with_mnemonic (menu_in_menu, "CSG _Merge", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_CSGMERGE); - menu_separator (menu); - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Select"); - create_menu_item_with_mnemonic (menu_in_menu, "Select Complete _Tall", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTCOMPLETETALL); - create_menu_item_with_mnemonic (menu_in_menu, "Select T_ouching", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTTOUCHING); - create_menu_item_with_mnemonic (menu_in_menu, "Select _Partial Tall", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTPARTIALTALL); - create_menu_item_with_mnemonic (menu_in_menu, "Select _Inside", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTINSIDE); -#ifndef QUAKE3 - create_menu_item_with_mnemonic (menu_in_menu, "Nudge Left", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGELEFT); - create_menu_item_with_mnemonic (menu_in_menu, "Nudge Right", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGERIGHT); - create_menu_item_with_mnemonic (menu_in_menu, "Nudge Up", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGEUP); - create_menu_item_with_mnemonic (menu_in_menu, "Nudge Down", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGEDOWN); -#endif - menu_separator (menu); - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Clipper"); - create_menu_item_with_mnemonic (menu_in_menu, "Toggle Clipper", - GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CLIPPER); - menu_separator (menu_in_menu); - create_menu_item_with_mnemonic (menu_in_menu, "Clip selection", - GTK_SIGNAL_FUNC (HandleCommand), ID_CLIP_SELECTED); - create_menu_item_with_mnemonic (menu_in_menu, "Split selection", - GTK_SIGNAL_FUNC (HandleCommand), ID_SPLIT_SELECTED); - create_menu_item_with_mnemonic (menu_in_menu, "Flip Clip orientation", - GTK_SIGNAL_FUNC (HandleCommand), ID_FLIP_CLIP); - menu_separator (menu); - create_menu_item_with_mnemonic (menu, "Connect entities", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_CONNECT); - create_menu_item_with_mnemonic (menu, "Ungroup entity", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_UNGROUPENTITY); - create_menu_item_with_mnemonic (menu, "Make detail", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MAKE_DETAIL); - create_menu_item_with_mnemonic (menu, "Make structural", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MAKE_STRUCTURAL); - - // BSP menu - menu = create_sub_menu_with_mnemonic (menu_bar, "_Bsp"); - - menu_separator (menu); - g_object_set_data (G_OBJECT (window), "menu_bsp", menu); - - // Grid menu - menu = create_sub_menu_with_mnemonic (menu_bar, "_Grid"); - if (g_PrefsDlg.m_bDetachableMenus) - menu_tearoff (menu); - - item = create_radio_menu_item_with_mnemonic (menu, NULL, "Grid0.25", - GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_025, FALSE); - g_object_set_data (G_OBJECT (window), "menu_grid_025", item); - item = create_radio_menu_item_with_mnemonic (menu, item, "Grid0.5", - GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_05, FALSE); - g_object_set_data (G_OBJECT (window), "menu_grid_05", item); - item = create_radio_menu_item_with_mnemonic (menu, item, "Grid1", - GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_1, FALSE); - g_object_set_data (G_OBJECT (window), "menu_grid_1", item); - item = create_radio_menu_item_with_mnemonic (menu, item, "Grid2", - GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_2, FALSE); - g_object_set_data (G_OBJECT (window), "menu_grid_2", item); - item = create_radio_menu_item_with_mnemonic (menu, item, "Grid4", - GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_4, FALSE); - g_object_set_data (G_OBJECT (window), "menu_grid_4", item); - item = create_radio_menu_item_with_mnemonic (menu, item, "Grid8", - GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_8, TRUE); - g_object_set_data (G_OBJECT (window), "menu_grid_8", item); - item = create_radio_menu_item_with_mnemonic (menu, item, "Grid16", - GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_16, FALSE); - g_object_set_data (G_OBJECT (window), "menu_grid_16", item); - item = create_radio_menu_item_with_mnemonic (menu, item, "Grid32", - GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_32, FALSE); - g_object_set_data (G_OBJECT (window), "menu_grid_32", item); - item = create_radio_menu_item_with_mnemonic (menu, item, "Grid64", - GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_64, FALSE); - g_object_set_data (G_OBJECT (window), "menu_grid_64", item); - item = create_radio_menu_item_with_mnemonic (menu, item, "Grid128", - GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_128, FALSE); - g_object_set_data (G_OBJECT (window), "menu_grid_128", item); - item = create_radio_menu_item_with_mnemonic (menu, item, "Grid256", - GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_256, FALSE); - g_object_set_data (G_OBJECT (window), "menu_grid_256", item); - menu_separator (menu); - item = create_check_menu_item_with_mnemonic (menu, "Snap to grid", - GTK_SIGNAL_FUNC (HandleCommand), ID_SNAPTOGRID, TRUE); - g_object_set_data (G_OBJECT (window), "menu_snaptogrid", item); - - // Textures menu - menu = create_sub_menu_with_mnemonic (menu_bar, "_Textures"); - if (g_PrefsDlg.m_bDetachableMenus) - menu_tearoff (menu); - - item = create_check_menu_item_with_mnemonic (menu, "Show In _Use", - GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_SHOWINUSE, FALSE); - g_object_set_data (G_OBJECT (window), "menu_textures_showinuse", item); - item = create_check_menu_item_with_mnemonic (menu, "Show _All", - GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_SHOWALL, FALSE); - g_object_set_data (G_OBJECT (window), "menu_textures_showall", item); - menu_separator (menu); - item = create_check_menu_item_with_mnemonic (menu, "Show shaders", - GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_SHADERS_SHOW, FALSE); - g_object_set_data (G_OBJECT (window), "menu_textures_shaders_show", item); - item = create_menu_item_with_mnemonic (menu, "Flush & Reload Shaders", - GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_RELOADSHADERS); - g_object_set_data (G_OBJECT (window), "menu_textures_reloadshaders", item); - item = create_menu_item_with_mnemonic (menu, "Load directory...", - GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_LOAD); - g_object_set_data (G_OBJECT (window), "menu_textures_load", item); - item = create_menu_item_with_mnemonic (menu, "Directory list...", - GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_LOADLIST); - menu_separator (menu); - - item = create_menu_item_with_mnemonic (menu, "_Surface Inspector", - GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_INSPECTOR); - menu_separator (menu); - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Render Quality"); - g_object_set_data (G_OBJECT (window), "render_quality_menu", menu_in_menu); - item = create_radio_menu_item_with_mnemonic (menu_in_menu, NULL, "_Wireframe", - GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_WIREFRAME, FALSE); - g_object_set_data (G_OBJECT (window), "menu_textures_wireframe", item); - item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "_Flat shade", - GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_FLATSHADE, FALSE); - g_object_set_data (G_OBJECT (window), "menu_textures_flatshade", item); - item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "_Nearest", - GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_NEAREST, FALSE); - g_object_set_data (G_OBJECT (window), "menu_view_nearest", item); - item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "Nearest _Mipmap", - GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_NEARESTMIPMAP, FALSE); - g_object_set_data (G_OBJECT (window), "menu_view_nearestmipmap", item); - item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "_Linear", - GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_LINEAR, FALSE); - g_object_set_data (G_OBJECT (window), "menu_view_linear", item); - item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "_Bilinear", - GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_BILINEAR, FALSE); - g_object_set_data (G_OBJECT (window), "menu_view_bilinear", item); - item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "B_ilinear Mipmap", - GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_BILINEARMIPMAP, FALSE); - g_object_set_data (G_OBJECT (window), "menu_view_bilinearmipmap", item); - item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "T_rilinear", - GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_TRILINEAR, FALSE); - g_object_set_data (G_OBJECT (window), "menu_view_trilinear", item); - create_menu_item_with_mnemonic (menu, "Find / Replace...", - GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURE_REPLACEALL); - - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Texture Lock"); - item = create_check_menu_item_with_mnemonic (menu_in_menu, "Moves", - GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLE_LOCK, TRUE); - g_object_set_data (G_OBJECT (window), "menu_toggle_lock", item); - item = create_check_menu_item_with_mnemonic (menu_in_menu, "Rotations", - GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLE_ROTATELOCK, TRUE); - g_object_set_data (G_OBJECT (window), "menu_toggle_rotatelock", item); - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Texture Window Scale"); - item = create_radio_menu_item_with_mnemonic (menu_in_menu, NULL, "200%", - GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_TEXTUREWINDOWSCALE_200, FALSE); - g_object_set_data (G_OBJECT (window), "menu_textures_texturewindowscale_200", item); - item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "100%", - GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_TEXTUREWINDOWSCALE_100, FALSE); - g_object_set_data (G_OBJECT (window), "menu_textures_texturewindowscale_100", item); - item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "50%", - GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_TEXTUREWINDOWSCALE_50, FALSE); - g_object_set_data (G_OBJECT (window), "menu_textures_texturewindowscale_50", item); - item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "25%", - GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_TEXTUREWINDOWSCALE_25, FALSE); - g_object_set_data (G_OBJECT (window), "menu_textures_texturewindowscale_25", item); - item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "10%", - GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_TEXTUREWINDOWSCALE_10, FALSE); - g_object_set_data (G_OBJECT (window), "menu_textures_texturewindowscale_10", item); - item = menu_separator (menu); - item = create_check_menu_item_with_mnemonic (menu, "shaderlist.txt only", - GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_SHADERLISTONLY, FALSE); - g_object_set_data (G_OBJECT (window), "menu_textures_shaderlistonly", item); - item = menu_separator (menu); - g_object_set_data (G_OBJECT (window), "menu_textures_separator", item); - g_object_set_data (G_OBJECT (window), "menu_textures", menu); - - // Misc menu - menu = create_sub_menu_with_mnemonic (menu_bar, "_Misc"); - if (g_PrefsDlg.m_bDetachableMenus) - menu_tearoff (menu); - - create_menu_item_with_mnemonic (menu, "_Benchmark", GTK_SIGNAL_FUNC (HandleCommand), ID_MISC_BENCHMARK); - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Colors"); - menu_3 = create_menu_in_menu_with_mnemonic (menu_in_menu, "Themes"); - create_menu_item_with_mnemonic (menu_3, "QE4 Original", GTK_SIGNAL_FUNC (HandleCommand), ID_COLOR_SETORIGINAL); - create_menu_item_with_mnemonic (menu_3, "Q3Radiant Original", GTK_SIGNAL_FUNC (HandleCommand), ID_COLOR_SETQER); - create_menu_item_with_mnemonic (menu_3, "Black and Green", GTK_SIGNAL_FUNC (HandleCommand), ID_COLOR_SETBLACK); - create_menu_item_with_mnemonic (menu_3, "Maya/Max/Lightwave Emulation", GTK_SIGNAL_FUNC (HandleCommand), ID_COLOR_SETYDNAR); - - menu_separator (menu_in_menu); - create_menu_item_with_mnemonic (menu_in_menu, "_Texture Background...", - GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTUREBK); - create_menu_item_with_mnemonic (menu_in_menu, "Grid Background...", - GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_XYBK); - create_menu_item_with_mnemonic (menu_in_menu, "Grid Major...", - GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_MAJOR); - create_menu_item_with_mnemonic (menu_in_menu, "Grid Minor...", - GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_MINOR); - create_menu_item_with_mnemonic (menu_in_menu, "Grid Major Small...", - GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_MAJOR_ALT); - create_menu_item_with_mnemonic (menu_in_menu, "Grid Minor Small...", - GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_MINOR_ALT); - create_menu_item_with_mnemonic (menu_in_menu, "Grid Text...", - GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_GRIDTEXT); - create_menu_item_with_mnemonic (menu_in_menu, "Grid Block...", - GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_GRIDBLOCK); - create_menu_item_with_mnemonic (menu_in_menu, "Default Brush...", - GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_BRUSH); - create_menu_item_with_mnemonic (menu_in_menu, "Camera Background...", - GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_CAMERABACK); - create_menu_item_with_mnemonic (menu_in_menu, "Selected Brush...", - GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_SELECTEDBRUSH); - create_menu_item_with_mnemonic (menu_in_menu, "Selected Brush (Camera)...", - GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_SELECTEDBRUSH3D); - create_menu_item_with_mnemonic (menu_in_menu, "Clipper...", - GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_CLIPPER); - create_menu_item_with_mnemonic (menu_in_menu, "Active View name...", - GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_VIEWNAME); - - create_menu_item_with_mnemonic (menu, "_Gamma...", - GTK_SIGNAL_FUNC (HandleCommand), ID_MISC_GAMMA); - create_menu_item_with_mnemonic (menu, "Find brush...", - GTK_SIGNAL_FUNC (HandleCommand), ID_MISC_FINDBRUSH); - item = create_menu_item_with_mnemonic (menu, "Next leak spot", - GTK_SIGNAL_FUNC (HandleCommand), ID_MISC_NEXTLEAKSPOT); - item = create_menu_item_with_mnemonic (menu, "Previous leak spot", - GTK_SIGNAL_FUNC (HandleCommand), ID_MISC_PREVIOUSLEAKSPOT); - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=394 -// create_menu_item_with_mnemonic (menu, "_Print XY View", GTK_SIGNAL_FUNC (HandleCommand), ID_MISC_PRINTXY); - item = create_menu_item_with_mnemonic (menu, "_Select Entity Color...", - GTK_SIGNAL_FUNC (HandleCommand), ID_MISC_SELECTENTITYCOLOR); - g_object_set_data (G_OBJECT (window), "menu_misc_selectentitycolor", item); - - // Region menu - menu = create_sub_menu_with_mnemonic (menu_bar, "_Region"); - if (g_PrefsDlg.m_bDetachableMenus) - menu_tearoff (menu); - - create_menu_item_with_mnemonic (menu, "_Off", - GTK_SIGNAL_FUNC (HandleCommand), ID_REGION_OFF); - create_menu_item_with_mnemonic (menu, "_Set XY", - GTK_SIGNAL_FUNC (HandleCommand), ID_REGION_SETXY); - create_menu_item_with_mnemonic (menu, "Set _Tall Brush", - GTK_SIGNAL_FUNC (HandleCommand), ID_REGION_SETTALLBRUSH); - create_menu_item_with_mnemonic (menu, "Set _Brush", - GTK_SIGNAL_FUNC (HandleCommand), ID_REGION_SETBRUSH); - create_menu_item_with_mnemonic (menu, "Set Se_lected Brushes", - GTK_SIGNAL_FUNC (HandleCommand), ID_REGION_SETSELECTION); - - // Brush menu - menu = create_sub_menu_with_mnemonic (menu_bar, "_Brush"); - if (g_PrefsDlg.m_bDetachableMenus) - menu_tearoff (menu); - - item = create_menu_item_with_mnemonic (menu, "3 sided", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_3SIDED); - item = create_menu_item_with_mnemonic (menu, "4 sided", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_4SIDED); - item = create_menu_item_with_mnemonic (menu, "5 sided", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_5SIDED); - item = create_menu_item_with_mnemonic (menu, "6 sided", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_6SIDED); - item = create_menu_item_with_mnemonic (menu, "7 sided", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_7SIDED); - item = create_menu_item_with_mnemonic (menu, "8 sided", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_8SIDED); - item = create_menu_item_with_mnemonic (menu, "9 sided", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_9SIDED); - menu_separator (menu); - create_menu_item_with_mnemonic (menu, "Arbitrary sided...", - GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_ARBITRARYSIDED); - menu_separator (menu); - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Primitives"); - create_menu_item_with_mnemonic (menu_in_menu, "Cone...", - GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_MAKECONE); - create_menu_item_with_mnemonic (menu_in_menu, "Sphere...", - GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_PRIMITIVES_SPHERE); - - // Curve menu - if (!g_pGameDescription->mNoPatch) - { - menu = create_sub_menu_with_mnemonic (menu_bar, "_Curve"); - if (g_PrefsDlg.m_bDetachableMenus) - menu_tearoff (menu); - - create_menu_item_with_mnemonic (menu, "Cylinder", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PATCHTUBE); - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "More Cylinders"); - create_menu_item_with_mnemonic (menu_in_menu, "Dense Cylinder", - GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PATCHDENSETUBE); - create_menu_item_with_mnemonic (menu_in_menu, "Very Dense Cylinder", - GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PATCHVERYDENSETUBE); - create_menu_item_with_mnemonic (menu_in_menu, "Square Cylinder", - GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PATCHSQUARE); - menu_separator (menu); - create_menu_item_with_mnemonic (menu, "End cap", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PATCHENDCAP); - create_menu_item_with_mnemonic (menu, "Bevel", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PATCHBEVEL); - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "More End caps, Bevels"); - create_menu_item_with_mnemonic (menu_in_menu, "Square Endcap", - GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_MOREENDCAPSBEVELS_SQUAREBEVEL); - create_menu_item_with_mnemonic (menu_in_menu, "Square Bevel", - GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_MOREENDCAPSBEVELS_SQUAREENDCAP); - menu_separator (menu); - create_menu_item_with_mnemonic (menu, "Cone", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PATCHCONE); - item = create_menu_item_with_mnemonic (menu, "Sphere", - GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PRIMITIVES_SPHERE); - gtk_widget_set_sensitive (item, FALSE); - menu_separator (menu); - item = create_menu_item_with_mnemonic (menu, "Simple Patch Mesh...", - GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_SIMPLEPATCHMESH); - g_object_set_data (G_OBJECT (window), "menu_simplepatchmesh", item); - menu_separator (menu); - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Insert"); - create_menu_item_with_mnemonic (menu_in_menu, "Insert (2) Columns", - GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_INSERT_INSERTCOLUMN); - create_menu_item_with_mnemonic (menu_in_menu, "Add (2) Columns", - GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_INSERT_ADDCOLUMN); - menu_separator (menu_in_menu); - create_menu_item_with_mnemonic (menu_in_menu, "Insert (2) Rows", - GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_INSERT_INSERTROW); - create_menu_item_with_mnemonic (menu_in_menu, "Add (2) Rows", - GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_INSERT_ADDROW); - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Delete"); - create_menu_item_with_mnemonic (menu_in_menu, "First (2) Columns", - GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_DELETE_FIRSTCOLUMN); - create_menu_item_with_mnemonic (menu_in_menu, "Last (2) Columns", - GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_DELETE_LASTCOLUMN); - menu_separator (menu_in_menu); - create_menu_item_with_mnemonic (menu_in_menu, "First (2) Rows", - GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_DELETE_FIRSTROW); - create_menu_item_with_mnemonic (menu_in_menu, "Last (2) Rows", - GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_DELETE_LASTROW); - menu_separator (menu); - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Matrix"); - create_menu_item_with_mnemonic (menu_in_menu, "Invert", - GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_NEGATIVE); - menu_3 = create_menu_in_menu_with_mnemonic (menu_in_menu, "Re-disperse"); - create_menu_item_with_mnemonic (menu_3, "Rows", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_REDISPERSE_ROWS); - create_menu_item_with_mnemonic (menu_3, "Cols (Intermediate)", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_REDISPERSE_INTERMEDIATE_COLS); - create_menu_item_with_mnemonic (menu_3, "Rows (Intermediate)", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_REDISPERSE_INTERMEDIATE_ROWS); - create_menu_item_with_mnemonic (menu_in_menu, "Transpose", - GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_MATRIX_TRANSPOSE); - menu_separator (menu); - create_menu_item_with_mnemonic (menu, "Cap Selection", - GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_CAP); - create_menu_item_with_mnemonic (menu, "Cycle Cap Texture", - GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_CYCLECAP); - menu_separator (menu); - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Overlay"); - create_menu_item_with_mnemonic (menu_in_menu, "Set", - GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_OVERLAY_SET); - create_menu_item_with_mnemonic (menu_in_menu, "Clear", - GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_OVERLAY_CLEAR); - menu_separator (menu); - create_menu_item_with_mnemonic (menu, "Thicken...", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_THICKEN); - } - // Plugins menu - menu = create_sub_menu_with_mnemonic (menu_bar, "_Plugins"); - if (g_PrefsDlg.m_bDetachableMenus) - menu_tearoff (menu); - - /* - create_menu_item_with_mnemonic (menu, "Refresh", GTK_SIGNAL_FUNC (HandleCommand), ID_PLUGINS_REFRESH); - */ - // NOTE: the seperator is used when doing a refresh of the list, everything past the seperator is removed - item = menu_separator (menu); - g_object_set_data (G_OBJECT (window), "menu_plugin_separator", item); - g_object_set_data (G_OBJECT (window), "menu_plugin", menu); - - // Help menu - menu = create_sub_menu_with_mnemonic (menu_bar, "_Help"); - if (g_PrefsDlg.m_bDetachableMenus) - menu_tearoff (menu); - - item = create_menu_item_with_mnemonic (menu, "Manual", - GTK_SIGNAL_FUNC (HandleCommand), ID_HELP); - gtk_widget_add_accelerator (item, "activate", accel, GDK_F1, (GdkModifierType)0, GTK_ACCEL_VISIBLE); - - // this creates all the per-game drop downs for the game pack helps - // it will take care of hooking the Sys_OpenURL calls etc. - create_game_help_menu(menu, accel); - - // TTimo: this is in global.xlink now - //create_menu_item_with_mnemonic (menu, "Links", - // GTK_SIGNAL_FUNC (HandleCommand), ID_HELP_LINKS); - create_menu_item_with_mnemonic (menu, "Bug report", - GTK_SIGNAL_FUNC (HandleCommand), ID_HELP_BUGREPORT); - create_menu_item_with_mnemonic (menu, "Shortcuts list", - GTK_SIGNAL_FUNC (HandleCommand), ID_HELP_COMMANDLIST); - create_menu_item_with_mnemonic (menu, "_About", - GTK_SIGNAL_FUNC (HandleCommand), ID_HELP_ABOUT); - - - // leo: Hidden menu to make the accelerators work, - // this is a hack that needs to be changed later if someone has a better idea. - // NOTE TTimo - // maybe the better idea would be NOT to use any such accelerator scheme and do all key listening and interpret ourselves - menu = create_sub_menu_with_mnemonic (menu_bar, "Hidden"); - if (g_PrefsDlg.m_bDetachableMenus) - menu_tearoff (menu); - - gtk_widget_hide (gtk_menu_get_attach_widget (GTK_MENU (menu))); - - create_menu_item_with_mnemonic (menu, "BendMode", GTK_SIGNAL_FUNC (HandleCommand), ID_PATCH_BEND); - create_menu_item_with_mnemonic (menu, "FitTexture", GTK_SIGNAL_FUNC (HandleCommand), IDC_BTN_FACEFIT); - create_menu_item_with_mnemonic (menu, "ViewTextures", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_TEXTURE); - create_menu_item_with_mnemonic (menu, "PatchInspector", GTK_SIGNAL_FUNC (HandleCommand), ID_PATCH_INSPECTOR); - create_menu_item_with_mnemonic (menu, "InvertCurveTextureX", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_NEGATIVETEXTUREY); - create_menu_item_with_mnemonic (menu, "InvertCurveTextureY", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_NEGATIVETEXTUREX); - create_menu_item_with_mnemonic (menu, "IncPatchColumn", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_INSERTCOLUMN); - create_menu_item_with_mnemonic (menu, "IncPatchRow", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_INSERTROW); - create_menu_item_with_mnemonic (menu, "DecPatchColumn", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_DELETECOLUMN); - create_menu_item_with_mnemonic (menu, "DecPatchRow", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_DELETEROW); - create_menu_item_with_mnemonic (menu, "Patch TAB", GTK_SIGNAL_FUNC (HandleCommand), ID_PATCH_TAB); - create_menu_item_with_mnemonic (menu, "Patch TAB", GTK_SIGNAL_FUNC (HandleCommand), ID_PATCH_TAB); - create_menu_item_with_mnemonic (menu, "SelectNudgeDown", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGEDOWN); - create_menu_item_with_mnemonic (menu, "CameraForward", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_FORWARD); - create_menu_item_with_mnemonic (menu, "CameraBack", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_BACK); - create_menu_item_with_mnemonic (menu, "CameraLeft", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_LEFT); - create_menu_item_with_mnemonic (menu, "CameraRight", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_RIGHT); - create_menu_item_with_mnemonic (menu, "CameraUp", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_UP); - create_menu_item_with_mnemonic (menu, "CameraDown", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_DOWN); - create_menu_item_with_mnemonic (menu, "CameraAngleUp", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_ANGLEUP); - create_menu_item_with_mnemonic (menu, "CameraAngleDown", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_ANGLEDOWN); - create_menu_item_with_mnemonic (menu, "CameraStrafeRight", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_STRAFERIGHT); - create_menu_item_with_mnemonic (menu, "CameraStrafeLeft", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_STRAFELEFT); - create_menu_item_with_mnemonic (menu, "ToggleGrid", GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_TOGGLE); - create_menu_item_with_mnemonic (menu, "ToggleCrosshairs", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CROSSHAIR); - create_menu_item_with_mnemonic (menu, "ToggleRealtime", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CAMERAUPDATE); - create_menu_item_with_mnemonic (menu, "MouseRotate", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECT_MOUSEROTATE); - create_menu_item_with_mnemonic (menu, "TexRotateClock", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_ROTATECLOCK); - create_menu_item_with_mnemonic (menu, "TexRotateCounter", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_ROTATECOUNTER); - create_menu_item_with_mnemonic (menu, "TexScaleUp", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SCALEUP); - create_menu_item_with_mnemonic (menu, "TexScaleDown", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SCALEDOWN); - create_menu_item_with_mnemonic (menu, "TexShiftLeft", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SHIFTLEFT); - create_menu_item_with_mnemonic (menu, "TexShiftRight", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SHIFTRIGHT); - create_menu_item_with_mnemonic (menu, "TexShiftUp", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SHIFTUP); - create_menu_item_with_mnemonic (menu, "TexShiftDown", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SHIFTDOWN); - create_menu_item_with_mnemonic (menu, "GridDown", GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_PREV); - create_menu_item_with_mnemonic (menu, "GridUp", GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_NEXT); - create_menu_item_with_mnemonic (menu, "TexScaleLeft", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SCALELEFT); - create_menu_item_with_mnemonic (menu, "TexScaleRight", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SCALERIGHT); - create_menu_item_with_mnemonic (menu, "MoveSelectionDOWN", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MOVEDOWN); - create_menu_item_with_mnemonic (menu, "MoveSelectionUP", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MOVEUP); - create_menu_item_with_mnemonic (menu, "DumpSelectedBrush", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_PRINT); - create_menu_item_with_mnemonic (menu, "ToggleSizePaint", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TOGGLESIZEPAINT); - create_menu_item_with_mnemonic (menu, "SelectNudgeLeft", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGELEFT); - create_menu_item_with_mnemonic (menu, "SelectNudgeRight", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGERIGHT); - create_menu_item_with_mnemonic (menu, "SelectNudgeUp", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGEUP); - create_menu_item_with_mnemonic (menu, "NaturalizePatch", GTK_SIGNAL_FUNC (HandleCommand), ID_PATCH_NATURALIZE); - create_menu_item_with_mnemonic (menu, "SnapPatchToGrid", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECT_SNAPTOGRID); - create_menu_item_with_mnemonic (menu, "SelectAllOfType", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECT_ALL); - create_menu_item_with_mnemonic (menu, "CycleOutlineStyle", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_OUTLINESTYLE); - create_menu_item_with_mnemonic (menu, "TextureWindowScaleup", GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTUREWINDOW_SCALEUP); - create_menu_item_with_mnemonic (menu, "TextureWindowScaledown", GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTUREWINDOW_SCALEDOWN); - - g_bIgnoreCommands--; -} - -void MainFrame::create_main_toolbar (GtkWidget *window, GtkWidget *vbox) -{ - GtkWidget *handle_box, *toolbar, *w; - - handle_box = gtk_handle_box_new (); - gtk_box_pack_start (GTK_BOX (vbox), handle_box, FALSE, FALSE, 0); - gtk_widget_show (handle_box); - g_object_set_data (G_OBJECT (window), "tb_handle_box", handle_box); - - toolbar = gtk_toolbar_new (); - gtk_toolbar_set_orientation (GTK_TOOLBAR(toolbar), GTK_ORIENTATION_HORIZONTAL); - gtk_toolbar_set_style (GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS); - // gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), user_rc.toolbar_style); - gtk_container_add (GTK_CONTAINER (handle_box), toolbar); - - gtk_widget_show (toolbar); - - w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "Open", "Open an existing map", "", - new_pixmap (window, "file_open.bmp"), GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ID_FILE_OPEN)); - g_object_set_data (G_OBJECT (window), "tb_file_open", w); - w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "Save", "Save the active map", "", - new_pixmap (window, "file_save.bmp"), GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ID_FILE_SAVE)); - g_object_set_data (G_OBJECT (window), "tb_file_save", w); - gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); - w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "x-axis Flip", "", - new_pixmap (window, "brush_flipx.bmp"), GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ID_BRUSH_FLIPX)); - g_object_set_data (G_OBJECT (window), "tb_brush_flipx", w); - w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "x-axis Rotate", "", - new_pixmap (window, "brush_rotatex.bmp"), GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ID_BRUSH_ROTATEX)); - g_object_set_data (G_OBJECT (window), "tb_brush_rotatex", w); - w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "y-axis Flip", "", - new_pixmap (window, "brush_flipy.bmp"), GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ID_BRUSH_FLIPY)); - g_object_set_data (G_OBJECT (window), "tb_brush_flipy", w); - w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "y-axis Rotate", "", - new_pixmap (window, "brush_rotatey.bmp"), GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ID_BRUSH_ROTATEY)); - g_object_set_data (G_OBJECT (window), "tb_brush_rotatey", w); - w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "z-axis Flip", "", - new_pixmap (window, "brush_flipz.bmp"), GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ID_BRUSH_FLIPZ)); - g_object_set_data (G_OBJECT (window), "tb_brush_flipz", w); - w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "z-axis Rotate", "", - new_pixmap (window, "brush_rotatez.bmp"), GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ID_BRUSH_ROTATEZ)); - g_object_set_data (G_OBJECT (window), "tb_brush_rotatez", w); - gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); - - if (g_PrefsDlg.m_bWideToolbar) - { - w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Complete Tall", "", - new_pixmap (window, "selection_selectcompletetall.bmp"), GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ID_SELECTION_SELECTCOMPLETETALL)); - g_object_set_data (G_OBJECT (window), "tb_selection_selectcompletetall", w); - w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Select Touching", "", - new_pixmap (window, "selection_selecttouching.bmp"), GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ID_SELECTION_SELECTTOUCHING)); - g_object_set_data (G_OBJECT (window), "tb_selection_selecttouching", w); - w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Select Partial Tall", "", - new_pixmap (window, "selection_selectpartialtall.bmp"), GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ID_SELECTION_SELECTPARTIALTALL)); - g_object_set_data (G_OBJECT (window), "tb_selection_selectpartialtall", w); - w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Select Inside", "", - new_pixmap (window, "selection_selectinside.bmp"), GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ID_SELECTION_SELECTINSIDE)); - g_object_set_data (G_OBJECT (window), "tb_selection_selectinside", w); - } else - { - w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Selection", "", - new_pixmap (window, "popup_selection.bmp"), GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ID_POPUP_SELECTION)); - g_object_set_data (G_OBJECT (window), "tb_popup_selection", w); - } - gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); - - w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "CSG Subtract", "", - new_pixmap (window, "selection_csgsubtract.bmp"), - GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SELECTION_CSGSUBTRACT)); - g_object_set_data (G_OBJECT (window), "tb_selection_csgsubtract", w); - - if (g_PrefsDlg.m_bWideToolbar) - { - w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "CSG Merge", "", - new_pixmap (window, "selection_csgmerge.bmp"), - GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SELECTION_CSGMERGE)); - g_object_set_data (G_OBJECT (window), "tb_selection_csgmerge", w); - } - - w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Hollow", "", - new_pixmap (window, "selection_makehollow.bmp"), - GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SELECTION_MAKEHOLLOW)); - g_object_set_data (G_OBJECT (window), "tb_selection_makehollow", w); - - if (g_PrefsDlg.m_bWideToolbar) - { - w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, - "", "Clipper", "", new_pixmap (window, "view_clipper.bmp"), - GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_VIEW_CLIPPER)); - g_object_set_data (G_OBJECT (window), "tb_view_clipper", w); - } - - gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); - - w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Change views", "", - new_pixmap (window, "view_change.bmp"), GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ID_VIEW_CHANGE)); - g_object_set_data (G_OBJECT (window), "tb_view_change", w); - - if (!g_PrefsDlg.m_bWideToolbar) - { - gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); - } - - w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Texture view mode", "", - new_pixmap (window, "textures_popup.bmp"), GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ID_TEXTURES_POPUP)); - g_object_set_data (G_OBJECT (window), "tb_textures_popup", w); - - if (g_PrefsDlg.m_bWideToolbar) - { - w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, - "", "Cubic clip the camera view", "", - new_pixmap (window, "view_cubicclipping.bmp"), - GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_VIEW_CUBICCLIPPING)); - g_object_set_data (G_OBJECT (window), "tb_view_cubicclipping", w); - } - - gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); - - if (!g_PrefsDlg.m_bWideToolbar) - { - w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, - "", "Camera preview", "", new_pixmap (window, "view_cameratoggle.bmp"), - GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_VIEW_CAMERATOGGLE)); - g_object_set_data (G_OBJECT (window), "tb_view_cameratoggle", w); - w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Update Camera", "", - new_pixmap (window, "view_cameraupdate.bmp"), GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ID_VIEW_CAMERAUPDATE)); - g_object_set_data (G_OBJECT (window), "tb_view_cameraupdate", w); - w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, - "", "Cubic clip the camera view", "", - new_pixmap (window, "view_cubicclipping.bmp"), - GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_VIEW_CUBICCLIPPING)); - g_object_set_data (G_OBJECT (window), "tb_view_cubicclipping", w); - gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); - w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, - "", "Entity inspector", "", new_pixmap (window, "view_entity.bmp"), - GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_VIEW_ENTITY)); - g_object_set_data (G_OBJECT (window), "tb_view_entity", w); - gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); - w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, - "", "Clipper", "", new_pixmap (window, "view_clipper.bmp"), - GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_VIEW_CLIPPER)); - g_object_set_data (G_OBJECT (window), "tb_view_clipper", w); - gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); - } - - w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, - "", "Free Rotation", "", new_pixmap (window, "select_mouserotate.bmp"), - GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SELECT_MOUSEROTATE)); - g_object_set_data (G_OBJECT (window), "tb_select_mouserotate", w); - gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); - w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, - "", "Free Scaling", "", new_pixmap (window, "select_mousescale.bmp"), - GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SELECT_MOUSESCALE)); - g_object_set_data (G_OBJECT (window), "tb_select_mousescale", w); - w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, - "", "Scale X", "", new_pixmap (window, "scalelockx.bmp"), - GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SCALELOCKX)); - g_object_set_data (G_OBJECT (window), "tb_scalelockx", w); - w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, - "", "Scale Y", "", new_pixmap (window, "scalelocky.bmp"), - GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SCALELOCKY)); - g_object_set_data (G_OBJECT (window), "tb_scalelocky", w); - w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, - "", "Scale Z", "", new_pixmap (window, "scalelockz.bmp"), - GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SCALELOCKZ)); - g_object_set_data (G_OBJECT (window), "tb_scalelockz", w); - - if (g_PrefsDlg.m_bWideToolbar) - { - gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); - w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, - "", "Don't select model brushes", "", - new_pixmap (window, "dontselectmodel.bmp"), GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ID_DONTSELECTMODEL)); - gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); - g_object_set_data (G_OBJECT (window), "tb_dontselectmodel", w); - - if (!g_pGameDescription->mNoPatch) - { - w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, - "", "Don't select curved brushes", "", - new_pixmap (window, "dontselectcurve.bmp"), GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ID_DONTSELECTCURVE)); - g_object_set_data (G_OBJECT (window), "tb_dontselectcurve", w); - } - } - - // bug #292, patch toolbar option - if (g_PrefsDlg.m_bPatchToolbar) - { - w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, - "", "Show patch bounding box", "", - new_pixmap (window, "patch_showboundingbox.bmp"), - GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_PATCH_SHOWBOUNDINGBOX)); - g_object_set_data (G_OBJECT (window), "tb_patch_showboundingbox", w); - w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, - "", "Show patches as wireframes", "", - new_pixmap (window, "patch_wireframe.bmp"), - GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_PATCH_WIREFRAME)); - g_object_set_data (G_OBJECT (window), "tb_patch_wireframe", w); - w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, - "", "Patch Bend mode", "", - new_pixmap (window, "patch_bend.bmp"), GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ID_PATCH_BEND)); - g_object_set_data (G_OBJECT (window), "tb_patch_bend", w); - w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Put caps on the current patch", "", - new_pixmap (window, "curve_cap.bmp"), GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ID_CURVE_CAP)); - g_object_set_data (G_OBJECT (window), "tb_curve_cap", w); - w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, - "", "Welds equal patch points during moves", "", - new_pixmap (window, "patch_weld.bmp"), GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ID_PATCH_WELD)); - g_object_set_data (G_OBJECT (window), "tb_patch_weld", w); - w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, - "", "Selects drill down rows and columns", "", - new_pixmap (window, "patch_drilldown.bmp"), GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ID_PATCH_DRILLDOWN)); - g_object_set_data (G_OBJECT (window), "tb_patch_drilldown", w); - } - - if (g_PrefsDlg.m_bWideToolbar) - { - gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); - w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Show Entities as", "", - new_pixmap (window, "show_entities.bmp"), GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ID_SHOW_ENTITIES)); - g_object_set_data (G_OBJECT (window), "tb_show_entities", w); - } - - /* - uh? that is OLD -#ifndef QUAKE3 - w = g_object_get_data (G_OBJECT (window), "tb_dontselectcurve"); - gtk_widget_hide (w); - w = g_object_get_data (G_OBJECT (window), "tb_patch_showboundingbox"); - gtk_widget_hide (w); - w = g_object_get_data (G_OBJECT (window), "tb_patch_weld"); - gtk_widget_hide (w); - w = g_object_get_data (G_OBJECT (window), "tb_patch_wireframe"); - gtk_widget_hide (w); -#endif - */ - - m_bCamPreview = true; - g_nScaleHow = (SCALE_X | SCALE_Y | SCALE_Z); -} - -void MainFrame::create_plugin_toolbar (GtkWidget *window, GtkWidget *vbox) -{ - GtkWidget *handle_box, *toolbar; - - handle_box = gtk_handle_box_new (); - gtk_box_pack_start (GTK_BOX (vbox), handle_box, FALSE, FALSE, 0); - if (g_PrefsDlg.m_bPluginToolbar) - gtk_widget_show (handle_box); - g_object_set_data (G_OBJECT (window), "tb_handle_box", handle_box); - - toolbar = gtk_toolbar_new(); - gtk_toolbar_set_orientation (GTK_TOOLBAR(toolbar), GTK_ORIENTATION_HORIZONTAL); - gtk_toolbar_set_style (GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS); - // gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), user_rc.toolbar_style); - gtk_container_add (GTK_CONTAINER (handle_box), toolbar); - g_object_set_data (G_OBJECT (window), "toolbar_plugin", toolbar); - gtk_widget_show (toolbar); -} - -void MainFrame::create_main_statusbar (GtkWidget *window, GtkWidget *vbox) -{ - GtkWidget *hbox, *hbox1; - GtkWidget *frame; - GtkWidget *label; - - hbox = gtk_hbox_new (FALSE, 0); - gtk_widget_show (hbox); - gtk_widget_set_usize (hbox, -1, 24); - gtk_container_border_width (GTK_CONTAINER (hbox), 1); - gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, TRUE, 2); - - frame = gtk_frame_new ((char*)NULL); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0); - gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); - - hbox1 = gtk_hbox_new (FALSE, 0); - gtk_container_add (GTK_CONTAINER (frame), hbox1); - gtk_container_border_width (GTK_CONTAINER (hbox1), 0); - gtk_widget_show (hbox1); - - label = gtk_label_new (" Label "); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox1), label, FALSE, TRUE, 0); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_padding (GTK_MISC (label), 3, 0); - m_pStatusLabel[0] = label; - - for (int i = 1; i < 6; i++) - { - frame = gtk_frame_new ((char*)NULL); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0); - gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); - - label = gtk_label_new (" Label "); - gtk_widget_show (label); - gtk_container_add (GTK_CONTAINER (frame), label); - m_pStatusLabel[i] = label; - } -} - -guint s_idle_id; -static gint mainframe_idle (gpointer user_data) -{ - g_pParentWnd->RoutineProcessing (); - return TRUE; -} - -static void Sys_Iconify (GtkWidget *w); -static void Sys_Restore (GtkWidget *w); - -inline void CHECK_RESTORE(GtkWidget* w) -{ - if (g_object_get_data (G_OBJECT (w), "was_mapped") != NULL) - gtk_widget_show (w); -} - - -// this is called when the window is restored from the iconified state -static void mainframe_map (GtkWidget *widget) -{ - if (g_pParentWnd->IsSleeping ()) - g_pParentWnd->OnSleep (); - - if ((g_pParentWnd->CurrentStyle() == MainFrame::eFloating) && (widget == g_pParentWnd->m_pWidget)) - { - // restore previously visible windows - CHECK_RESTORE (g_pParentWnd->GetCamWnd ()->m_pParent); - if (g_PrefsDlg.m_bFloatingZ) - CHECK_RESTORE (g_pParentWnd->GetZWnd ()->m_pParent); - CHECK_RESTORE (g_pParentWnd->GetXYWnd ()->m_pParent); - CHECK_RESTORE (g_pParentWnd->GetXZWnd ()->m_pParent); - CHECK_RESTORE (g_pParentWnd->GetYZWnd ()->m_pParent); - CHECK_RESTORE (g_pGroupDlg->m_pWidget); - } -} - -inline void CHECK_MINIMIZE(GtkWidget* w) -{ - g_object_set_data (G_OBJECT (w), "was_mapped", (void*)(GTK_WIDGET_VISIBLE (w) != 0)); - gtk_widget_hide (w); -} - -static void mainframe_unmap (GtkWidget *widget) -{ - - if ((g_pParentWnd->CurrentStyle() == MainFrame::eFloating) && (widget == g_pParentWnd->m_pWidget)) - { - // minimize all other windows when the main window is minimized - CHECK_MINIMIZE (g_pParentWnd->GetCamWnd ()->m_pParent); - if (g_PrefsDlg.m_bFloatingZ) - CHECK_MINIMIZE (g_pParentWnd->GetZWnd ()->m_pParent); - CHECK_MINIMIZE (g_pParentWnd->GetXYWnd ()->m_pParent); - CHECK_MINIMIZE (g_pParentWnd->GetXZWnd ()->m_pParent); - CHECK_MINIMIZE (g_pParentWnd->GetYZWnd ()->m_pParent); - CHECK_MINIMIZE (g_pGroupDlg->m_pWidget); - } -} - -static GtkWidget* create_floating (MainFrame* mainframe) -{ - GtkWidget *wnd = gtk_window_new (GTK_WINDOW_TOPLEVEL); - //if (mainframe->CurrentStyle() != MainFrame::eFloating) - gtk_window_set_transient_for (GTK_WINDOW (wnd), GTK_WINDOW (mainframe->m_pWidget)); - gtk_widget_set_events (wnd, GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK); - gtk_signal_connect (GTK_OBJECT (wnd), "delete_event", GTK_SIGNAL_FUNC (widget_delete_hide), NULL); - gtk_signal_connect (GTK_OBJECT (wnd), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); - gtk_signal_connect (GTK_OBJECT (wnd), "key_press_event", - GTK_SIGNAL_FUNC (mainframe_keypress), mainframe); - gtk_signal_connect (GTK_OBJECT (wnd), "key_release_event", - GTK_SIGNAL_FUNC (mainframe_keyrelease), mainframe); - gtk_signal_connect (GTK_OBJECT (wnd), "map_event", - GTK_SIGNAL_FUNC (mainframe_map), mainframe); - - gtk_window_set_default_size (GTK_WINDOW (wnd), 100, 100); - -#ifdef DBG_WINDOWPOS - Sys_Printf("create_floating: %p, gtk_window_set_default_size 100, 100\n", wnd); -#endif - - return wnd; -} - -void console_populate_popup(GtkTextView* textview, GtkMenu* menu, gpointer user_data) -{ - menu_separator(GTK_WIDGET(menu)); - - GtkWidget* item = gtk_menu_item_new_with_label ("Clear"); - gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (Sys_ClearPrintf), NULL); - gtk_widget_show (item); - gtk_menu_append (GTK_MENU (menu), item); -} - -void console_construct(GtkWidget* textview) -{ - g_signal_connect(G_OBJECT(textview), "populate-popup", G_CALLBACK(console_populate_popup), NULL); -} - -extern MemStream g_Clipboard; - -void Clipboard_CopyMap() -{ - g_Clipboard.SetLength(0); - Map_Export (&g_Clipboard, "xmap", false, true); -} - -void Clipboard_PasteMap() -{ - if (g_Clipboard.GetLength() > 0) - { - g_Clipboard.Seek(0, SEEK_SET); - Map_Import(&g_Clipboard, "xmap", true); - } -} - -/*! -Platform-independent GTK clipboard support. -\todo Using GDK_SELECTION_CLIPBOARD fails on win32, so we use the win32 API directly for now. -*/ -#if defined (__linux__) || defined (__APPLE__) - -enum -{ - RADIANT_CLIPPINGS = 23, -}; - -static const GtkTargetEntry clipboard_targets[] = { - { "RADIANT_CLIPPINGS", 0, RADIANT_CLIPPINGS, }, -}; - -static void clipboard_get (GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, gpointer user_data_or_owner) -{ - guchar *buffer; - gint len; - GdkAtom type = GDK_NONE; - - len = g_Clipboard.GetLength(); - - if (!len) - { - buffer = NULL; - } else - { - buffer = g_Clipboard.GetBuffer (); - } - - if(info == clipboard_targets[0].info) - { - type = gdk_atom_intern(clipboard_targets[0].target, FALSE); - } - - gtk_selection_data_set (selection_data, type, 8, buffer, len); -} - -static void clipboard_clear (GtkClipboard *clipboard, gpointer user_data_or_owner) -{ -} - -static void clipboard_received (GtkClipboard *clipboard, GtkSelectionData *data, gpointer user_data) -{ - g_Clipboard.SetLength (0); - - if (data->length < 0) - Sys_FPrintf(SYS_ERR, "Error retrieving selection\n"); - else if(strcmp(gdk_atom_name(data->type), clipboard_targets[0].target) == 0) - g_Clipboard.Write (data->data, data->length); - - Clipboard_PasteMap(); -} - -void clipboard_copy() -{ - Clipboard_CopyMap(); - - GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); - - gtk_clipboard_set_with_data (clipboard, clipboard_targets, 1, clipboard_get, clipboard_clear, NULL); -} - -void clipboard_paste() -{ - GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); - - gtk_clipboard_request_contents (clipboard, gdk_atom_intern(clipboard_targets[0].target, FALSE), clipboard_received, NULL); -} - - -#elif defined(WIN32) - -void clipboard_copy() -{ - Clipboard_CopyMap(); - - bool bClipped = false; - UINT nClipboard = ::RegisterClipboardFormat("RadiantClippings"); - if (nClipboard > 0) - { - if (::OpenClipboard(NULL)) - { - EmptyClipboard(); - long lSize = g_Clipboard.GetLength(); - HANDLE h = ::GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, lSize + sizeof(long)); - if (h != NULL) - { - unsigned char *cp = reinterpret_cast(::GlobalLock(h)); - memcpy(cp, &lSize, sizeof(long)); - cp += sizeof(long); - g_Clipboard.Seek(0, SEEK_SET); - g_Clipboard.Read(cp, lSize); - ::GlobalUnlock(h); - ::SetClipboardData(nClipboard, h); - ::CloseClipboard(); - bClipped = true; - } - } - } - - if (!bClipped) - { - Sys_Printf("Unable to register Windows clipboard formats, copy/paste between editors will not be possible\n"); - } -} - -void clipboard_paste() -{ - bool bPasted = false; - UINT nClipboard = ::RegisterClipboardFormat("RadiantClippings"); - if (nClipboard > 0 && ::OpenClipboard(NULL)) - { - if(IsClipboardFormatAvailable(nClipboard)) - { - HANDLE h = ::GetClipboardData(nClipboard); - if (h) - { - g_Clipboard.SetLength(0); - unsigned char *cp = reinterpret_cast(::GlobalLock(h)); - long lSize = 0; - memcpy(&lSize, cp, sizeof(long)); - cp += sizeof(long); - g_Clipboard.Write(cp, lSize); - ::GlobalUnlock(h); - } - } - ::CloseClipboard(); - } - - Clipboard_PasteMap(); -} - -#endif - -void MainFrame::Copy() -{ - clipboard_copy(); -} - -void MainFrame::Paste() -{ - clipboard_paste(); - UpdateSurfaceDialog(); -} - - -#ifdef DBG_WINDOWPOS -GtkWidget *watchit = NULL; - -void CheckWatchit(char *msg) -{ - static int width = 0; - if ((watchit!=NULL) && (watchit->allocation.width != width)) - { - Sys_Printf("CheckWatchit %s: %d\n", msg, watchit->allocation.width); - width = watchit->allocation.width; - } -} -#endif - -#ifdef _WIN32 -BOOL CALLBACK m_pCountMonitor (HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -{ - int *n = (int *) dwData; - - (*n)++; - - return TRUE; -} - -struct monitorInfo_s { - GdkRectangle *win_monitors; - int i_win_mon; -}; - -BOOL CALLBACK m_pEnumMonitor (HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -{ - monitorInfo_s *monitorInfo = (monitorInfo_s *) dwData; - GdkRectangle *monitor; - MONITORINFOEX lpmi; - - monitor = monitorInfo->win_monitors + monitorInfo->i_win_mon; - - memset(&lpmi, 0, sizeof(MONITORINFOEX)); - lpmi.cbSize = sizeof(MONITORINFOEX); - - GetMonitorInfo( hMonitor, &lpmi ); - - if( lpmi.dwFlags & MONITORINFOF_PRIMARY ) { - RECT rect; - - SystemParametersInfo (SPI_GETWORKAREA, 0, &rect, 0); - monitor->x = rect.left; - monitor->y = rect.top; - monitor->width = rect.right - rect.left; - monitor->height = rect.bottom - rect.top; - - if (monitorInfo->i_win_mon != 0) - { - GdkRectangle temp = *monitor; - *monitor = monitorInfo->win_monitors[0]; - monitorInfo->win_monitors[0] = temp; - } - } else { - monitor->x = lpmi.rcMonitor.left; - monitor->y = lpmi.rcMonitor.top; - monitor->width = lpmi.rcMonitor.right - lpmi.rcMonitor.left; - monitor->height = lpmi.rcMonitor.bottom - lpmi.rcMonitor.top; - } - - monitorInfo->i_win_mon++; - - return TRUE; -} - -void PositionWindowOnPrimaryScreen(window_position_t& position) -{ - const GdkRectangle primaryMonitorRect = g_pParentWnd->GetPrimaryMonitorRect(); - - if( position.x <= primaryMonitorRect.x + 6 ) - position.x = primaryMonitorRect.x + 6; - else if( position.x >= ( primaryMonitorRect.x + primaryMonitorRect.width ) - 6 ) - position.x = primaryMonitorRect.x + 6; - - if( position.y <= primaryMonitorRect.y + 6 ) - position.y = primaryMonitorRect.y + 6; - else if( position.y >= ( primaryMonitorRect.y + primaryMonitorRect.height ) - 6 ) - position.y = primaryMonitorRect.y + 6; - - if( position.x + position.w >= ( primaryMonitorRect.x + primaryMonitorRect.width ) - 18 ) - position.w = primaryMonitorRect.width - 18; - if( position.y + position.h >= ( primaryMonitorRect.y + primaryMonitorRect.height ) - 18 ) - position.h = primaryMonitorRect.height - 18; -} -#endif - -GtkWidget* create_framed_widget(GtkWidget* widget) -{ - GtkWidget* frame = gtk_frame_new ((char*)NULL); - gtk_widget_show (frame); - gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); - gtk_container_add (GTK_CONTAINER (frame), widget); - gtk_widget_show(widget); - return frame; -} - -gboolean entry_focus_in(GtkWidget *widget, GdkEventFocus *event, gpointer user_data) -{ - gtk_window_remove_accel_group (GTK_WINDOW (g_pParentWnd->m_pWidget), global_accel); - return FALSE; -} - -gboolean entry_focus_out(GtkWidget *widget, GdkEventFocus *event, gpointer user_data) -{ - gtk_window_add_accel_group (GTK_WINDOW (g_pParentWnd->m_pWidget), global_accel); - return FALSE; -} - -GtkWidget* create_framed_texwnd(TexWnd* texwnd) -{ - GtkWidget* frame = gtk_frame_new ((char*)NULL); - gtk_widget_show (frame); - gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); - - GtkWidget* hbox = gtk_hbox_new (FALSE, 0); - gtk_widget_show (hbox); - gtk_container_add (GTK_CONTAINER (frame), hbox); - - GtkWidget* w = gtk_vscrollbar_new (GTK_ADJUSTMENT (gtk_adjustment_new (0,0,0,1,1,1))); - gtk_widget_show (w); - gtk_box_pack_end (GTK_BOX (hbox), w, FALSE, TRUE, 0); - g_qeglobals_gui.d_texture_scroll = w; - - GtkWidget* texbox = gtk_vbox_new (FALSE, 0); - gtk_widget_show (texbox); - gtk_box_pack_start (GTK_BOX (hbox), texbox, TRUE, TRUE, 0); - - w = gtk_entry_new (); - gtk_box_pack_start (GTK_BOX (texbox), w, FALSE, FALSE, 0); - texwnd->m_pFilter = w; - g_signal_connect(G_OBJECT(w), "focus_in_event", G_CALLBACK(entry_focus_in), NULL); - g_signal_connect(G_OBJECT(w), "focus_out_event", G_CALLBACK(entry_focus_out), NULL); - - w = texwnd->GetWidget (); - gtk_box_pack_start (GTK_BOX (texbox), w, TRUE, TRUE, 0); - gtk_widget_show (w); - - return frame; -} - -static ZWnd *create_floating_zwnd(MainFrame *mainframe) -{ - ZWnd *pZWnd = new ZWnd (); - GtkWidget* wnd = create_floating (mainframe); - - gtk_window_set_title (GTK_WINDOW (wnd), "Z"); - - pZWnd->m_pParent = wnd; - - { - GtkWidget* frame = create_framed_widget(pZWnd->GetWidget()); - gtk_container_add (GTK_CONTAINER (wnd), frame); - } - - gtk_widget_realize (wnd); - - // turn OFF minimize and maximize boxes. - // Must be *after* realize, or wnd->window is NULL - // should do the right thing on *nix, need to verify. - gdk_window_set_decorations ( wnd->window, - GdkWMDecoration(GDK_DECOR_ALL | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE ) ); - //TODO 50 by observation, will vary depending on decoration sizes - { - GdkGeometry geometry; - geometry.min_width = 50; - //we only care about width, but have to set this too, or get nasty bugs - geometry.min_height = 10; - gdk_window_set_geometry_hints( wnd->window,&geometry,GDK_HINT_MIN_SIZE); - } - -#ifdef _WIN32 - if( g_PrefsDlg.m_bStartOnPrimMon ) { - PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.posZWnd ); - } -#endif - load_window_pos (wnd, g_PrefsDlg.mWindowInfo.posZWnd); - - if (g_PrefsDlg.m_bZVis) - gtk_widget_show (wnd); - - return pZWnd; -} - -static const int gutter = 12; - -void MainFrame::Create () -{ - GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - m_pWidget = window; - gtk_widget_set_events (window, GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK); - gtk_signal_connect (GTK_OBJECT (window), "delete_event", - GTK_SIGNAL_FUNC (mainframe_delete), this); - gtk_signal_connect (GTK_OBJECT (window), "destroy", - GTK_SIGNAL_FUNC (mainframe_destroy), this); - gtk_signal_connect (GTK_OBJECT (window), "key_press_event", - GTK_SIGNAL_FUNC (mainframe_keypress), this); - gtk_signal_connect (GTK_OBJECT (window), "key_release_event", - GTK_SIGNAL_FUNC (mainframe_keyrelease), this); - gtk_signal_connect (GTK_OBJECT (window), "map_event", - GTK_SIGNAL_FUNC (mainframe_map), this); - gtk_signal_connect (GTK_OBJECT (window), "unmap_event", - GTK_SIGNAL_FUNC (mainframe_unmap), this); - - g_qeglobals_gui.d_main_window = window; - -#ifdef _WIN32 - // calculate gdk offset - int n_win_monitors = 0; - - monitorInfo_s monitorInfo; - - // detect multiple monitors - EnumDisplayMonitors (NULL, NULL, m_pCountMonitor, reinterpret_cast(&n_win_monitors)); - - monitorInfo.win_monitors = new GdkRectangle [ n_win_monitors ]; - monitorInfo.i_win_mon = 0; - EnumDisplayMonitors (NULL, NULL, m_pEnumMonitor, reinterpret_cast(&monitorInfo)); - - gdk_offset_x = G_MININT; - gdk_offset_y = G_MININT; - - // calculate offset - for( monitorInfo.i_win_mon = 0; monitorInfo.i_win_mon < n_win_monitors; monitorInfo.i_win_mon++ ) { - gdk_offset_x = MAX (gdk_offset_x, -monitorInfo.win_monitors[monitorInfo.i_win_mon].x); - gdk_offset_y = MAX (gdk_offset_y, -monitorInfo.win_monitors[monitorInfo.i_win_mon].y); - } - - Sys_Printf( "GDK's coordinate system is offset by %d over the x-axis and %d over the y-axis from Windows' coordinate system.\n", gdk_offset_x, gdk_offset_y ); - - if( g_PrefsDlg.m_bStartOnPrimMon ) - { - // get gdk monitors - GdkDisplay *display; - GdkScreen *screen; - gint n_gdk_monitors = 0; - gint i_mon; - GdkRectangle rect; - - // detect multiple monitors - display = gdk_display_get_default (); - Sys_Printf( "GDK detects that server %s manages %d screens\n", gdk_display_get_name (display), gdk_display_get_n_screens (display) ); - - screen = gdk_display_get_screen( display, 1 ); - n_gdk_monitors = gdk_screen_get_n_monitors( screen ); - - Sys_Printf( "GDK detects that screen 1 has %d monitors\n", n_gdk_monitors ); - - for( i_mon = 0; i_mon < n_gdk_monitors; i_mon++ ) { - memset( &rect, 0, sizeof(rect) ); - gdk_screen_get_monitor_geometry( screen, i_mon, &rect ); - Sys_Printf( " monitor %d: x: %d y: %d w: %d h: %d\n", i_mon, rect.x, rect.y, rect.width, rect.height ); - - if( i_mon == 0 ) { - memcpy( &primaryMonitorRect, &rect, sizeof(primaryMonitorRect) ); - } - } - - PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.position ); - } - else { - primaryMonitorRect.x = primaryMonitorRect.y = 0; - primaryMonitorRect.width = gdk_screen_width (); - primaryMonitorRect.height = gdk_screen_height (); - } - -#endif - - load_window_pos(window, g_PrefsDlg.mWindowInfo.position); - - GtkWidget* vbox = gtk_vbox_new (FALSE, 0); - gtk_container_add (GTK_CONTAINER (window), vbox); - gtk_widget_show (vbox); - - create_main_menu (window, vbox); - MRU_Load (); - create_main_toolbar (window, vbox); - create_plugin_toolbar (window,vbox); - - m_nCurrentStyle = g_PrefsDlg.m_nView; - - g_pGroupDlg->Create (); - OnPluginsRefresh(); - - CreateQEChildren(); - - gtk_widget_show (window); - - // not needed on win32, it's in the .rc -#ifndef _WIN32 - { - GdkPixmap *pixmap; - GdkBitmap *mask; - load_pixmap ("icon.bmp", window, &pixmap, &mask); - gdk_window_set_icon (window->window, NULL, pixmap, mask); - } -#endif - - if (CurrentStyle() == eRegular || CurrentStyle() == eRegularLeft) - { - { - GtkWidget* vsplit = gtk_vpaned_new (); - m_pSplits[0] = vsplit; - gtk_box_pack_start (GTK_BOX (vbox), vsplit, TRUE, TRUE, 0); - gtk_widget_show (vsplit); - - { - GtkWidget* hsplit = gtk_hpaned_new (); - m_pSplits[2] = hsplit; - gtk_paned_add1 (GTK_PANED (vsplit), hsplit); - gtk_widget_show (hsplit); - - { - GtkWidget* hsplit2 = gtk_hpaned_new (); - m_pSplits[3] = hsplit2; - gtk_paned_add2 (GTK_PANED (hsplit), hsplit2); - gtk_widget_show (hsplit2); - - { - GtkWidget* vsplit2 = gtk_vpaned_new (); - m_pSplits[1] = vsplit2; - if (CurrentStyle() == eRegular) - gtk_paned_add2 (GTK_PANED (hsplit2), vsplit2); - else - gtk_paned_add1 (GTK_PANED (hsplit), vsplit2); - gtk_widget_show (vsplit2); - - // camera - m_pCamWnd = new CamWnd (); - { - GtkWidget* frame = create_framed_widget(m_pCamWnd->GetWidget()); - gtk_paned_add1 (GTK_PANED (vsplit2), frame); - } - - // xy - m_pXYWnd = new XYWnd (); - m_pXYWnd->SetViewType(XY); - { - GtkWidget* frame = create_framed_widget(m_pXYWnd->GetWidget ()); - gtk_paned_add1 (GTK_PANED (hsplit2), frame); - } - - // z - m_pZWnd = new ZWnd (); - { - GtkWidget* frame = create_framed_widget(m_pZWnd->GetWidget ()); - if (CurrentStyle() == eRegular) - gtk_paned_add1 (GTK_PANED (hsplit), frame); - else - gtk_paned_add2 (GTK_PANED (hsplit2), frame); - } - - // textures - m_pTexWnd = new TexWnd (); - { - GtkWidget* frame = create_framed_texwnd(m_pTexWnd); - gtk_paned_add2 (GTK_PANED (vsplit2), frame); - } - - // console - { - GtkWidget* scr = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); - gtk_widget_show (scr); - gtk_paned_pack2 (GTK_PANED (vsplit), scr, FALSE, TRUE); - - { - GtkWidget* text = gtk_text_view_new (); - gtk_widget_set_size_request(text, 0, -1); // allow shrinking - gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD); - gtk_text_view_set_editable (GTK_TEXT_VIEW(text), FALSE); - gtk_container_add (GTK_CONTAINER (scr), text); - gtk_widget_show (text); - g_qeglobals_gui.d_edit = text; - } - } - } - } - } - } - - gtk_paned_set_position (GTK_PANED (m_pSplits[0]), g_PrefsDlg.mWindowInfo.nXYHeight+28); - - if (CurrentStyle() == eRegular) - { - gtk_paned_set_position (GTK_PANED (m_pSplits[2]), g_PrefsDlg.mWindowInfo.nZWidth); - gtk_paned_set_position (GTK_PANED (m_pSplits[3]), g_PrefsDlg.mWindowInfo.nXYWidth); - } - else - { - gtk_paned_set_position (GTK_PANED (m_pSplits[2]), g_PrefsDlg.mWindowInfo.nCamWidth); - while (gtk_events_pending ()) gtk_main_iteration (); - gtk_paned_set_position (GTK_PANED (m_pSplits[3]), g_PrefsDlg.mWindowInfo.nXYWidth); - } - - while (gtk_events_pending ()) gtk_main_iteration (); - - gtk_paned_set_position (GTK_PANED (m_pSplits[1]), g_PrefsDlg.mWindowInfo.nCamHeight); - } - else if (CurrentStyle() == eFloating) - { - { - GtkWidget* wnd = create_floating (this); - gtk_window_set_title (GTK_WINDOW (wnd), "Camera"); - -#ifdef _WIN32 - if( g_PrefsDlg.m_bStartOnPrimMon ) { - PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.posCamWnd ); - } -#endif - load_window_pos (wnd, g_PrefsDlg.mWindowInfo.posCamWnd); - - gtk_widget_show (wnd); - - m_pCamWnd = new CamWnd (); - - { - GtkWidget* frame = create_framed_widget(m_pCamWnd->GetWidget ()); - gtk_container_add (GTK_CONTAINER (wnd), frame); - } - - m_pCamWnd->m_pParent = wnd; - } - - if (g_PrefsDlg.m_bFloatingZ) - { - m_pZWnd = create_floating_zwnd(this); - - { - GtkWidget* wnd = create_floating (this); - gtk_window_set_title (GTK_WINDOW (wnd), "XY View"); - -#ifdef _WIN32 - if( g_PrefsDlg.m_bStartOnPrimMon ) { - PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.posXYWnd ); - } -#endif - load_window_pos (wnd, g_PrefsDlg.mWindowInfo.posXYWnd); - - m_pXYWnd = new XYWnd (); - m_pXYWnd->SetViewType(XY); - - { - GtkWidget* frame = create_framed_widget(m_pXYWnd->GetWidget()); - gtk_container_add (GTK_CONTAINER (wnd), frame); - } - - m_pXYWnd->m_pParent = wnd; - - gtk_widget_show (wnd); - } - } - else - { - GtkWidget* wnd = create_floating (this); - gtk_window_set_title (GTK_WINDOW (wnd), "XY View"); - -#ifdef _WIN32 - if( g_PrefsDlg.m_bStartOnPrimMon ) { - PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.posXYWnd ); - } -#endif - load_window_pos (wnd, g_PrefsDlg.mWindowInfo.posXYWnd); - - m_pZWnd = new ZWnd (); - m_pZWnd->m_pParent = wnd; - - m_pXYWnd = new XYWnd (); - m_pXYWnd->SetViewType(XY); - m_pXYWnd->m_pParent = wnd; - - - { - GtkWidget* hsplit = gtk_hpaned_new (); - m_pSplits[0] = hsplit; - gtk_container_add (GTK_CONTAINER (wnd), hsplit); - gtk_widget_show (hsplit); - - { - GtkWidget* frame = create_framed_widget(m_pZWnd->GetWidget()); - gtk_paned_add1 (GTK_PANED (hsplit), frame); - } - { - GtkWidget* frame = create_framed_widget(m_pXYWnd->GetWidget()); - gtk_paned_add2 (GTK_PANED (hsplit), frame); - } - } - - gtk_widget_show (wnd); - - gtk_paned_set_position (GTK_PANED (m_pSplits[0]), g_PrefsDlg.mWindowInfo.nZFloatWidth); - } - - { - GtkWidget* wnd = create_floating (this); - gtk_window_set_title (GTK_WINDOW (wnd), "XZ View"); - -#ifdef _WIN32 - if( g_PrefsDlg.m_bStartOnPrimMon ) { - PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.posXZWnd ); - } -#endif - load_window_pos (wnd, g_PrefsDlg.mWindowInfo.posXZWnd); - - m_pXZWnd = new XYWnd (); - m_pXZWnd->m_pParent = wnd; - m_pXZWnd->SetViewType(XZ); - - { - GtkWidget* frame = create_framed_widget(m_pXZWnd->GetWidget()); - gtk_container_add (GTK_CONTAINER (wnd), frame); - } - - if (g_PrefsDlg.m_bXZVis) - gtk_widget_show (wnd); - } - - { - GtkWidget* wnd = create_floating (this); - gtk_window_set_title (GTK_WINDOW (wnd), "YZ View"); - -#ifdef _WIN32 - if( g_PrefsDlg.m_bStartOnPrimMon ) { - PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.posYZWnd ); - } -#endif - load_window_pos (wnd, g_PrefsDlg.mWindowInfo.posYZWnd); - - m_pYZWnd = new XYWnd (); - m_pYZWnd->m_pParent = wnd; - m_pYZWnd->SetViewType(YZ); - - { - GtkWidget* frame = create_framed_widget(m_pYZWnd->GetWidget()); - gtk_container_add (GTK_CONTAINER (wnd), frame); - } - - if (g_PrefsDlg.m_bYZVis) - gtk_widget_show (wnd); - } - - m_pTexWnd = new TexWnd (); - { - GtkWidget* frame = create_framed_texwnd(m_pTexWnd); - m_pTexWnd->m_pParent = g_pGroupDlg->m_pWidget; - - { - GtkWidget* w = gtk_label_new ("Textures"); - gtk_widget_show (w); - gtk_notebook_insert_page (GTK_NOTEBOOK (g_pGroupDlg->m_pNotebook), frame, w, 1); - } - } - - g_pGroupDlg->Show (); - } - else // 4 way - { - { - GtkWidget* hsplit = gtk_hpaned_new (); - m_pSplits[0] = hsplit; - gtk_box_pack_start (GTK_BOX (vbox), hsplit, TRUE, TRUE, 0); - gtk_widget_show (hsplit); - - { - GtkWidget* vsplit1 = gtk_vpaned_new (); - m_pSplits[1] = vsplit1; - gtk_paned_add1 (GTK_PANED (hsplit), vsplit1); - gtk_widget_show (vsplit1); - - { - GtkWidget* vsplit2 = gtk_vpaned_new (); - m_pSplits[2] = vsplit2; - gtk_paned_add2 (GTK_PANED (hsplit), vsplit2); - gtk_widget_show (vsplit2); - - m_pCamWnd = new CamWnd (); - { - GtkWidget* frame = create_framed_widget(m_pCamWnd->GetWidget()); - gtk_paned_add1 (GTK_PANED (vsplit1), frame); - } - - m_pXYWnd = new XYWnd (); - m_pXYWnd->SetViewType(XY); - { - GtkWidget* frame = create_framed_widget(m_pXYWnd->GetWidget()); - gtk_paned_add1 (GTK_PANED (vsplit2), frame); - } - - m_pYZWnd = new XYWnd (); - m_pYZWnd->SetViewType(YZ); - { - GtkWidget* frame = create_framed_widget(m_pYZWnd->GetWidget()); - gtk_paned_add2 (GTK_PANED (vsplit1), frame); - } - - m_pXZWnd = new XYWnd (); - m_pXZWnd->SetViewType(XZ); - { - GtkWidget* frame = create_framed_widget(m_pXZWnd->GetWidget()); - gtk_paned_add2 (GTK_PANED (vsplit2), frame); - } - } - } - } - - // g_qeglobals_gui.d_edit = NULL; - - { - m_pTexWnd = new TexWnd (); - GtkWidget* frame = create_framed_texwnd(m_pTexWnd); - - { - GtkWidget* w = gtk_label_new ("Textures"); - gtk_widget_show (w); - gtk_notebook_insert_page (GTK_NOTEBOOK (g_pGroupDlg->m_pNotebook), frame, w, 1); - } - } - - m_pTexWnd->m_pParent = g_pGroupDlg->m_pWidget; -// gtk_widget_realize (m_pTexWnd->GetWidget ()); - m_pZWnd = create_floating_zwnd(this); - - while (gtk_events_pending ()) - gtk_main_iteration (); - - { - int x = GTK_PANED (m_pSplits[0])->max_position/2 - gutter; - gtk_paned_set_position (GTK_PANED (m_pSplits[0]), x); - } - - { - int y = GTK_PANED (m_pSplits[1])->max_position/2 - gutter; - gtk_paned_set_position (GTK_PANED (m_pSplits[1]), y); - gtk_paned_set_position (GTK_PANED (m_pSplits[2]), y); - } - } - - if(g_PrefsDlg.mWindowInfo.nState & GDK_WINDOW_STATE_MAXIMIZED) - gtk_window_maximize(GTK_WINDOW(window)); - - gtk_widget_show (window); - - Texture_Init(); - - if (m_pXYWnd) // this is always true? - { - m_pXYWnd->SetActive(true); - } - m_bSplittersOK = true; - Texture_SetMode(g_qeglobals.d_savedinfo.iTexMenu); - - g_pParentWnd->OnEntitiesSetViewAs(0); - -// m_wndTextureBar.Create (vbox); - create_main_statusbar (window, vbox); - - LoadCommandMap(); - ShowMenuItemKeyBindings(window); - - if (g_qeglobals_gui.d_edit != NULL) - console_construct(g_qeglobals_gui.d_edit); - - // bool load_last = FALSE; - - SetGridStatus(); - SetButtonMenuStates(); - - // m_bShowShader and m_bTextureShaderlistOnly have a menu checkbox, update it now - GtkWidget *item; - g_bIgnoreCommands++; - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_shaders_show")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bShowShaders ? TRUE : FALSE); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_shaderlistonly")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bTexturesShaderlistOnly ? TRUE : FALSE); - g_bIgnoreCommands--; - -// if (g_PrefsDlg.m_bTextureBar) -// gtk_widget_show (m_wndTextureBar.m_pWidget); - - SetActiveXY(m_pXYWnd); - - s_idle_id = gtk_timeout_add (25, mainframe_idle, this); - - QGL_InitExtensions (); - - if (g_PrefsDlg.mLocalPrefs.mbEmpty) - { - g_PrefsDlg.mLocalPrefs.mbEmpty = false; - g_PrefsDlg.SavePrefs(); - } - - // remove the pid file - remove (g_pidGameFile.GetBuffer ()); - - Sys_Printf ("Entering message loop\n"); - - m_bDoLoop = true; - - m_nTimer = gtk_timeout_add (1000, timer, this); -} - -// ============================================================================= -// MainFrame class - -MainFrame::MainFrame() -{ - m_bDoLoop = false; - m_bSplittersOK = false; - g_pParentWnd = this; - m_pXYWnd = (XYWnd*)NULL; - m_pCamWnd = NULL; - m_pTexWnd = (TexWnd*)NULL; - m_pZWnd = (ZWnd*)NULL; - m_pYZWnd = (XYWnd*)NULL; - m_pXZWnd = (XYWnd*)NULL; - m_pActiveXY = (XYWnd*)NULL; - m_bCamPreview = true; - m_pWatchBSP = NULL; - for (int n = 0; n < 6; n++) - m_pStatusLabel[n] = NULL; - m_bNeedStatusUpdate = false; - m_nTimer = 0; - m_bSleeping = false; - Create (); -} - -MainFrame::~MainFrame() -{ - while (g_BSPFrontendCommands) - { - free (g_BSPFrontendCommands->data); - g_BSPFrontendCommands = g_slist_remove (g_BSPFrontendCommands, g_BSPFrontendCommands->data); - } -} - -void MainFrame::ReleaseContexts () -{ - if (m_pXYWnd) - m_pXYWnd->DestroyContext (); - if (m_pYZWnd) - m_pYZWnd->DestroyContext (); - if (m_pXZWnd) - m_pXZWnd->DestroyContext (); - if (m_pCamWnd) - m_pCamWnd->DestroyContext (); - if (m_pTexWnd) - m_pTexWnd->DestroyContext (); - if (m_pZWnd) - m_pZWnd->DestroyContext (); -} - -void MainFrame::CreateContexts () -{ - if (m_pCamWnd) - m_pCamWnd->CreateContext (); - if (m_pXYWnd) - m_pXYWnd->CreateContext (); - if (m_pYZWnd) - m_pYZWnd->CreateContext (); - if (m_pXZWnd) - m_pXZWnd->CreateContext (); - if (m_pTexWnd) - m_pTexWnd->CreateContext (); - if (m_pZWnd) - m_pZWnd->CreateContext (); -} - -static void Sys_Iconify (GtkWidget *w) -{ - // we might not have been realized yet - if (w->window == NULL) - return; - - if (!GTK_WIDGET_MAPPED (w)) - return; - -#if defined (__linux__) || defined (__APPLE__) - Sys_FPrintf(SYS_WRN, "FIXME: Sys_Iconify\n"); -#if 0 - XWindowAttributes xattr; - GdkWindowPrivate *Private; - - Private = (GdkWindowPrivate*)w->window; - g_object_set_data (G_OBJECT (w), "was_mapped", GINT_TO_POINTER (0)); - - if (!Private->destroyed) - { - xattr.map_state = IsUnmapped; - XGetWindowAttributes(Private->xdisplay, Private->xwindow, &xattr); - - if (xattr.map_state != IsUnmapped) - g_object_set_data (G_OBJECT (w), "was_mapped", GINT_TO_POINTER (1)); - - XIconifyWindow (Private->xdisplay, Private->xwindow, 0); - } -#endif -#endif - -#ifdef _WIN32 - ShowWindow ((HWND)GDK_WINDOW_HWND (w->window), SW_MINIMIZE); -#endif -} - -static void Sys_Restore (GtkWidget *w) -{ - // we might not have been realized yet - if (w->window == NULL) - return; - - if (!GTK_WIDGET_VISIBLE (w)) - return; - -#if defined (__linux__) || defined (__APPLE__) - Sys_FPrintf(SYS_WRN, "FIXME: Sys_Restore\n"); - #if 0 - XWindowAttributes xattr; - GdkWindowPrivate *Private; - - Private = (GdkWindowPrivate*)w->window; - - xattr.map_state = IsUnmapped; - XGetWindowAttributes(Private->xdisplay, Private->xwindow, &xattr); - - if (xattr.map_state == IsUnmapped) - XMapRaised (Private->xdisplay, Private->xwindow); - #endif -#endif - -#ifdef _WIN32 - ShowWindow ((HWND)GDK_WINDOW_HWND (w->window), SW_RESTORE); -#endif -} - -#ifdef _DEBUG -//#define DBG_SLEEP -#endif - -void RefreshModelSkin (GSList **pModels, entitymodel_t *model) -{ - //++timo FIXME: the are some bogus entitymodel_t that appear in the list cause of buggy HasModel - // so we avoid the fucked up ones, assuming they are at the end - if (!model->strSkin) - { -#ifdef DBG_SLEEP - Sys_Printf("Dropping model %p with empty skin in RefreshModelSkin\n", model); -#endif - - // and also keeping it so we have an actual count of empty models - g_slist_append (*pModels, model); - return; - } - // do we have this model already? - if (g_slist_find (*pModels, model)) - { -#ifdef DBG_SLEEP - - // looks like we don't have the filename for the model, only the skin name and tris.. so we put the adress - Sys_Printf("Already processed model: %p %s\n", model, ((GString *)model->strSkin)->str); -#endif - return; - } - model->nTextureBind = Texture_LoadSkin(((GString *)model->strSkin)->str, &model->nSkinWidth, &model->nSkinHeight ); - if (model->nTextureBind != -1) - Sys_Printf("LOADED SKIN: %s\n", ((GString *)model->strSkin)->str ); - else - Sys_Printf("Load skin failed: %s\n", ((GString *)model->strSkin)->str ); - *pModels = g_slist_append (*pModels, model); -#ifdef DBG_SLEEP - Sys_Printf("Processed model %p %s\n", model, ((GString *)model->strSkin)->str); -#endif -} - -void MainFrame::OnSleep() -{ - m_bSleeping ^= 1; - if (m_bSleeping) - { - // useful when trying to debug crashes in the sleep code - Sys_Printf("Going into sleep mode..\n"); - - Sys_Printf("Dispatching sleep msg..."); - DispatchRadiantMsg (RADIANT_SLEEP); - Sys_Printf("Done.\n"); - - if (CurrentStyle() == eSplit) - Sys_Iconify (m_pZWnd->m_pParent); - - Sys_Iconify (m_pWidget); - Select_Deselect(); - QERApp_FreeShaders (); - g_bScreenUpdates = false; - - // release contexts - Sys_Printf("Releasing contexts..."); - ReleaseContexts(); - Sys_Printf("Done.\n"); - - // free all the skins in the caches - // their GL resources have been freed but the structs are not, so Radiant would think they are still valid - g_lstSkinCache.RemoveAll(); - } else - { - Sys_Printf("Waking up\n"); - if (CurrentStyle() == eSplit) - Sys_Restore (m_pZWnd->m_pParent); - - Sys_Restore (m_pWidget); - - // create contexts - Sys_Printf("Creating contexts..."); - CreateContexts(); - Sys_Printf("Done.\n"); - - Sys_Printf("Making current on camera..."); - m_pCamWnd->MakeCurrent (); - Sys_Printf("Done.\n"); - - Sys_Printf("Reloading shaders..."); - // reload the shader scripts and textures - QERApp_ReloadShaders (); - // current shader - // NOTE: we are kinda making it loop on itself, it will update the pShader and scroll the texture window - Texture_SetTexture (&g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef, false, NULL, false); - Sys_Printf("Done.\n"); - - // rebuild the patches by setting the bDirty flag on them - for (brush_t* b=active_brushes.next ; b != &active_brushes ; b=b->next) - { - if (b->patchBrush) - b->pPatch->bDirty = true; - } - - Sys_Printf("Reloading skins..."); - // we have purged all the skins before going to sleep - // to rebuild, go through everything that needs a skin and call Texture_LoadSkin - // namely, all entitymodel_t - // since there's no direct list we go through entities to get the eclass_t and from there the entitymodel_t - // (a single eclass_t can reference several entitymodel_t) - // FIXME: and what's up with md3Class then? what is it used for? -/* - eclass_t *e; - entity_t *ent; - GSList *Models = NULL; - for (ent = entities.next; ent != &entities; ent = ent->next) - { - // if it's a model with skin then the fixedsize flag must be on - // only if there IS a model .. we are not trying to load - if (ent->eclass->fixedsize) - { - if (ent->eclass->model) - { -#ifdef DBG_SLEEP - if (ent->md3Class) - Sys_Printf("WARNING: unexpected ent->md3Class!=NULL with ent->eclass->model!=NULL\n"); -#endif - entitymodel_t *model; - for (model = ent->eclass->model; model; model=model->pNext) - RefreshModelSkin (&Models, model); - } else if (ent->md3Class) - { - entitymodel_t *model; - for (model = ent->md3Class->model; model; model=model->pNext) - RefreshModelSkin (&Models, model); - } -#ifdef DBG_SLEEP - else - Sys_Printf("WARNING: entity %p %s with fixedsize and no model no md3Class\n", ent, ent->eclass->name); -#endif - } - } -#ifdef DBG_SLEEP - for (e = g_md3Cache; e ; e = e->next) - { - entitymodel_t *model; - for (model = e->model; model; model=model->pNext) - if (!g_slist_find (Models, model)) - { - Sys_Printf("model %p ", model); - if (model->strSkin) - Sys_Printf("%s not found in main loop\n", ((GString *)model->strSkin)->str); - else - Sys_Printf("not found in main loop (no skin)\n"); - } - } -#endif - // clean the model list - g_slist_free (Models); -*/ - Sys_Printf("Done.\n"); - - // bring back the GL font - gtk_glwidget_create_font (m_pCamWnd->GetWidget ()); - - g_bScreenUpdates = true; - - Sys_Printf("Dispatching wake msg..."); - DispatchRadiantMsg (RADIANT_WAKEUP); - Sys_Printf("Done\n"); - } -} - -void WINAPI QERApp_Sleep() -{ - g_pParentWnd->OnSleep(); -} - -/*! -NOTE TTimo -the exit path is a bit complicated, I guess we have to run the window pos saving in OnDelete -and not in OnDestroy because the info may be lost already? -\todo try sinking OnDelete into OnDestroy and see if it breaks anything -*/ -void MainFrame::OnDelete () -{ - save_window_pos(m_pWidget, g_PrefsDlg.mWindowInfo.position); - - // surface inspector and patch inspector - save_window_pos (g_dlgSurface.GetWidget(), g_PrefsDlg.mWindowInfo.posSurfaceWnd); - save_window_pos (g_PatchDialog.GetWidget(), g_PrefsDlg.mWindowInfo.posPatchWnd); - - // entity inspector / group dialog - // NOTE TTimo do we have to save a different window depending on the view mode? - save_window_pos (g_pGroupDlg->m_pWidget, g_PrefsDlg.mWindowInfo.posEntityWnd); - - if (g_PrefsDlg.m_bFloatingZ) - save_window_pos (m_pZWnd->m_pParent, g_PrefsDlg.mWindowInfo.posZWnd); - else - g_PrefsDlg.mWindowInfo.nZFloatWidth = GTK_PANED (m_pSplits[0])->child1_size; - - if (CurrentStyle() == eFloating) - { - save_window_pos (m_pCamWnd->m_pParent, g_PrefsDlg.mWindowInfo.posCamWnd); - save_window_pos (m_pXYWnd->m_pParent, g_PrefsDlg.mWindowInfo.posXYWnd); - save_window_pos (m_pXZWnd->m_pParent, g_PrefsDlg.mWindowInfo.posXZWnd); - save_window_pos (m_pYZWnd->m_pParent, g_PrefsDlg.mWindowInfo.posYZWnd); - } - - g_PrefsDlg.mWindowInfo.nState = gdk_window_get_state(g_pParentWnd->m_pWidget->window); -} - -void MainFrame::OnDestroy () -{ - // shut down console output first - // (we'll still get the info if we are running a log file anyway) - g_qeglobals_gui.d_edit = NULL; - -#ifdef _DEBUG - Sys_Printf("MainFrame::OnDestroy\n"); -#endif - if (s_idle_id) - gtk_timeout_remove (s_idle_id); - if (m_nTimer) - gtk_timeout_remove (m_nTimer); - - if (!g_qeglobals.disable_ini) - { - Sys_Printf("Start writing prefs\n"); - Sys_Printf("MRU_Save... "); - MRU_Save (); - Sys_Printf("OK\n"); - - gpointer w; - - w = g_object_get_data (G_OBJECT (g_pGroupDlg->m_pWidget), "split1"); - g_PrefsDlg.mWindowInfo.nEntitySplit1 = GTK_PANED (w)->child1_size; - w = g_object_get_data (G_OBJECT (g_pGroupDlg->m_pWidget), "split2"); - g_PrefsDlg.mWindowInfo.nEntitySplit2 = GTK_PANED (w)->child1_size; - - if (!FloatingGroupDialog()) - { - GtkWidget *vsplit, *hsplit, *vsplit2, *hsplit2; - - vsplit = m_pSplits[0]; - vsplit2 = m_pSplits[1]; - hsplit = m_pSplits[2]; - hsplit2 = m_pSplits[3]; - - g_PrefsDlg.mWindowInfo.nXYHeight = GTK_PANED (vsplit)->child1_size; - g_PrefsDlg.mWindowInfo.nXYWidth = GTK_PANED (hsplit2)->child1_size; - - if(CurrentStyle() == eRegular) - g_PrefsDlg.mWindowInfo.nZWidth = GTK_PANED (hsplit)->child1_size; - else - g_PrefsDlg.mWindowInfo.nCamWidth = GTK_PANED (hsplit)->child1_size; - - g_PrefsDlg.mWindowInfo.nCamHeight = GTK_PANED (vsplit2)->child1_size; - } else - { - if (g_PrefsDlg.m_bFloatingZ || CurrentStyle() == eSplit) - { - if (GTK_WIDGET_VISIBLE (m_pZWnd->m_pParent)) - g_PrefsDlg.m_bZVis = TRUE; - else - g_PrefsDlg.m_bZVis = FALSE; - } - } - g_PrefsDlg.SavePrefs(); - Sys_Printf("Done prefs\n"); - } - - // spog - this may be better in another place.. - // deletes filters list and assigns g_qeglobals.d_savedinfo.filters = NULL - g_qeglobals.d_savedinfo.filters = FilterListDelete(g_qeglobals.d_savedinfo.filters); - - delete m_pXYWnd; m_pXYWnd = NULL; - delete m_pYZWnd; m_pYZWnd = NULL; - delete m_pXZWnd; m_pXZWnd = NULL; - delete m_pZWnd; m_pZWnd = NULL; - delete m_pTexWnd; m_pTexWnd = NULL; - delete m_pCamWnd; m_pCamWnd = NULL; - - if (g_pGroupDlg->m_pWidget) - { - //!\todo fix "Gtk-CRITICAL **: file gtknotebook.c: line 4643 (gtk_notebook_get_tab_label): assertion `GTK_IS_WIDGET (child)' failed" - gtk_widget_destroy (g_pGroupDlg->m_pWidget); - g_pGroupDlg->m_pWidget = NULL; - } - - if (strcmpi(currentmap, "unnamed.map") != 0) - { - g_PrefsDlg.m_strLastMap = currentmap; - g_PrefsDlg.SavePrefs (); - } - Sys_Printf("CleanUpEntities..."); - CleanUpEntities(); - Sys_Printf("Done.\n"); - - Sys_Printf("Releasing brushes..."); - while (active_brushes.next != &active_brushes) - Brush_Free (active_brushes.next, false); - while (selected_brushes.next != &selected_brushes) - Brush_Free (selected_brushes.next, false); - while (filtered_brushes.next != &filtered_brushes) - Brush_Free (filtered_brushes.next, false); - Sys_Printf("Done.\n"); - - Sys_Printf("Releasing entities..."); - while (entities.next != &entities) - Entity_Free (entities.next); - Sys_Printf("Done.\n"); - - epair_t* pEPair = g_qeglobals.d_project_entity->epairs; - while (pEPair) - { - epair_t* pNextEPair = pEPair->next; - free (pEPair->key); - free (pEPair->value); - free (pEPair); - pEPair = pNextEPair; - } - - entity_t* pEntity = g_qeglobals.d_project_entity->next; - while (pEntity != NULL && pEntity != g_qeglobals.d_project_entity) - { - entity_t* pNextEntity = pEntity->next; - Entity_Free(pEntity); - pEntity = pNextEntity; - } - - Sys_Printf("Freeing world entity..."); - if (world_entity) - Entity_Free(world_entity); - Sys_Printf("Done.\n"); - - Sys_Printf("Shutdown VFS..."); - vfsShutdown (); - Sys_Printf("Done.\n"); - - Sys_Printf("FreeShaders..."); - QERApp_FreeShaders(); - Sys_Printf("Done.\n"); -} - -// TTimo: now using profile.cpp code -void MainFrame::LoadCommandMap() -{ - FILE *f; - CString strINI; - bool bUserCmdList = false; - int nLen; - // verbose a little: count of user commands we recognized - int iCount = 0; - int iOverrideCount = 0; - int j; - - -#if defined (__linux__) || defined (__APPLE__) - strINI = g_PrefsDlg.m_rc_path->str; -#elif defined(WIN32) - strINI = g_strGameToolsPath; -#else -#error "WTF are you compiling this on" -#endif - AddSlash (strINI); - strINI += "shortcuts.ini"; - - f = fopen (strINI.GetBuffer(), "r"); - if (f != NULL) - { - fclose(f); - // loop through all the commands - for (int i = 0; i < g_nCommandCount; i++) - { - char value[1024]; - if (read_var( strINI.GetBuffer(), "Commands", g_Commands[i].m_strCommand, value )) - { - if (!bUserCmdList) - { - Sys_Printf("Found user's shortcuts list at %s\n", strINI.GetBuffer() ); - bUserCmdList = true; - } - CString strBuff; - strBuff = value; - strBuff.TrimLeft(); - strBuff.TrimRight(); - strBuff.MakeLower(); - int nSpecial = strBuff.Find("+alt"); - g_Commands[i].m_nModifiers = 0; - if (nSpecial >= 0) - { - g_Commands[i].m_nModifiers |= RAD_ALT; - FindReplace(strBuff, "+alt", ""); - } - nSpecial = strBuff.Find("+ctrl"); - if (nSpecial >= 0) - { - g_Commands[i].m_nModifiers |= RAD_CONTROL; - FindReplace(strBuff, "+ctrl", ""); - } - nSpecial = strBuff.Find("+shift"); - if (nSpecial >= 0) - { - g_Commands[i].m_nModifiers |= RAD_SHIFT; - FindReplace(strBuff, "+shift", ""); - } - strBuff.TrimLeft(); - strBuff.TrimRight(); - strBuff.MakeUpper(); - // strBuff has been cleaned of it's modifiers .. switch between a regular key and a virtual one - // based on length - nLen = strBuff.GetLength(); - if (nLen == 1) // most often case.. deal with first - { - g_Commands[i].m_nKey = __toascii(strBuff.GetAt(0)); - iCount++; - } else // special key - { - for (j = 0; j < g_nKeyCount; j++) - { - if (strBuff.CompareNoCase(g_Keys[j].m_strName) == 0) - { - g_Commands[i].m_nKey = g_Keys[j].m_nVKKey; - iCount++; - break; - } - } - if (j == g_nKeyCount) - { - Sys_Printf("WARNING: failed to parse user command %s\n", value); - continue; - } - } - // maybe this new shortcut is overriding another one - // then we need to disable the other binded key - for (j = 0; j < g_nCommandCount; j++) - { - if (j == i) - continue; - if (g_Commands[i].m_nKey == g_Commands[j].m_nKey && g_Commands[i].m_nModifiers == g_Commands[j].m_nModifiers) - { - // found! - g_Commands[j].m_nKey = 0; - // verbose - iOverrideCount++; - // it's the only one - break; - } - } - } - } - if (iOverrideCount) - Sys_Printf("User's command list overrides %d default commands\n", iOverrideCount); - Sys_Printf("Parsed %d custom shortcuts\n", iCount ); - } - else - Sys_Printf("Looked for a '%s' keyboard shortcuts file, not found\n", strINI.GetBuffer()); -} - -// TTimo: an m_nKey can be set to zero if there's no shorcut binded -// we also output the count of commands that are not binded .. dunno if it's much use .. -// (non-binded keys are usually keys that were defined by shortcuts overriden by user prefs) -void MainFrame::ShowMenuItemKeyBindings(GtkWidget* window) -{ - //!\todo Find a better way to get the global accelerator group.. - GtkAccelGroup *accel = GTK_ACCEL_GROUP(gtk_accel_groups_from_object(G_OBJECT(window))->data); - gpointer item; - guint mods; - int i; - int iCount = 0; - - for (i = 0; i < g_nCommandCount; i++) - { - if (g_Commands[i].m_nKey == 0) - { - iCount++; - continue; - } - - item = g_object_get_data (G_OBJECT (m_pWidget), g_Commands[i].m_strMenu); - if (item == NULL) - { - Sys_FPrintf (SYS_WRN, "WARNING: keyboard shortcuts init, no menu item found for command: \"%s\"\n", - g_Commands[i].m_strCommand); - continue; - } - - mods = 0; - if (g_Commands[i].m_nModifiers) // are there modifiers present? - { - if (g_Commands[i].m_nModifiers & RAD_SHIFT) - mods |= GDK_SHIFT_MASK; - if (g_Commands[i].m_nModifiers & RAD_ALT) - mods |= GDK_MOD1_MASK; - if (g_Commands[i].m_nModifiers & RAD_CONTROL) - mods |= GDK_CONTROL_MASK; - } - - // GTK won't add accelerators for some keys (ex.: delete), so we have to do it manually - if (gtk_accelerator_valid (g_Commands[i].m_nKey, (GdkModifierType)mods)) - { -#ifdef DBG_KBD - // NOTE TTimo this is the important place where all the shortcuts are binded - Sys_Printf("Calling gtk_widget_add_accelerator on command: %s menu: %s key: %d mods: %d\n", g_Commands[i].m_strCommand, g_Commands[i].m_strMenu, g_Commands[i].m_nKey, mods); -#endif - gtk_widget_add_accelerator (GTK_WIDGET (item), "activate", accel, g_Commands[i].m_nKey, - (GdkModifierType)mods, GTK_ACCEL_VISIBLE); - } else - { - GtkAccelLabel *accel_label = GTK_ACCEL_LABEL (GTK_BIN (item)->child); - GString *gstring; - gboolean had_mod; - - g_free (accel_label->accel_string); - accel_label->accel_string = NULL; - - gstring = g_string_new (accel_label->accel_string); - g_string_append (gstring, " "); - - had_mod = FALSE; - if (mods & GDK_SHIFT_MASK) - { - g_string_append (gstring, "Shft"); - had_mod = TRUE; - } - if (mods & GDK_CONTROL_MASK) - { - if (had_mod) - g_string_append (gstring, "+"); - g_string_append (gstring, "Ctl"); - had_mod = TRUE; - } - if (mods & GDK_MOD1_MASK) - { - if (had_mod) - g_string_append (gstring, "+"); - g_string_append (gstring, "Alt"); - had_mod = TRUE; - } - - if (had_mod) - g_string_append (gstring, "+"); - if (g_Commands[i].m_nKey < 0x80 || (g_Commands[i].m_nKey > 0x80 && g_Commands[i].m_nKey <= 0xff)) - { - switch (g_Commands[i].m_nKey) - { - case ' ': - g_string_append (gstring, "Space"); - break; - case '\\': - g_string_append (gstring, "Backslash"); - break; - default: - g_string_append_c (gstring, toupper (g_Commands[i].m_nKey)); - break; - } - } else - { - gchar *tmp; - - tmp = gtk_accelerator_name (g_Commands[i].m_nKey, (GdkModifierType)0); - if (tmp[0] != 0 && tmp[1] == 0) - tmp[0] = toupper (tmp[0]); - g_string_append (gstring, tmp); - g_free (tmp); - } - - g_free (accel_label->accel_string); - accel_label->accel_string = gstring->str; - g_string_free (gstring, FALSE); - - if (!accel_label->accel_string) - accel_label->accel_string = g_strdup (""); - - gtk_widget_queue_resize (GTK_WIDGET (accel_label)); - } - } - - if (iCount) - Sys_Printf("%d commands not bound to a key\n", iCount); -} - -void MainFrame::CreateQEChildren() -{ - // load the project file - if (g_argc > 1) - { - Sys_Printf("loading project file from the command line: %s\n", g_argv[1]); - if (!QE_LoadProject(g_argv[1])) - Error("Unable to load project file %s\n", g_argv[1]); - } - else - { - const char* filename = NULL; - char buf[PATH_MAX]; - const char *r; - bool bTriedTemplate = false; - - if (g_PrefsDlg.m_nLastProjectVer != 0 && g_PrefsDlg.m_nLastProjectVer != PROJECT_VERSION) { - // we need to regenerate from template - Sys_Printf("last project has version %d, this binary wants version %d - regenerating from the template\n", g_PrefsDlg.m_nLastProjectVer, PROJECT_VERSION); - g_PrefsDlg.m_strLastProject = ""; - } - - r = g_PrefsDlg.m_strLastProject.GetBuffer(); - - while(r == NULL || *r == '\0' || access(r, R_OK) != 0 || !QE_LoadProject(r)) - { - if(!bTriedTemplate) - { - // try default project location - bTriedTemplate = true; - // for all OSes, we look for the template in the base installation (no homepath here) - strcpy(buf, g_pGameDescription->mEnginePath.GetBuffer()); - strcat(buf, g_pGameDescription->mBaseGame.GetBuffer()); - strcat(buf, "/scripts/"); - strcat(buf, PROJECT_TEMPLATE_NAME); - r = buf; - } - else - { - gtk_MessageBox (NULL, "Failed to load project file.\nPlease enter a valid project file.", "Load Project"); - - filename = file_dialog (m_pWidget, TRUE, "Choose Project File", buf, "project"); - if (filename != NULL) - r = filename; - else - Error("Cannot continue without loading a project..."); - } - } - } - - QE_Init (); -} - -void MainFrame::OnTimer() -{ - GdkModifierType mask; - - gdk_window_get_pointer (NULL, NULL, NULL, &mask); - - if ((mask & (GDK_BUTTON1_MASK|GDK_BUTTON2_MASK|GDK_BUTTON3_MASK)) == 0) - { - QE_CountBrushesAndUpdateStatusBar(); - QE_CheckAutoSave(); - } - - // see MainFrame::UpdateStatusText below - if (m_bNeedStatusUpdate) - { - for (int n = 0; n < 6; n++) - { - if (m_strStatus[n].GetLength() >= 0 && m_pStatusLabel[n] != NULL) - gtk_label_set_text (GTK_LABEL (m_pStatusLabel[n]), m_strStatus[n]); - } - m_bNeedStatusUpdate = false; - } -} - -void MainFrame::UpdateStatusText() -{ - m_bNeedStatusUpdate = true; -} - -void MainFrame::SetStatusText(int nPane, const char* pText) -{ - if (pText && nPane <= 5 && nPane >= 0) - { - m_strStatus[nPane] = pText; - UpdateStatusText(); - } -} -void MainFrame::SetButtonMenuStates() -{ - GtkWidget *item; - g_bIgnoreCommands++; - - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showangles")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_qeglobals.d_savedinfo.show_angles); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_shownames")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_qeglobals.d_savedinfo.show_names); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showcoordinates")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_qeglobals.d_savedinfo.show_coordinates); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showoutline")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_qeglobals.d_savedinfo.show_outline); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_selection_nooutline")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_ZBUF)); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showaxes")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_qeglobals.d_savedinfo.show_axis); - //item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showpath")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - (g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS) ? FALSE : TRUE); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_clusterportals")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLUSTERPORTALS) != 0); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_lightgrid")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - (g_qeglobals.d_savedinfo.exclude & EXCLUDE_LIGHTGRID) != 0); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_world")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - (g_qeglobals.d_savedinfo.exclude & EXCLUDE_WORLD) != 0); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_entities")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - (g_qeglobals.d_savedinfo.exclude & EXCLUDE_ENT) != 0); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_areaportals")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - (g_qeglobals.d_savedinfo.exclude & EXCLUDE_AREAPORTALS) != 0); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_translucent")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - (g_qeglobals.d_savedinfo.exclude & EXCLUDE_TRANSLUCENT) != 0); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_liquids")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - (g_qeglobals.d_savedinfo.exclude & EXCLUDE_LIQUIDS) != 0); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_caulk")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK) != 0); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_clips")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP) != 0); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_botclips")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP) != 0); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_structural")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - (g_qeglobals.d_savedinfo.exclude & EXCLUDE_STRUCTURAL) != 0); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_paths")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - (g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS) != 0); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_clusterportals")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLUSTERPORTALS) != 0); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_lightgrid")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - (g_qeglobals.d_savedinfo.exclude & EXCLUDE_LIGHTGRID) != 0); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_lights")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - (g_qeglobals.d_savedinfo.exclude & EXCLUDE_LIGHTS) != 0); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_patches")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CURVES) != 0); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_details")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - (g_qeglobals.d_savedinfo.exclude & EXCLUDE_DETAILS) != 0); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_hintsskips")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - (g_qeglobals.d_savedinfo.exclude & EXCLUDE_HINTSSKIPS) != 0); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_models")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - (g_qeglobals.d_savedinfo.exclude & EXCLUDE_MODELS) != 0); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_triggers")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - (g_qeglobals.d_savedinfo.exclude & EXCLUDE_TRIGGERS) != 0); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_toggle_lock")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (g_PrefsDlg.m_bTextureLock) ? TRUE : FALSE); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_toggle_rotatelock")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (g_PrefsDlg.m_bRotateLock) ? TRUE : FALSE); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_cubicclipping")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (g_PrefsDlg.m_bCubicClipping) ? TRUE : FALSE); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_opengllighting")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (g_PrefsDlg.m_bGLLighting) ? TRUE : FALSE); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_snaptogrid")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (!g_PrefsDlg.m_bNoClamp) ? TRUE : FALSE); - - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_view_cubicclipping")); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_PrefsDlg.m_bCubicClipping) ? TRUE : FALSE); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_dontselectmodel")); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_PrefsDlg.m_bSelectModels) ? FALSE : TRUE); - - if (!g_pGameDescription->mNoPatch) - { - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_dontselectcurve")); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_PrefsDlg.m_bSelectCurves) ? FALSE : TRUE); - - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_showboundingbox")); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchShowBounds) ? TRUE : FALSE); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_weld")); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchWeld) ? TRUE : FALSE); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_drilldown")); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchDrillDown) ? TRUE : FALSE); - } - - int id, n = g_PrefsDlg.m_nTextureScale; - switch (n) - { - case 10 : id = ID_TEXTURES_TEXTUREWINDOWSCALE_10; break; - case 25 : id = ID_TEXTURES_TEXTUREWINDOWSCALE_25; break; - case 50 : id = ID_TEXTURES_TEXTUREWINDOWSCALE_50; break; - case 200 : id = ID_TEXTURES_TEXTUREWINDOWSCALE_200; break; - default : id = ID_TEXTURES_TEXTUREWINDOWSCALE_100; break; - } - SetTextureScale (id); - - // FIXME TTimo cleaned up .. the right place to do this in QE_LoadProject? -/* - if (g_qeglobals.d_project_entity) - { - FillTextureMenu(); // redundant but i'll clean it up later.. yeah right.. - FillBSPMenu(); - } - */ - g_bIgnoreCommands--; -} - -void MainFrame::UpdateWindows(int nBits) -{ - if (!g_bScreenUpdates) - return; -#ifdef DBG_WINDOWPOS - static int bean_count = 0; - char bean_buf[100]; - sprintf(bean_buf,"UpdateWindows %d",bean_count); - CheckWatchit(bean_buf); - bean_count++; -#endif - - if (nBits & (W_XY | W_XY_OVERLAY)) - { - if (m_pXYWnd) - m_pXYWnd->RedrawWindow (); - if (m_pXZWnd) - m_pXZWnd->RedrawWindow (); - if (m_pYZWnd) - m_pYZWnd->RedrawWindow (); - } - - if (nBits & W_CAMERA || ((nBits & W_CAMERA_IFON) && m_bCamPreview)) - { - if (m_pCamWnd) - m_pCamWnd->RedrawWindow (); - } - - if (nBits & (W_Z | W_Z_OVERLAY)) - { - if (m_pZWnd) - m_pZWnd->RedrawWindow (); - } - - if (nBits & W_TEXTURE) - { - if (m_pTexWnd) - m_pTexWnd->RedrawWindow (); - } -#ifdef DBG_WINDOWPOS - sprintf(bean_buf,"%d (end UpdateWidows)",bean_count); - CheckWatchit(bean_buf); -#endif -} - -void MainFrame::RoutineProcessing() -{ -#ifdef DBG_WINDOWPOS - static int bean_count = 0; - char bean_buf[100]; - sprintf(bean_buf,"RoutineProcessing %d",bean_count); - CheckWatchit(bean_buf); - bean_count++; -#endif - - if (m_bDoLoop) - { - double time = 0.0; - double oldtime = 0.0; - double delta= 0.0; - -/* // checking KeyState works right - static short a1,a2; - a2 = GetKeyState(VK_MENU); - if (a1!=a2) - { - Sys_Printf("VK_MENU: %d\n",a2); - a1 = a2; - } - static short b1,b2; - b2 = GetKeyState(VK_UP); - if (b1!=b2) - { - Sys_Printf("VK_UP: %d\n",b2); - b1 = b2; - } */ - - time = Sys_DoubleTime (); - delta = time - oldtime; - oldtime = time; - if (delta > 0.2) - delta = 0.2; - - // update the BSP process watcher - if (m_pWatchBSP) - m_pWatchBSP->RoutineProcessing(); - - // run time dependant behavior - if (m_pCamWnd) - m_pCamWnd->Cam_MouseControl(delta); - - if (g_nUpdateBits) - { - int nBits = g_nUpdateBits; // this is done to keep this routine from being - g_nUpdateBits = 0; // re-entered due to the paint process.. only - UpdateWindows(nBits); // happens in rare cases but causes a stack overflow - } -/* - // Enable/disable the menu items - GtkWidget *item; - - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_cameraupdate")); - gtk_widget_set_sensitive (item, (m_bCamPreview == false)); - if (!g_PrefsDlg.m_bWideToolbar) - { - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_view_cameraupdate")); - gtk_widget_set_sensitive (item, (m_bCamPreview == false)); - } - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_edit_undo")); - gtk_widget_set_sensitive (item, Undo_UndoAvailable()); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_edit_redo")); - gtk_widget_set_sensitive (item, Undo_RedoAvailable()); - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_file_saveregion")); - gtk_widget_set_sensitive (item, region_active); - g_bIgnoreCommands++; - // update the toolbar before displaying the menu: - // show in use check box - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_showinuse")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), !g_bShowAllShaders); - // show all check box - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_showall")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_bShowAllShaders); - g_bIgnoreCommands--; - */ - } -#ifdef DBG_WINDOWPOS - sprintf(bean_buf,"%d (end RoutineProcessing)",bean_count); - CheckWatchit(bean_buf); -#endif -} - -void MainFrame::DoWatchBSP() -{ - // network monitoring of the BSP process - if (!m_pWatchBSP) - m_pWatchBSP = new CWatchBSP(); -} - -void MainFrame::CleanPlugInMenu() -{ - GtkWidget *menu, *sep; - GList *lst; - - // delete everything after the separator - menu = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_plugin")); - sep = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_plugin_separator")); - m_nNextPlugInID = ID_PLUGIN_START; - - lst = g_list_find (gtk_container_children (GTK_CONTAINER (menu)), sep); - while (lst->next) - { - gtk_container_remove (GTK_CONTAINER (menu), GTK_WIDGET (lst->next->data)); - lst = g_list_find (gtk_container_children (GTK_CONTAINER (menu)), sep); - } -} - -void MainFrame::AddPlugInMenuItem(IPlugIn* pPlugIn) -{ - GtkWidget *menu, *item, *parent; - const char *menuText; - - parent = gtk_menu_item_new_with_label (pPlugIn->getMenuName()); - gtk_widget_show (parent); - gtk_container_add (GTK_CONTAINER (g_object_get_data (G_OBJECT (m_pWidget), "menu_plugin")), parent); - - int nCount = pPlugIn->getCommandCount(); - if (nCount > 0) - { - menu = gtk_menu_new (); - while (nCount > 0) - { - menuText = pPlugIn->getCommand(--nCount); - if (menuText != NULL && strlen(menuText) > 0) - { - if (!strcmp(menuText, "-")) - { - item = gtk_menu_item_new (); - gtk_widget_set_sensitive (item, FALSE); - } else - { - item = gtk_menu_item_new_with_label (menuText); - gtk_signal_connect (GTK_OBJECT (item), "activate", - GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (m_nNextPlugInID)); - } - gtk_widget_show (item); - gtk_container_add (GTK_CONTAINER (menu), item); - pPlugIn->addMenuID(m_nNextPlugInID++); - } - } - gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent), menu); - } -} - -void MainFrame::OnPlugIn(unsigned int nID, char* str) -{ - m_PlugInMgr.Dispatch(nID, str); -} - -inline GtkToolbarChildType gtktoolbarchildtype_for_toolbarbuttontype(IToolbarButton::EType type) -{ - switch(type) - { - case IToolbarButton::eSpace: - return GTK_TOOLBAR_CHILD_SPACE; - case IToolbarButton::eButton: - return GTK_TOOLBAR_CHILD_BUTTON; - case IToolbarButton::eToggleButton: - return GTK_TOOLBAR_CHILD_TOGGLEBUTTON; - case IToolbarButton::eRadioButton: - return GTK_TOOLBAR_CHILD_RADIOBUTTON; - } - Error("invalid toolbar button type"); - return (GtkToolbarChildType)0; -} - -void toolbar_insert(GtkWidget *toolbar, const char* image, const char* text, const char* tooltip, IToolbarButton::EType type, GtkSignalFunc handler, gpointer data) -{ - GtkWidget *w, *pixmap; - GdkPixmap *gdkpixmap; - GdkBitmap *mask; - - load_plugin_bitmap(image, (void **)&gdkpixmap, (void **)&mask); - pixmap = gtk_pixmap_new (gdkpixmap, mask); - gdk_pixmap_unref (gdkpixmap); - gdk_pixmap_unref (mask); - w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), gtktoolbarchildtype_for_toolbarbuttontype(type), NULL, text, tooltip, "", GTK_WIDGET (pixmap), handler, data); -} - -void SignalToolbarButton(GtkWidget *widget, gpointer data) -{ - const_cast(reinterpret_cast(data))->activate(); -} - -void MainFrame::AddPlugInToolbarButton(const IToolbarButton* button) -{ - GtkWidget*const toolbar = GTK_WIDGET(g_object_get_data (G_OBJECT (m_pWidget), "toolbar_plugin")); - toolbar_insert(toolbar, button->getImage(), button->getText(), button->getTooltip(), button->getType(), GTK_SIGNAL_FUNC(SignalToolbarButton), reinterpret_cast(const_cast(button))); -} - -void MainFrame::OnSelectionSelectNudgedown() -{ - NudgeSelection(3, g_qeglobals.d_gridsize); -} - -void MainFrame::OnSelectionSelectNudgeleft() -{ - NudgeSelection(0, g_qeglobals.d_gridsize); -} - -void MainFrame::OnSelectionSelectNudgeright() -{ - NudgeSelection(2, g_qeglobals.d_gridsize); -} - -void MainFrame::OnSelectionSelectNudgeup() -{ - NudgeSelection(1, g_qeglobals.d_gridsize); -} - -void MainFrame::NudgeSelection(int nDirection, float fAmount) -{ - if (ActiveXY()->RotateMode()) - { - int nAxis = 0; - if (ActiveXY()->GetViewType() == XY) - { - nAxis = 2; - } else - if (g_pParentWnd->ActiveXY()->GetViewType() == XZ) - { - nAxis = 1; - fAmount = -fAmount; - } - - if (nDirection == 2 || nDirection == 3) - { - fAmount = -fAmount; - } - - float fDeg = -fAmount; - float fAdj = fAmount; - - g_pParentWnd->ActiveXY()->Rotation()[nAxis] += fAdj; - CString strStatus; - strStatus.Format("Rotation x:: %.1f y:: %.1f z:: %.1f", g_pParentWnd->ActiveXY()->Rotation()[0], - g_pParentWnd->ActiveXY()->Rotation()[1], g_pParentWnd->ActiveXY()->Rotation()[2]); - g_pParentWnd->SetStatusText(2, strStatus); - Select_RotateAxis(nAxis, fDeg, false, true); - Sys_UpdateWindows (W_ALL); - } else - if (ActiveXY()->ScaleMode()) - { - if (nDirection == 0 || nDirection == 3) - { - fAmount = -fAmount; - } - vec3_t v; - v[0] = v[1] = v[2] = 1.0; - if (fAmount > 0) - { - v[0] = 1.1f; - v[1] = 1.1f; - v[2] = 1.1f; - } else - { - v[0] = 0.9f; - v[1] = 0.9f; - v[2] = 0.9f; - } - - Select_Scale((g_nScaleHow & SCALE_X) ? v[0] : 1.0, - (g_nScaleHow & SCALE_Y) ? v[1] : 1.0, - (g_nScaleHow & SCALE_Z) ? v[2] : 1.0); - Sys_UpdateWindows (W_ALL); - } else - { - // 0 - left, 1 - up, 2 - right, 3 - down - int nDim; - if (nDirection == 0) - { - nDim = ActiveXY()->GetViewType() == YZ ? 1 : 0; - fAmount = -fAmount; - } else if (nDirection == 1) - { - nDim = ActiveXY()->GetViewType() == XY ? 1 : 2; - } else if (nDirection == 2) - { - nDim = ActiveXY()->GetViewType() == YZ ? 1 : 0; - } else - { - nDim = ActiveXY()->GetViewType() == XY ? 1 : 2; - fAmount = -fAmount; - } - Nudge(nDim, fAmount); - } -} - -void MainFrame::Nudge(int nDim, float fNudge) -{ - vec3_t vMove; - vMove[0] = vMove[1] = vMove[2] = 0; - vMove[nDim] = fNudge; - - if((g_qeglobals.d_select_mode == sel_vertex || - g_qeglobals.d_select_mode == sel_curvepoint) - && g_qeglobals.d_num_move_points) - Select_NudgePoint(vMove, true); - else - Select_Move(vMove, true); - Sys_UpdateWindows (W_ALL); -} - -void MainFrame::SetGridStatus() -{ - CString strStatus; - char c1; - char c2; - c1 = (g_PrefsDlg.m_bTextureLock) ? 'M' : ' '; - c2 = (g_PrefsDlg.m_bRotateLock) ? 'R' : ' '; - strStatus.Format("G:%g R:%i C:%i L:%c%c", g_qeglobals.d_gridsize, - g_PrefsDlg.m_nRotation, g_PrefsDlg.m_nCubicScale, c1, c2); - SetStatusText(4, strStatus); -} - -void MainFrame::UpdatePatchToolbarButtons() -{ - GtkWidget *item; - g_bIgnoreCommands++; - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_bend")); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchBendMode) ? TRUE : FALSE); -// item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_insdel")); -// gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchInsertMode) ? TRUE : FALSE); - g_bIgnoreCommands--; -} - -// ============================================================================= -// Command handlers - -void MainFrame::OnFileNew() -{ - if (ConfirmModified()) - Map_New (); -} - -void MainFrame::OnFileOpen() -{ - if (!ConfirmModified()) - return; - - const char *str; - char buf[NAME_MAX]; - - strcpy(buf, g_qeglobals.m_strHomeMaps.GetBuffer()); - strcat(buf, "maps/"); - - str = file_dialog (m_pWidget, TRUE, "Open Map", buf, MAP_MAJOR); - - if (str != NULL) - { - strcpy(currentmap,str); - MRU_AddFile (str); - Map_LoadFile(str); - } -} - -void MainFrame::OnFileImportmap() -{ - const char *str; - char buf[NAME_MAX]; - - strcpy(buf, g_qeglobals.m_strHomeMaps.GetBuffer()); - strcat(buf, "maps/"); - - str = file_dialog (m_pWidget, TRUE, "Import Map", buf, MAP_MAJOR); - - if (str != NULL) - { - Map_ImportFile(str); - } -} - -void MainFrame::OnFileSave() -{ - if (!strcmp(currentmap, "unnamed.map")) - OnFileSaveas(); - else - Map_SaveFile (currentmap, false); -} - -void MainFrame::OnFileSaveas() -{ - const char* str; - char buf[NAME_MAX]; - - strcpy(buf, g_qeglobals.m_strHomeMaps.GetBuffer()); - strcat(buf, "maps/"); - - str = file_dialog (g_pParentWnd->m_pWidget, FALSE, "Save Map", buf, MAP_MAJOR); - - if (str != NULL) - { - strcpy (currentmap, str); - MRU_AddFile (str); - Map_SaveFile (str, false); // ignore region - } -} - -void MainFrame::OnFileExportmap() -{ - const char* str; - char buf[NAME_MAX]; - - strcpy(buf, g_qeglobals.m_strHomeMaps.GetBuffer()); - strcat(buf, "maps/"); - - str = file_dialog (m_pWidget, FALSE, "Export Selection", buf, MAP_MAJOR); - - if (str != NULL) - { - Map_SaveSelected (str); - } -} - -void MainFrame::OnFileSaveregion() -{ - const char* str; - char buf[NAME_MAX]; - - strcpy(buf, g_qeglobals.m_strHomeMaps.GetBuffer()); - strcat(buf, "maps/"); - - str = file_dialog (g_pParentWnd->m_pWidget, FALSE, "Export Region", buf, MAP_MAJOR); - - if (str != NULL) - { - Map_SaveFile (str, true); // ignore region - } -} - -void MainFrame::OnFileNewproject() -{ - char* name = DoNewProjectDlg (); - - // create a new project: - // create directories and grab current project, save it in new project tree in scripts/user.qe4 - // on linux we create under ~/.q3a, on win32 under strEnginePath - // NOTE: working on a seperate project file might be broken, never did much experiment with that.. - if ((name != NULL) && (strlen (name) > 0)) - { - CString strNewBasePath; - - // NOTE TTimo this would probably not work right on *nix - strNewBasePath = g_pGameDescription->mEnginePath.GetBuffer(); // assume paths end with '/' - strNewBasePath += name; - strNewBasePath += "/"; - - CString strProjToLoad; - CString strMapToLoad; - - // if the dir exists, ask the user if they want to continue anyway - if (Q_mkdir (strNewBasePath.GetBuffer(), 0755) != 0) - { - CString strMsg; - strMsg.Format("The directory name %s already exists\nContinue anyway ?\n", strNewBasePath.GetBuffer ()); - Sys_Printf(strMsg); - if (gtk_MessageBox(m_pWidget, strMsg, "Error", MB_YESNO) != IDYES) - { - Sys_Printf("New Project cancelled, directory already exists for project\n"); - free (name); - return; - } - } - - CString strDir; - strDir = strNewBasePath; - strDir += "maps/"; - Q_mkdir (strDir.GetBuffer(), 0755); - - strDir = strNewBasePath; - strDir += "textures/"; - Q_mkdir (strDir.GetBuffer(), 0755); - - strDir = strNewBasePath; - strDir += "scripts/"; - Q_mkdir (strDir.GetBuffer(), 0755); - - // print a warning for total conversions, since setting the basepath when required files are - // not there _will_ break things (ie; textures/radiant/notex.tga, scripts/entities.def) - Sys_FPrintf(SYS_WRN, "*** Note: basepath unchanged\n"); - - SetKeyValue( g_qeglobals.d_project_entity, "gamename", name); - - strDir = strNewBasePath; - strDir += "maps/autosave.map"; - SetKeyValue( g_qeglobals.d_project_entity, "autosave", strDir.GetBuffer() ); - - // state that this is a user project file, no templating - SetKeyValue( g_qeglobals.d_project_entity, "user_project", "1" ); - // create the project file - strProjToLoad = strNewBasePath; - strProjToLoad += "scripts/"; - strProjToLoad += name; - strProjToLoad += "."; - strProjToLoad += PROJECT_FILETYPE; - QE_SaveProject(strProjToLoad.GetBuffer()); - free (name); - } -} - -void MainFrame::OnFileLoadproject() -{ - if (ConfirmModified()) - ProjectDialog (); -} - -void MainFrame::OnFileProjectsettings() -{ - DoProjectSettings(); -} - -void MainFrame::OnFilePointfile() -{ - if (g_qeglobals.d_pointfile_display_list) - Pointfile_Clear (); - else - Pointfile_Check (); -} - -void MainFrame::OnMru(unsigned int nID) -{ - if (ConfirmModified()) - MRU_Activate (nID - ID_FILE_RECENT1); -} - -void MainFrame::OnFileExit() -{ - if (ConfirmModified()) - { - // stop printing during shutdown - // NOTE: we should cleanly release GL contexts and stuff when exiting - - OnDelete(); - - g_qeglobals_gui.d_edit = NULL; - gtk_widget_destroy (m_pWidget); - } -} - -void MainFrame::OnFileCheckUpdate() - -{ - // build the URL - Str URL; - URL = "http://www.qeradiant.com/index.php?data=dlupdate&query_dlup=1"; -#ifdef _WIN32 - URL += "&OS_dlup=1"; -#else - URL += "&OS_dlup=2"; -#endif - URL += "&Version_dlup=" RADIANT_VERSION; - g_PrefsDlg.mGamesDialog.AddPacksURL(URL); - OpenURL(URL.GetBuffer()); -} - -void MainFrame::OnEditUndo() -{ - Undo_Undo(); -} - -void MainFrame::OnEditRedo() -{ - Undo_Redo(); -} - -void MainFrame::OnEditCopybrush() -{ - Copy(); -} - -void MainFrame::OnEditPastebrush() -{ - Select_Deselect(); - - Undo_Start("paste"); - - Paste(); - - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnEditPastebrushToCamera() -{ - Select_Deselect(); - if (ActiveXY()) - { - vec3_t mid, camorigin, delta; - - ActiveXY()->Paste(); - - // Work out the delta - Select_GetMid( mid ); - - // Snap camera origin to grid - VectorCopy( m_pCamWnd->Camera()->origin, camorigin ); - camorigin[0] = floor(camorigin[0] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; - camorigin[1] = floor(camorigin[1] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; - camorigin[2] = floor(camorigin[2] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; - - VectorSubtract( camorigin, mid, delta ); - - // Move to camera - Select_Move( delta, false ); - - Undo_Start("paste to camera"); - Undo_EndBrushList(&selected_brushes); - Undo_End(); - } -} - -void MainFrame::OnSelectionDelete() -{ - brush_t *brush; - //if (ActiveXY()) - // ActiveXY()->UndoCopy(); - Undo_Start("delete"); - Undo_AddBrushList(&selected_brushes); - //add all deleted entities to the undo - for (brush = selected_brushes.next; brush != &selected_brushes; brush = brush->next) - { - Undo_AddEntity(brush->owner); - } - // NOTE: Select_Delete does NOT delete entities - Select_Delete(); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnEditMapinfo() -{ - DoMapInfo (); -} - -void MainFrame::OnEditEntityinfo() -{ - DoEntityList (); -} - -void MainFrame::OnBrushScripts() -{ - DoScriptsDlg (); -} - -void MainFrame::OnEditLoadprefab() -{ - const char *filename; - CString CurPath; - - if (g_PrefsDlg.m_strPrefabPath.GetLength() > 0) - { - CurPath = g_PrefsDlg.m_strPrefabPath; - AddSlash (CurPath); - } - - filename = file_dialog (m_pWidget, TRUE, "Import Prefab", CurPath.GetBuffer(), MAP_MAJOR); - - if (filename != NULL) - { - Map_ImportFile(filename); - } -} - -void MainFrame::OnEditSaveprefab() -{ - const char *filename; - CString CurPath; - - if (g_PrefsDlg.m_strPrefabPath.GetLength() > 0) - { - CurPath = g_PrefsDlg.m_strPrefabPath; - } else - { - char tmp[PATH_MAX]; - getcwd (tmp, PATH_MAX); - CurPath = tmp; - } - AddSlash (CurPath); - - filename = file_dialog (m_pWidget, FALSE, "Export Prefab", CurPath.GetBuffer(), MAP_MAJOR); - if (filename != NULL) - { - Map_SaveSelected(filename); - } -} - -void MainFrame::OnPrefs() -{ - int nView = g_PrefsDlg.m_nView; - bool bToolbar = g_PrefsDlg.m_bWideToolbar; - bool bPluginToolbar = g_PrefsDlg.m_bPluginToolbar; - int nShader = g_PrefsDlg.m_nShader; - int nTextureQuality = g_PrefsDlg.m_nTextureQuality; - int nLightRadiuses = g_PrefsDlg.m_nLightRadiuses; - g_PrefsDlg.LoadPrefs(); - - if (g_PrefsDlg.DoModal() == IDOK) - { - if ((g_PrefsDlg.m_nLatchedView != nView) || - (g_PrefsDlg.m_bLatchedDetachableMenus != g_PrefsDlg.m_bDetachableMenus) || - (g_PrefsDlg.m_bLatchedWideToolbar != bToolbar) || - (g_PrefsDlg.m_bLatchedPatchToolbar != bToolbar) || - (g_PrefsDlg.m_bLatchedPluginToolbar != bPluginToolbar) || - (g_PrefsDlg.m_nLatchedShader != nShader) || - (g_PrefsDlg.m_nLatchedTextureQuality != nTextureQuality) - || (g_PrefsDlg.m_bLatchedFloatingZ != g_PrefsDlg.m_bFloatingZ) - ) - gtk_MessageBox(m_pWidget, "You must restart Radiant for the changes to take effect."); - - // if the view mode was switched to floating, set the Z window on by default - // this was originally intended as a bug fix, but the fix is elsewhere .. anyway making sure we force Z on each time is good - // (and we simply hope there will be a SavePrefs before we die) - if ((g_PrefsDlg.m_nView != nView) && ((EViewStyle)g_PrefsDlg.m_nView == (EViewStyle)eFloating)) - { - g_PrefsDlg.m_bZVis = true; - } - - if (m_pTexWnd) - m_pTexWnd->UpdatePrefs(); - - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_snaptogrid")); - g_bIgnoreCommands++; - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - (!g_PrefsDlg.m_bNoClamp) ? TRUE : FALSE); - g_bIgnoreCommands--; - } -} - -void MainFrame::OnTogglecamera() -{ - if (CurrentStyle() == eFloating) // floating views - { - if (m_pCamWnd && m_pCamWnd->m_pParent) - { - if (GTK_WIDGET_VISIBLE (m_pCamWnd->m_pParent)) - widget_delete_hide (m_pCamWnd->m_pParent); - else - gtk_widget_show (m_pCamWnd->m_pParent); - } - } else - { - if (GTK_WIDGET_VISIBLE (m_pCamWnd->GetWidget ())) - gtk_widget_hide (m_pCamWnd->GetWidget ()); - else - gtk_widget_show (m_pCamWnd->GetWidget ()); - } -} - -void MainFrame::OnToggleconsole() -{ - if (FloatingGroupDialog()) // QE4 style - { - if (inspector_mode == W_CONSOLE) - { - if (GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity)) - widget_delete_hide (g_qeglobals_gui.d_entity); - else - gtk_widget_show (g_qeglobals_gui.d_entity); - } else - { - gtk_widget_show (g_qeglobals_gui.d_entity); - SetInspectorMode(W_CONSOLE); - } - } -} - -// trigger the entity inspector on/off -void MainFrame::OnViewEntity() -{ - // make sure we're working with the current selection (bugzilla #436) - if( ! GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity)) - Select_Reselect(); - - if (!FloatingGroupDialog()) - { - if (GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity) && inspector_mode == W_ENTITY) - widget_delete_hide (g_qeglobals_gui.d_entity); - else - { - gtk_widget_show (g_qeglobals_gui.d_entity); - SetInspectorMode(W_ENTITY); - } - } else - { - if (inspector_mode == W_ENTITY) - { - if (GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity)) - widget_delete_hide (g_qeglobals_gui.d_entity); - else - gtk_widget_show (g_qeglobals_gui.d_entity); - } else - { - gtk_widget_show (g_qeglobals_gui.d_entity); - SetInspectorMode(W_ENTITY); - } - } -} - -void MainFrame::OnViewGroups() -{ - if (!FloatingGroupDialog()) - { - if (GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity) && inspector_mode == W_GROUP) - widget_delete_hide (g_qeglobals_gui.d_entity); - else - { - gtk_widget_show (g_qeglobals_gui.d_entity); - SetInspectorMode(W_GROUP); - } - } else - { - if (inspector_mode == W_GROUP && CurrentStyle() != MainFrame::eFloating) - { - if (GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity)) - widget_delete_hide (g_qeglobals_gui.d_entity); - else - gtk_widget_show (g_qeglobals_gui.d_entity); - } else - { - gtk_widget_show (g_qeglobals_gui.d_entity); - SetInspectorMode(W_GROUP); - } - } -} - -void MainFrame::OnToggleview() -{ - if (CurrentStyle() == eFloating) // QE4 style - { - if (m_pXYWnd && m_pXYWnd->m_pParent) - { - if (GTK_WIDGET_VISIBLE (m_pXYWnd->m_pParent)) - widget_delete_hide (m_pXYWnd->m_pParent); - else - gtk_widget_show (m_pXYWnd->m_pParent); - } - } -} - -void MainFrame::OnToggleviewXz() -{ - if (CurrentStyle() == eFloating) // QE4 style - { - if (m_pXZWnd && m_pXZWnd->m_pParent) - { - // get windowplacement doesn't actually save this so we will here - g_PrefsDlg.m_bXZVis = GTK_WIDGET_VISIBLE (m_pXZWnd->m_pParent); - if (g_PrefsDlg.m_bXZVis) - widget_delete_hide (m_pXZWnd->m_pParent); - else - gtk_widget_show (m_pXZWnd->m_pParent); - g_PrefsDlg.m_bXZVis ^= 1; - g_PrefsDlg.SavePrefs (); - } - } -} - -void MainFrame::OnToggleviewYz() -{ - if (CurrentStyle() == eFloating) // QE4 style - { - if (m_pYZWnd && m_pYZWnd->m_pParent) - { - g_PrefsDlg.m_bYZVis = GTK_WIDGET_VISIBLE (m_pYZWnd->m_pParent); - if (g_PrefsDlg.m_bYZVis) - widget_delete_hide (m_pYZWnd->m_pParent); - else - gtk_widget_show (m_pYZWnd->m_pParent); - g_PrefsDlg.m_bYZVis ^= 1; - g_PrefsDlg.SavePrefs (); - } - } -} - -void MainFrame::OnTogglez() -{ - if ( g_pParentWnd->FloatingGroupDialog() ) // QE4 style - { - if (m_pZWnd && m_pZWnd->m_pParent) - { - if (GTK_WIDGET_VISIBLE (m_pZWnd->m_pParent)) - widget_delete_hide (m_pZWnd->m_pParent); - else - gtk_widget_show (m_pZWnd->m_pParent); - g_PrefsDlg.m_bZVis ^= 1; - g_PrefsDlg.SavePrefs (); - } - } else { - Sys_FPrintf( SYS_WRN, "Z view toggle is only valid in floating views\n" ); - } -} - -void MainFrame::OnViewCenter() -{ - m_pCamWnd->Camera()->angles[ROLL] = m_pCamWnd->Camera()->angles[PITCH] = 0; - m_pCamWnd->Camera()->angles[YAW] = 22.5 * floor((m_pCamWnd->Camera()->angles[YAW]+11)/22.5); - Sys_UpdateWindows (W_CAMERA | W_XY_OVERLAY); -} - -void MainFrame::OnViewUpfloor() -{ - m_pCamWnd->Cam_ChangeFloor (true); -} - -void MainFrame::OnViewDownfloor() -{ - m_pCamWnd->Cam_ChangeFloor (false); -} - -void MainFrame::OnViewCenterview() -{ - if(CurrentStyle() == eSplit) - { - GetXYWnd()->PositionView(); - GetXZWnd()->PositionView(); - GetYZWnd()->PositionView(); - Sys_UpdateWindows (W_XY|W_XZ|W_YZ); - } - else { - m_pXYWnd->PositionView(); - Sys_UpdateWindows (W_XY); - } -} - -void MainFrame::OnViewNextview() -{ - if (CurrentStyle() == eSplit) - { - GetXYWnd()->PositionView(); - GetXZWnd()->PositionView(); - GetYZWnd()->PositionView(); - Sys_UpdateWindows (W_XY|W_XZ|W_YZ); - } - else { - if (m_pXYWnd->GetViewType() == XY) - m_pXYWnd->SetViewType(XZ); - else - if (m_pXYWnd->GetViewType() == XZ) - m_pXYWnd->SetViewType(YZ); - else - m_pXYWnd->SetViewType(XY); - m_pXYWnd->PositionView(); - Sys_UpdateWindows (W_XY); - } -} - -void MainFrame::OnViewXy() -{ - if(!FloatingGroupDialog()) - { - m_pXYWnd->SetViewType(XY); - m_pXYWnd->PositionView(); - } - Sys_UpdateWindows (W_XY); -} - -void MainFrame::OnViewSide() -{ - if (!FloatingGroupDialog()) - { - m_pXYWnd->SetViewType(XZ); - m_pXYWnd->PositionView(); - } - Sys_UpdateWindows (W_XY); -} - -void MainFrame::OnViewFront() -{ - if (!FloatingGroupDialog()) - { - m_pXYWnd->SetViewType(YZ); - m_pXYWnd->PositionView(); - } - Sys_UpdateWindows (W_XY); -} - -void MainFrame::OnView100() -{ - if (m_pXYWnd) - m_pXYWnd->SetScale(1); - if (m_pXZWnd) - m_pXZWnd->SetScale(1); - if (m_pYZWnd) - m_pYZWnd->SetScale(1); - Sys_UpdateWindows (W_XY|W_XY_OVERLAY); -} - -void MainFrame::OnViewZoomin() -{ - if (m_pXYWnd && m_pXYWnd->Active()) - { - m_pXYWnd->SetScale(m_pXYWnd->Scale() * 5.0 / 4); - if (m_pXYWnd->Scale() > 30) - m_pXYWnd->SetScale(30); - } - - if (m_pXZWnd && m_pXZWnd->Active()) - { - m_pXZWnd->SetScale(m_pXZWnd->Scale() * 5.0 / 4); - if (m_pXZWnd->Scale() > 30) - m_pXZWnd->SetScale(30); - } - - if (m_pYZWnd && m_pYZWnd->Active()) - { - m_pYZWnd->SetScale(m_pYZWnd->Scale() * 5.0 / 4); - if (m_pYZWnd->Scale() > 30) - m_pYZWnd->SetScale(30); - } - - Sys_UpdateWindows (W_XY|W_XY_OVERLAY); -} - -// NOTE: the zoom out factor is 4/5, we could think about customizing it -// we don't go below a zoom factor corresponding to 10% of the max world size -// (this has to be computed against the window size) -void MainFrame::OnViewZoomout() -{ - float min_scale; - if (m_pXYWnd && m_pXYWnd->Active()) - { - m_pXYWnd->SetScale(m_pXYWnd->Scale() * 4.0 / 5); - min_scale = MIN(m_pXYWnd->Width(),m_pXYWnd->Height()) / ( 1.1 * (g_MaxWorldCoord-g_MinWorldCoord)); - if (m_pXYWnd->Scale() < min_scale) m_pXYWnd->SetScale (min_scale); - } - - if (m_pXZWnd && m_pXZWnd->Active()) - { - m_pXZWnd->SetScale(m_pXZWnd->Scale() * 4.0 / 5); - min_scale = MIN(m_pXZWnd->Width(),m_pXZWnd->Height()) / ( 1.1 * (g_MaxWorldCoord-g_MinWorldCoord)); - if (m_pXZWnd->Scale() < min_scale) m_pXZWnd->SetScale (min_scale); - } - - if (m_pYZWnd && m_pYZWnd->Active()) - { - m_pYZWnd->SetScale(m_pYZWnd->Scale() * 4.0 / 5); - min_scale = MIN(m_pYZWnd->Width(),m_pYZWnd->Height()) / ( 1.1 * (g_MaxWorldCoord-g_MinWorldCoord)); - if (m_pYZWnd->Scale() < min_scale) m_pYZWnd->SetScale (min_scale); - } - Sys_UpdateWindows (W_XY|W_XY_OVERLAY); -} - -void MainFrame::OnViewZ100() -{ - z.scale = 1; - Sys_UpdateWindows (W_Z|W_Z_OVERLAY); -} - -void MainFrame::OnViewZzoomin() -{ - z.scale *= 5.0/4; - if (z.scale > 4) - z.scale = 4; - Sys_UpdateWindows (W_Z|W_Z_OVERLAY); -} - -void MainFrame::OnViewZzoomout() -{ - z.scale *= 4.0f/5; - if (z.scale < 0.125) - z.scale = 0.125; - Sys_UpdateWindows (W_Z|W_Z_OVERLAY); -} - -void MainFrame::OnViewCubein() -{ - g_PrefsDlg.m_nCubicScale--; - if (g_PrefsDlg.m_nCubicScale < 1) - g_PrefsDlg.m_nCubicScale = 1; - g_PrefsDlg.SavePrefs (); - Sys_UpdateWindows(W_CAMERA); - SetGridStatus(); -} - -void MainFrame::OnViewCubeout() -{ - g_PrefsDlg.m_nCubicScale++; - if (g_PrefsDlg.m_nCubicScale > 22) - g_PrefsDlg.m_nCubicScale = 22; - g_PrefsDlg.SavePrefs (); - Sys_UpdateWindows(W_CAMERA); - SetGridStatus(); -} - -void MainFrame::OnViewShownames() -{ - g_qeglobals.d_savedinfo.show_names = !g_qeglobals.d_savedinfo.show_names; - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_shownames")); - g_bIgnoreCommands++; - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - g_qeglobals.d_savedinfo.show_names ? TRUE : FALSE); - g_bIgnoreCommands--; - Sys_UpdateWindows (W_XY); -} - -void MainFrame::OnViewShowAngles() -{ - g_qeglobals.d_savedinfo.show_angles = !g_qeglobals.d_savedinfo.show_angles; - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showangles")); - g_bIgnoreCommands++; - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - g_qeglobals.d_savedinfo.show_angles ? TRUE : FALSE); - g_bIgnoreCommands--; - Sys_UpdateWindows (W_XY); -} - -void MainFrame::OnViewShowblocks() -{ - g_qeglobals.show_blocks ^= 1; - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showblocks")); - g_bIgnoreCommands++; - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_qeglobals.show_blocks ? TRUE : FALSE); - g_bIgnoreCommands--; - Sys_UpdateWindows (W_XY); -} - -void MainFrame::OnViewShowcoordinates() -{ - g_qeglobals.d_savedinfo.show_coordinates ^= 1; - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showcoordinates")); - g_bIgnoreCommands++; - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - g_qeglobals.d_savedinfo.show_coordinates ? TRUE : FALSE); - g_bIgnoreCommands--; - Sys_UpdateWindows (W_XY|W_Z); -} - -void MainFrame::OnViewShowOutline() -{ - g_qeglobals.d_savedinfo.show_outline ^= 1; - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showoutline")); - g_bIgnoreCommands++; - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - g_qeglobals.d_savedinfo.show_outline ? TRUE : FALSE); - g_bIgnoreCommands--; - Sys_UpdateWindows (W_XY); -} - -void MainFrame::OnViewShowAxes() -{ - g_qeglobals.d_savedinfo.show_axis ^= 1; - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showaxes")); - g_bIgnoreCommands++; - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), - g_qeglobals.d_savedinfo.show_axis ? TRUE : FALSE); - g_bIgnoreCommands--; - Sys_UpdateWindows (W_XY); -} - -void MainFrame::OnViewShowWorkzone() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showworkzone")); - g_bIgnoreCommands++; - if (g_qeglobals.d_show_work) - { - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); - g_qeglobals.d_show_work = false; - } else - { - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - g_qeglobals.d_show_work = true; - } - g_bIgnoreCommands--; - Sys_UpdateWindows (W_XY); -} - -void MainFrame::OnViewHideshowHideselected() -{ - Select_Hide(); - Select_Deselect(); -} - -void MainFrame::OnViewHideshowShowhidden() -{ - Select_ShowAllHidden(); -} - -/** -sets the view mode for the entities -called upon LoadPrefs too -NOTE TTimo previous implementation had a SavePrefs call - .. I don't think it is relevant, removed (the prefs are saved upon exit) -NOTE TTimo we activate the menu item, this is only needed when we are called upon a prefs load - (otherwise we are always called following user action on the widget) -*/ -void MainFrame::OnEntitiesSetViewAs(int mode) -{ - gpointer item = NULL; - if (mode == 0) - { - switch (g_PrefsDlg.m_nEntityShowState) - { - case ENTITY_BOX: - item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_boundingbox"); - break; - case ENTITY_WIRE: - item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_wireframe"); - break; - case ENTITY_SELECTED: - item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_selectedwireframe"); - break; - case ENTITY_SELECTED_SKIN: - item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_selectedskinned"); - break; - case ENTITY_SKINNED: - item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_skinned"); - break; - case ENTITY_SKINNED_BOXED: - item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_skinnedandboxed"); - break; - } - g_bIgnoreCommands++; - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - g_bIgnoreCommands--; - return; - } - - switch (mode) - { - case ID_VIEW_ENTITIESAS_BOUNDINGBOX: - g_PrefsDlg.m_nEntityShowState = ENTITY_BOX; - item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_boundingbox"); - break; - case ID_VIEW_ENTITIESAS_WIREFRAME: - g_PrefsDlg.m_nEntityShowState = ENTITY_WIRE; - item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_wireframe"); - break; - case ID_VIEW_ENTITIESAS_SELECTEDWIREFRAME: - g_PrefsDlg.m_nEntityShowState = ENTITY_SELECTED; - item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_selectedwireframe"); - break; - case ID_VIEW_ENTITIESAS_SELECTEDSKINNED: - g_PrefsDlg.m_nEntityShowState = ENTITY_SELECTED_SKIN; - item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_selectedskinned"); - break; - case ID_VIEW_ENTITIESAS_SKINNED: - g_PrefsDlg.m_nEntityShowState = ENTITY_SKINNED; - item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_skinned"); - break; - case ID_VIEW_ENTITIESAS_SKINNEDANDBOXED: - g_PrefsDlg.m_nEntityShowState = ENTITY_SKINNED_BOXED; - item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_skinnedandboxed"); - break; - default: - Sys_FPrintf(SYS_ERR, "Entity mode ID_ not found in MainFrame::Entities_SetViewAs\n"); - return; - } - - if (!item) - { - Sys_FPrintf(SYS_ERR, "menu not found in MainFrame::Entities_SetViewAs\n"); - return; - } - - g_bIgnoreCommands++; - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - g_bIgnoreCommands--; - - Sys_UpdateWindows(W_ALL); -} - -void MainFrame::OnViewCubicclipping() -{ - GtkWidget *w; - - g_PrefsDlg.m_bCubicClipping ^= 1; - g_bIgnoreCommands++; - w = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_cubicclipping")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), g_PrefsDlg.m_bCubicClipping ? TRUE : FALSE); - w = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_view_cubicclipping")); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), g_PrefsDlg.m_bCubicClipping ? TRUE : FALSE); - g_bIgnoreCommands--; - g_PrefsDlg.SavePrefs (); - //Map_BuildBrushData (); - Sys_UpdateWindows(W_CAMERA); -} - -void MainFrame::OnViewOpengllighting() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_opengllighting")); - g_PrefsDlg.m_bGLLighting ^= 1; - g_PrefsDlg.SavePrefs (); - g_bIgnoreCommands++; - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bGLLighting ? TRUE : FALSE); - Sys_UpdateWindows (W_XY|W_CAMERA); - g_bIgnoreCommands--; -} - -void MainFrame::OnSelectionDragedges() -{ - if (g_qeglobals.d_select_mode == sel_edge) - { - g_qeglobals.d_select_mode = sel_brush; - Sys_UpdateWindows (W_ALL); - } else - { - SetupVertexSelection (); - if (g_qeglobals.d_numpoints) - g_qeglobals.d_select_mode = sel_edge; - Sys_UpdateWindows (W_ALL); - } -} - -void MainFrame::OnSelectionDragvertecies() -{ - if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_curvepoint) - { - g_qeglobals.d_select_mode = sel_brush; - Sys_UpdateWindows (W_ALL); - } else - { - //--if (QE_SingleBrush() && selected_brushes.next->patchBrush) - if (OnlyPatchesSelected()) - { - Patch_EditPatch(); - } else //if (!AnyPatchesSelected()) // allows vertex mode when patches are selected - { - SetupVertexSelection (); - if (g_qeglobals.d_numpoints) - g_qeglobals.d_select_mode = sel_vertex; - } - Sys_UpdateWindows (W_ALL); - } -} - -void MainFrame::OnSelectionClone() -{ - Select_Clone(); -} - -// called when the escape key is used (either on the main window or on an inspector) -void MainFrame::OnSelectionDeselect() -{ - if (g_bClipMode) - OnViewClipper(); - else - if (g_bRotateMode) - OnSelectMouserotate(); - else - if (g_bScaleMode) - OnSelectMousescale(); - else - if (g_bPathMode) - { - if (ActiveXY()) - ActiveXY()->KillPathMode(); - } else - { - if (g_qeglobals.d_select_mode == sel_curvepoint && g_qeglobals.d_num_move_points > 0) - { - g_qeglobals.d_num_move_points = 0; - Sys_UpdateWindows(W_ALL); - } else - { - Select_Deselect (); - SetStatusText(2, " "); - } - } -} - -void MainFrame::OnBrushFlipx() -{ - Undo_Start("flip X"); - Undo_AddBrushList(&selected_brushes); - - Select_FlipAxis (0); - // spog - this does not work - it's a rotate not a flip - /* - for (brush_t *b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - { - if(b->owner->eclass->fixedsize) - { - char buf[16]; - float a = FloatForKey(b->owner, "angle"); - a = div ((int)(180 - a), 180).rem; - sprintf (buf, "%d", (int)a); - SetKeyValue(b->owner, "angle", buf); - Brush_Build(b,true,true,false,false); // don't filter - } - } - */ - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnBrushFlipy() -{ - Undo_Start("flip Y"); - Undo_AddBrushList(&selected_brushes); - - Select_FlipAxis (1); - // spog - this does not work - it's a rotate not a flip - /* - for (brush_t *b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - { - if(b->owner->eclass->fixedsize) - { - float a = FloatForKey(b->owner, "angle"); - if (a == 0 || a == 180 || a == 360) - continue; - if ( a == 90 || a == 270) - { - a += 180; - } - else if (a > 270) - a += 90; - else if (a > 180) - a -= 90; - else if (a > 90) - a += 90; - else - a -= 90; - a = (int)a % 360; - char buf[16]; - sprintf (buf, "%d", (int)a); - SetKeyValue(b->owner, "angle", buf); - Brush_Build(b,true,true,false,false); // don't filter - } - - } - */ - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnBrushFlipz() -{ - Undo_Start("flip Z"); - Undo_AddBrushList(&selected_brushes); - Select_FlipAxis (2); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnBrushRotatex() -{ - Undo_Start("rotate X"); - Undo_AddBrushList(&selected_brushes); - Select_RotateAxis (0, 90); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnBrushRotatey() -{ - Undo_Start("rotate Y"); - Undo_AddBrushList(&selected_brushes); - Select_RotateAxis (1, 90); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnBrushRotatez() -{ - Undo_Start("rotate Z"); - Undo_AddBrushList(&selected_brushes); - Select_RotateAxis (2, 90); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnSelectionArbitraryrotation() -{ - Undo_Start("arbitrary rotation"); - Undo_AddBrushList(&selected_brushes); - - DoRotateDlg (); - - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnSelectScale() -{ - Undo_Start("scale"); - Undo_AddBrushList(&selected_brushes); - DoScaleDlg (); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnSelectionMakehollow() -{ - //if (ActiveXY()) - // ActiveXY()->UndoCopy(); - Undo_Start("hollow"); - Undo_AddBrushList(&selected_brushes); - CSG_MakeHollow (); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnSelectionCsgsubtract() -{ - Undo_Start("CSG subtract"); - CSG_Subtract(); - Undo_End(); -} - -void MainFrame::OnSelectionCsgmerge() -{ - Undo_Start("CSG merge"); - Undo_AddBrushList(&selected_brushes); - CSG_Merge(); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnSelectionNoOutline() -{ - //g_qeglobals.d_savedinfo.bNoSelectedOutlines ^= 1; - g_qeglobals.d_savedinfo.iSelectedOutlinesStyle = (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_ZBUF) ^ OUTLINE_ZBUF; - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_selection_nooutline")); - g_bIgnoreCommands++; - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_ZBUF)); - g_bIgnoreCommands--; - Sys_UpdateWindows (W_CAMERA); -} - -void MainFrame::OnSelectionOutlineStyle() -{ - if ((g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_ZBUF) && (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_BSEL)) - g_qeglobals.d_savedinfo.iSelectedOutlinesStyle &= ~OUTLINE_ZBUF; - else if (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_BSEL) - g_qeglobals.d_savedinfo.iSelectedOutlinesStyle &= ~OUTLINE_BSEL; - else if (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_ZBUF) - g_qeglobals.d_savedinfo.iSelectedOutlinesStyle |= OUTLINE_BSEL; - else - g_qeglobals.d_savedinfo.iSelectedOutlinesStyle |= OUTLINE_ZBUF; - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_selection_nooutline")); - g_bIgnoreCommands++; - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_ZBUF)); - g_bIgnoreCommands--; - Sys_UpdateWindows (W_CAMERA); -} - -void MainFrame::OnSelectionSelectcompletetall() -{ - if (ActiveXY()) - ActiveXY()->UndoCopy(); - Select_CompleteTall (); -} - -void MainFrame::OnSelectionSelecttouching() -{ - Select_Touching(); -} - -void MainFrame::OnSelectionSelectpartialtall() -{ - Select_PartialTall(); -} - -void MainFrame::OnSelectionSelectinside() -{ - Select_Inside (); -} - -void MainFrame::OnViewClipper() -{ - GtkWidget *w = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_view_clipper")); - g_bIgnoreCommands++; - - if (ActiveXY()) - { - if (ActiveXY()->ClipMode()) - { - ActiveXY()->SetClipMode(false); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), FALSE); - } else - { - if (ActiveXY()->RotateMode()) - OnSelectMouserotate(); - ActiveXY()->SetClipMode(true); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), TRUE); - } - } - g_bIgnoreCommands--; -} - -void MainFrame::OnClipSelected() -{ - if (m_pActiveXY && m_pActiveXY->ClipMode()) - { - Undo_Start("clip selected"); - Undo_AddBrushList(&selected_brushes); - m_pActiveXY->Clip(); - Undo_EndBrushList(&selected_brushes); - Undo_End(); - } else - { - if (g_bPatchBendMode) - Patch_BendHandleENTER(); -// else if (g_bPatchBendMode) -// Patch_InsDelHandleENTER(); - } -} - -void MainFrame::OnSplitSelected() -{ - if (m_pActiveXY) - { - Undo_Start("split selected"); - Undo_AddBrushList(&selected_brushes); - m_pActiveXY->SplitClip(); - Undo_EndBrushList(&selected_brushes); - Undo_End(); - } -} - -void MainFrame::OnFlipClip() -{ - if (m_pActiveXY) - m_pActiveXY->FlipClip(); -} - -void MainFrame::OnSelectionConnect() -{ - Undo_Start("connect selected entities"); - Undo_AddBrushList(&selected_brushes); - ConnectEntities(); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnSelectionUngroupentity() -{ - Undo_Start("ungroup selected entities"); - Undo_AddBrushList(&selected_brushes); - Select_Ungroup(); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnSelectionMergeentity() -{ - Undo_Start("merge entity"); - Undo_AddBrushList(&selected_brushes); - Select_MergeEntity(); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnSelectionGroupworld() -{ - Undo_Start("group world"); - Undo_AddBrushList(&selected_brushes); - Select_GroupEntity(world_entity); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnSelectionMakeDetail() -{ - Undo_Start("make detail"); - Undo_AddBrushList(&selected_brushes); - Select_MakeDetail (); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnSelectionMakeStructural() -{ - Undo_Start("make structural"); - Undo_AddBrushList(&selected_brushes); - Select_MakeStructural (); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnBspCommand (unsigned int nID) -{ - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=503 - // make sure we don't attempt to region compile a map with the camera outside the region - if (region_active) - { - vec3_t vOrig; - VectorSet(vOrig, - (int)g_pParentWnd->GetCamWnd()->Camera()->origin[0], - (int)g_pParentWnd->GetCamWnd()->Camera()->origin[1], - (int)g_pParentWnd->GetCamWnd()->Camera()->origin[2]); - - int i; - for (i=0 ; i<3 ; i++) - { - if (vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i]) - { - Sys_FPrintf(SYS_ERR, "The camera must be in the region to start a region compile.\n"); - return; - } - } - } - - // if the map has not been saved yet we need to handle it now before we start processing the BSP commands - if (stricmp( currentmap, "unnamed.map") == 0) - { - OnFileSaveas(); - } - - if (g_PrefsDlg.m_bSnapShots && (stricmp (currentmap, "unnamed.map") != 0)) - Map_Snapshot(); - - if (g_qeglobals.bBSPFrontendPlugin) - { - char *cmd = (char*)g_slist_nth_data (g_BSPFrontendCommands, nID-CMD_BSPCOMMAND); - g_BSPFrontendTable.m_pfnDispatchBSPCommand (cmd); - } else - { - RunBsp (bsp_commands[nID-CMD_BSPCOMMAND]); - } -} - -void MainFrame::OnGrid (unsigned int nID) -{ - if (nID == ID_GRID_025) - { - g_qeglobals.d_gridsize = 0.25f; - g_qeglobals.d_bSmallGrid = true; - } else if (nID == ID_GRID_05) - { - g_qeglobals.d_gridsize = 0.5f; - g_qeglobals.d_bSmallGrid = true; - } else - { - switch (nID) - { - case ID_GRID_1: g_qeglobals.d_gridsize = 0; break; - case ID_GRID_2: g_qeglobals.d_gridsize = 1; break; - case ID_GRID_4: g_qeglobals.d_gridsize = 2; break; - case ID_GRID_8: g_qeglobals.d_gridsize = 3; break; - case ID_GRID_16: g_qeglobals.d_gridsize = 4; break; - case ID_GRID_32: g_qeglobals.d_gridsize = 5; break; - case ID_GRID_64: g_qeglobals.d_gridsize = 6; break; - case ID_GRID_128: g_qeglobals.d_gridsize = 7; break; - case ID_GRID_256: g_qeglobals.d_gridsize = 8; break; - } - g_qeglobals.d_gridsize = 1 << (int)g_qeglobals.d_gridsize; - g_qeglobals.d_bSmallGrid = false; - } - - SetGridStatus(); - - // SnapTToGrid option: need to check everywhere the grid size is changed - // this is a bit clumsy, have to do in OnGrid OnGridPrev and OnGridNext - if (g_PrefsDlg.m_bSnapTToGrid) - DoSnapTToGrid(); - - Sys_UpdateWindows (W_XY|W_Z); -} - -void MainFrame::OnSnaptogrid() -{ - g_PrefsDlg.m_bNoClamp ^= 1; - g_PrefsDlg.SavePrefs (); - - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_snaptogrid")); - g_bIgnoreCommands++; - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bNoClamp ? FALSE : TRUE); - g_bIgnoreCommands--; -} - -void MainFrame::OnTexturesShowinuse() -{ - Sys_BeginWait (); - Texture_ShowInuse (); -#ifdef _DEBUG - if (!g_bShowAllShaders) - Sys_Printf("Already showing only in-use textures.\n"); -#endif - Sys_UpdateWindows( W_TEXTURE ); - Sys_EndWait (); -} - -void MainFrame::OnTexturesShowall() -{ - Texture_ShowAll(); -} - -// do some triggering on/off, if the inspector is already up then hide it -void MainFrame::OnTexturesInspector() -{ - ToggleSurface(); -} - -void MainFrame::OnViewNearest(unsigned int nID) -{ - Texture_SetMode(nID); -} - -void MainFrame::OnTextureReplaceall() -{ - FindTextureDialog::show(); -} - -void MainFrame::OnToggleLock() -{ - g_PrefsDlg.m_bTextureLock = !g_PrefsDlg.m_bTextureLock; - - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_toggle_lock")); - g_bIgnoreCommands++; - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bTextureLock ? TRUE : FALSE); - g_bIgnoreCommands--; - g_PrefsDlg.SavePrefs (); - SetGridStatus(); -} - -void MainFrame::OnToggleRotatelock() -{ - g_PrefsDlg.m_bRotateLock ^= 1; - - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_toggle_rotatelock")); - g_bIgnoreCommands++; - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bRotateLock ? TRUE : FALSE); - g_bIgnoreCommands--; - g_PrefsDlg.SavePrefs (); - SetGridStatus(); -} - -// use a dialog for direct selection of a texture menu -// the API is a bit crappy, we need to set texture_directory to the directory name in /textures/ -void MainFrame::OnTexturesLoad() -{ - char def_path[NAME_MAX]; - - // FIXME - // check if that works with fs_game (I suspect some more design is needed) - // see how this is done in 1.2? - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=507 - strcpy (def_path, g_pGameDescription->mEnginePath.GetBuffer()); - strcat (def_path, g_pGameDescription->mBaseGame.GetBuffer()); - strcat (def_path, "/"); - - char *dir = dir_dialog (m_pWidget, "Load textures from path", def_path); - - if (dir != NULL) - { - // very uncertain task, let's hope the guy pointed to somewhere below the dir we gave him - Sys_Printf("user select: '%s'\n", dir); - // remove a potential trailing slash? - if (dir[strlen(dir)-1]=='/' || dir[strlen(dir)-1]=='\\') - dir[strlen(dir)-1] = '\0'; - char *pouic = MAX(strrchr(dir, '/'),strrchr(dir, '\\')); - if (pouic) - { - strcpy(texture_directory, pouic+1); - Sys_Printf("Loading '%s'\n", texture_directory); - Texture_ShowDirectory(); - } - else - Sys_FPrintf(SYS_WRN, "Failed to extract the directory\n"); - g_free(dir); - } - else - Sys_FPrintf(SYS_WRN, "texture load dialog cancelled\n"); -} - -void MainFrame::OnTexturesReloadshaders() -{ - Sys_BeginWait (); - QERApp_ReloadShaders(); - // current shader - // NOTE: we are kinda making it loop on itself, it will update the pShader and scroll the texture window - Texture_SetTexture (&g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef, false, NULL, false); - Sys_UpdateWindows (W_ALL); - Sys_EndWait(); -} - -void MainFrame::OnTexturesShadersShow() -{ - g_PrefsDlg.m_bShowShaders ^= 1; - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_shaders_show")); - g_bIgnoreCommands++; - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bShowShaders ? TRUE : FALSE); - g_bIgnoreCommands--; - Sys_UpdateWindows(W_TEXTURE); -} - -void MainFrame::SetTextureScale(int id) -{ - GtkWidget *item; - - switch (id) - { - case ID_TEXTURES_TEXTUREWINDOWSCALE_10: - g_PrefsDlg.m_nTextureScale = 10; - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_texturewindowscale_10")); - break; - case ID_TEXTURES_TEXTUREWINDOWSCALE_25: - g_PrefsDlg.m_nTextureScale = 25; - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_texturewindowscale_25")); - break; - case ID_TEXTURES_TEXTUREWINDOWSCALE_50: - g_PrefsDlg.m_nTextureScale = 50; - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_texturewindowscale_50")); - break; - case ID_TEXTURES_TEXTUREWINDOWSCALE_200: - g_PrefsDlg.m_nTextureScale = 200; - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_texturewindowscale_200")); - break; - default: - g_PrefsDlg.m_nTextureScale = 100; - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_texturewindowscale_100")); - break; - } - - g_bIgnoreCommands++; - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - g_bIgnoreCommands--; - - Texture_ResetPosition(); -} - -void MainFrame::OnTexturewindowScaleup() -{ - switch(g_PrefsDlg.m_nTextureScale) { - // 200, all the way in, don't do anything - case 100: - SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_200); - break; - case 50: - SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_100); - break; - case 25: - SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_50); - break; - case 10: - SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_25); - break; - } -} - -void MainFrame::OnTexturewindowScaledown() -{ - switch(g_PrefsDlg.m_nTextureScale) { - case 200: - SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_100); - break; - case 100: - SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_50); - break; - case 50: - SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_25); - break; - case 25: - SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_10); - break; - // 10, all the way out, don't do anything - } -} - -void MainFrame::OnTexturesLoadlist() -{ - DoTextureListDlg (); -} - -void MainFrame::OnTexturesShaderlistonly() -{ - g_PrefsDlg.m_bTexturesShaderlistOnly ^= 1; - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget),"menu_textures_shaderlistonly")); - g_bIgnoreCommands++; - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bTexturesShaderlistOnly ? TRUE : FALSE); - g_bIgnoreCommands--; - FillTextureMenu(); -} - -void MainFrame::OnTextureWad(unsigned int nID) -{ - Sys_BeginWait (); - Texture_ShowDirectory (nID); - Sys_UpdateWindows (W_ALL); - Sys_EndWait (); -} - -void MainFrame::OnMiscBenchmark() -{ - m_pCamWnd->BenchMark(); -} - -void MainFrame::OnColorSetoriginal() -{ - for (int i=0 ; i<3 ; i++) - { - g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][i] = 0.25f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][i] = 1.0f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR][i] = 0.75f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR][i] = 0.5f; - g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][i] = 0.25f; - } - - //djbob - g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR_ALT][0] = 0.5f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR_ALT][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR_ALT][2] = 0.0f; - - g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR_ALT][0] = 1.0f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR_ALT][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR_ALT][2] = 0.0f; - //-djbob - - g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][0] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][2] = 1.0f; - - g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][0] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][2] = 0.0f; - - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0] = 1.0f; - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2] = 0.0f; - - g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][0] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][2] = 1.0f; - - g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][0] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][2] = 0.0f; - - g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][0] = 0.5f; - g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][2] = 0.75f; - - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][0] = 1.0f; - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][2] = 0.0f; - - Sys_UpdateWindows (W_ALL); -} - -void MainFrame::OnColorSetqer() -{ - for (int i=0 ; i<3 ; i++) - { - g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][i] = 0.25f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][i] = 1.0f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR][i] = 1.0f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR][i] = 0.5f; - g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][i] = 0.25f; - } - - g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][0] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][2] = 1.0f; - - g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][0] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][2] = 0.0f; - - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0] = 1.0f; - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2] = 0.0f; - - g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][0] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][2] = 1.0f; - - g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][0] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][2] = 0.0f; - - g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][0] = 0.5f; - g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][2] = 0.75f; - - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][0] = 1.0f; - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][2] = 0.0f; - - Sys_UpdateWindows (W_ALL); -} - -void MainFrame::OnColorSetblack() -{ - for (int i=0 ; i<3 ; i++) - { - g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][i] = 0.25f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][i] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR][i] = 0.2f; - g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][i] = 0.25f; - } - - g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR][0] = 0.3f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR][1] = 0.5f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR][2] = 0.5f; - - g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][0] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][2] = 1.0f; - - g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][0] = 1.0f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][1] = 1.0f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][2] = 1.0f; - - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0] = 1.0f; - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2] = 0.0f; - - g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][0] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][2] = 1.0f; - - g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][0] = 1.0f; - g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][1] = 1.0f; - g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][2] = 1.0f; - - g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][0] = 0.7f; - g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][1] = 0.7f; - g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][2] = 0.0f; - - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][0] = 1.0f; - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][2] = 0.0f; - - Sys_UpdateWindows (W_ALL); -} - -/* ydnar: to emulate maya/max/lightwave color schemes */ -void MainFrame::OnColorSetydnar() -{ - for (int i=0 ; i<3 ; i++) - { - g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][i] = 0.25f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][i] = 0.77f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR][i] = 0.83f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR][i] = 0.89f; - g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][i] = 0.25f; - } - - g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][0] = 1.0f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][1] = 1.0f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][2] = 1.0f; - - g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][0] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][2] = 0.0f; - - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0] = 1.0f; - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2] = 0.0f; - - g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][0] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][2] = 1.0f; - - g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][0] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][2] = 0.0f; - - g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][0] = 0.5f; - g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][2] = 0.75f; - - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][0] = 1.0f; - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][1] = 0.0f; - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][2] = 0.0f; - - Sys_UpdateWindows (W_ALL); -} - -void MainFrame::OnTexturebk() -{ - DoColor(COLOR_TEXTUREBACK); - Sys_UpdateWindows (W_ALL); -} - -void MainFrame::OnColorsXybk() -{ - DoColor(COLOR_GRIDBACK); - Sys_UpdateWindows (W_ALL); -} - -void MainFrame::OnColorsMajor() -{ - DoColor(COLOR_GRIDMAJOR); - Sys_UpdateWindows (W_ALL); -} - -void MainFrame::OnColorsMinor() -{ - DoColor(COLOR_GRIDMINOR); - Sys_UpdateWindows (W_ALL); -} - -void MainFrame::OnColorsMajor_Alt() -{ - DoColor(COLOR_GRIDMAJOR_ALT); - Sys_UpdateWindows (W_ALL); -} - -void MainFrame::OnColorsMinor_Alt() -{ - DoColor(COLOR_GRIDMINOR_ALT); - Sys_UpdateWindows (W_ALL); -} - -void MainFrame::OnColorsGridtext() -{ - DoColor(COLOR_GRIDTEXT); - Sys_UpdateWindows (W_ALL); -} - -void MainFrame::OnColorsGridblock() -{ - DoColor(COLOR_GRIDBLOCK); - Sys_UpdateWindows (W_ALL); -} - -void MainFrame::OnColorsCameraBack() -{ - DoColor(COLOR_CAMERABACK); - Sys_UpdateWindows (W_ALL); -} - -void MainFrame::OnColorsBrush() -{ - DoColor(COLOR_BRUSHES); - Sys_UpdateWindows (W_ALL); -} - -void MainFrame::OnColorsSelectedbrush() -{ - DoColor(COLOR_SELBRUSHES); - Sys_UpdateWindows (W_ALL); -} - -void MainFrame::OnColorsSelectedbrush3D() -{ - DoColor(COLOR_SELBRUSHES3D); - Sys_UpdateWindows (W_ALL); -} - -void MainFrame::OnColorsClipper() -{ - DoColor(COLOR_CLIPPER); - Sys_UpdateWindows (W_ALL); -} - -void MainFrame::OnColorsViewname() -{ - DoColor(COLOR_VIEWNAME); - Sys_UpdateWindows (W_ALL); -} - -void MainFrame::OnMiscGamma() -{ - float fSave = g_qeglobals.d_savedinfo.fGamma; - DoGamma(); - if (fSave != g_qeglobals.d_savedinfo.fGamma) - { - gtk_MessageBox(m_pWidget, "You must restart Radiant for Gamma settings to take effect."); - } -} -void MainFrame::OnMiscFindbrush() -{ - DoFind(); -} - -void MainFrame::OnMiscNextleakspot() -{ - Pointfile_Next(); -} - -void MainFrame::OnMiscPreviousleakspot() -{ - Pointfile_Prev(); -} - -void MainFrame::OnMiscPrintxy() -{ -// WXY_Print(); -} - -void MainFrame::OnMiscSelectentitycolor() -{ - if (edit_entity) - { - CString strColor = ValueForKey(edit_entity, "_color"); - if (strColor.GetLength() > 0) - { - float fR, fG, fB; - int n = sscanf(strColor,"%f %f %f", &fR, &fG, &fB); - if (n == 3) - { - g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][0] = fR; - g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][1] = fG; - g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][2] = fB; - } - } - - if (inspector_mode == W_ENTITY && (DoColor(COLOR_ENTITY))) - { - char buffer[100]; - sprintf(buffer, "%f %f %f", g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][0], - g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][1], - g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][2]); - - gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntValueField]), buffer); - gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntKeyField]), "_color"); - AddProp(); - //DK - SOF change to get color to entity quickly - //--::SetWindowText( hwndEnt[EntValueField], buffer ); - //--::SetWindowText( hwndEnt[EntKeyField], "color" ); - //--AddProp(); - } - Sys_UpdateWindows( W_ALL ); - } -} - -void MainFrame::OnConvertcurves() -{ -#if 0 - Select_Deselect(); - for (brush_t* pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next) - { - if (pb->curveBrush) - { - for (face_t* f = pb->brush_faces ; f ; f=f->next) - { - if (f->texdef.contents & CONTENTS_LADDER) - { - f->texdef.contents &= ~CONTENTS_LADDER; - f->texdef.contents |= CONTENTS_NEGATIVE_CURVE; - } - } - } - } - Map_BuildBrushData(); -#endif -} - -void MainFrame::OnRegionOff() -{ - Map_RegionOff (); -} - -void MainFrame::OnRegionSetxy() -{ - Map_RegionXY (); -} - -void MainFrame::OnRegionSettallbrush() -{ - Map_RegionTallBrush (); -} - -void MainFrame::OnRegionSetbrush() -{ - Map_RegionBrush (); -} - -void MainFrame::OnRegionSetselection() -{ - Map_RegionSelectedBrushes (); -} - -void MainFrame::OnBrush3sided() -{ - Undo_Start("3 sided"); - Undo_AddBrushList(&selected_brushes); - Brush_MakeSided(3); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnBrush4sided() -{ - Undo_Start("4 sided"); - Undo_AddBrushList(&selected_brushes); - Brush_MakeSided(4); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnBrush5sided() -{ - Undo_Start("5 sided"); - Undo_AddBrushList(&selected_brushes); - Brush_MakeSided(5); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnBrush6sided() -{ - Undo_Start("6 sided"); - Undo_AddBrushList(&selected_brushes); - Brush_MakeSided(6); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnBrush7sided() -{ - Undo_Start("7 sided"); - Undo_AddBrushList(&selected_brushes); - Brush_MakeSided(7); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnBrush8sided() -{ - Undo_Start("8 sided"); - Undo_AddBrushList(&selected_brushes); - Brush_MakeSided(8); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnBrush9sided() -{ - Undo_Start("9 sided"); - Undo_AddBrushList(&selected_brushes); - Brush_MakeSided(9); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnBrushArbitrarysided() -{ - Undo_Start("arbitrary sided"); - Undo_AddBrushList(&selected_brushes); - DoSides(); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnBrushMakecone() -{ - Undo_Start("make cone"); - Undo_AddBrushList(&selected_brushes); - DoSides(true); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnBrushPrimitivesSphere() -{ - Undo_Start("make sphere"); - Undo_AddBrushList(&selected_brushes); - - DoSides(false, true); - - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurvePatchtube() -{ - Undo_Start("make curve cylinder"); - Undo_AddBrushList(&selected_brushes); - Patch_BrushToMesh(false); - Sys_UpdateWindows (W_ALL); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurvePatchdensetube() -{ - Undo_Start("dense cylinder"); - Undo_AddBrushList(&selected_brushes); - - Patch_BrushToMesh(false); - OnCurveInsertAddrow(); - Sys_UpdateWindows (W_ALL); - - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurvePatchverydensetube() -{ - Undo_Start("very dense cylinder"); - Undo_AddBrushList(&selected_brushes); - - Patch_BrushToMesh(false); - OnCurveInsertAddrow(); - OnCurveInsertInsertrow(); - OnCurveInsertAddrow(); - Sys_UpdateWindows (W_ALL); - - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurvePatchsquare() -{ - Undo_Start("square cylinder"); - Undo_AddBrushList(&selected_brushes); - - Patch_BrushToMesh(false, false, false, true); - Sys_UpdateWindows (W_ALL); - - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurvePatchendcap() -{ - Undo_Start("make end cap"); - Undo_AddBrushList(&selected_brushes); - Patch_BrushToMesh(false, false, true); - Sys_UpdateWindows (W_ALL); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurvePatchbevel() -{ - Undo_Start("make bevel"); - Undo_AddBrushList(&selected_brushes); - Patch_BrushToMesh(false, true, false); - Sys_UpdateWindows (W_ALL); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurveMoreendcapsbevelsSquarebevel() -{ - Undo_Start("square bevel"); - Undo_AddBrushList(&selected_brushes); - - Patch_BrushToMesh(false, true, false, true); - Sys_UpdateWindows (W_ALL); - - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurveMoreendcapsbevelsSquareendcap() -{ - Undo_Start("square endcap"); - Undo_AddBrushList(&selected_brushes); - - Patch_BrushToMesh(false, false, true, true); - Sys_UpdateWindows (W_ALL); - - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurvePatchcone() -{ - Undo_Start("make curve cone"); - Undo_AddBrushList(&selected_brushes); - Patch_BrushToMesh(true); - Sys_UpdateWindows (W_ALL); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurveSimplepatchmesh() -{ - Undo_Start("make simpe patch mesh"); - Undo_AddBrushList(&selected_brushes); - DoNewPatchDlg (); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurveInsertInsertcolumn() -{ - Undo_Start("insert (2) columns"); - Undo_AddBrushList(&selected_brushes); - Patch_AdjustSelected(true, true, false); - Sys_UpdateWindows(W_ALL); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurveInsertAddcolumn() -{ - Undo_Start("add (2) columns"); - Undo_AddBrushList(&selected_brushes); - Patch_AdjustSelected(true, true, true); - Sys_UpdateWindows(W_ALL); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurveInsertInsertrow() -{ - Undo_Start("insert (2) rows"); - Undo_AddBrushList(&selected_brushes); - Patch_AdjustSelected(true, false, false); - Sys_UpdateWindows(W_ALL); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurveInsertAddrow() -{ - Undo_Start("add (2) rows"); - Undo_AddBrushList(&selected_brushes); - Patch_AdjustSelected(true, false, true); - Sys_UpdateWindows(W_ALL); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurveDeleteFirstcolumn() -{ - Undo_Start("delete first (2) columns"); - Undo_AddBrushList(&selected_brushes); - Patch_AdjustSelected(false, true, true); - Sys_UpdateWindows(W_ALL); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurveDeleteLastcolumn() -{ - Undo_Start("delete last (2) columns"); - Undo_AddBrushList(&selected_brushes); - Patch_AdjustSelected(false, true, false); - Sys_UpdateWindows(W_ALL); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurveDeleteFirstrow() -{ - Undo_Start("delete first (2) rows"); - Undo_AddBrushList(&selected_brushes); - Patch_AdjustSelected(false, false, true); - Sys_UpdateWindows(W_ALL); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurveDeleteLastrow() -{ - Undo_Start("delete last (2) rows"); - Undo_AddBrushList(&selected_brushes); - Patch_AdjustSelected(false, false, false); - Sys_UpdateWindows(W_ALL); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurveNegative() -{ - Patch_ToggleInverted(); - //Sys_UpdateWindows(W_ALL); -} - -void MainFrame::OnCurveRedisperseRows() -{ - Undo_Start("redisperse rows"); - Undo_AddBrushList(&selected_brushes); - Patch_DisperseRows(); - Sys_UpdateWindows (W_ALL); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurveRedisperseIntermediateCols() -{ - Undo_Start("redisperse im cols"); - Undo_AddBrushList(&selected_brushes); - Patch_DisperseIntermediateColumns(); - Sys_UpdateWindows (W_ALL); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurveRedisperseIntermediateRows() -{ - Undo_Start("redisperse im rows"); - Undo_AddBrushList(&selected_brushes); - Patch_DisperseIntermediateRows(); - Sys_UpdateWindows (W_ALL); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurveMatrixTranspose() -{ - Patch_Transpose(); - Sys_UpdateWindows (W_ALL); -} - -void MainFrame::OnCurveCap() -{ - Patch_CapCurrent(); - Sys_UpdateWindows (W_ALL); -} - -void MainFrame::OnCurveCyclecap() -{ - Patch_CycleCapSelected(); - Sys_UpdateWindows (W_ALL); -} - -void MainFrame::OnCurveOverlaySet() -{ - Patch_SetOverlays(); - Sys_UpdateWindows(W_ALL); -} - -void MainFrame::OnCurveOverlayClear() -{ - Patch_ClearOverlays(); - Sys_UpdateWindows(W_ALL); -} - -void MainFrame::OnCurveThicken() -{ - Undo_Start("curve thicken"); - Undo_AddBrushList(&selected_brushes); - DoThickenDlg (); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -/*! -this can no longer be trigger manually from the menu -happens only once at startup -*/ -void MainFrame::OnPluginsRefresh() -{ - CleanPlugInMenu(); - m_PlugInMgr.Init(); -} - -// open the Q3Rad manual -void MainFrame::OnHelp() -{ - // at least on win32, g_strGameToolsPath + "Q3Rad_Manual/index.htm" - Str help; - help = g_strAppPath; - help += "Q3Rad_Manual/index.htm"; - OpenURL(help.GetBuffer()); -} - -// FIXME: we'll go towards a unified help thing soon -void MainFrame::OnHelpLinks() -{ - Str link; - link = g_strAppPath; - link += "links.htm"; - OpenURL(link.GetBuffer()); -} - -void MainFrame::OnHelpBugreport() -{ - OpenURL("http://www.qeradiant.com/faq/fom-serve/cache/138.html"); -} - -void MainFrame::OnHelpCommandlist() -{ - DoCommandListDlg (); -} - -void MainFrame::OnHelpAbout() -{ - DoAbout(); -} - -void MainFrame::OnPopupSelection() -{ - GtkWidget *menu, *item; - char *labels[] = { "Select Complete Tall", "Select Touching", "Select Partial Tall", "Select Inside"}; - int ids[] = { ID_SELECTION_SELECTCOMPLETETALL, ID_SELECTION_SELECTTOUCHING, - ID_SELECTION_SELECTPARTIALTALL, ID_SELECTION_SELECTINSIDE}; - - menu = gtk_menu_new (); - - for (int i = 0; i < 4; i++) - { - item = gtk_menu_item_new_with_label (labels[i]); - gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (ids[i])); - gtk_widget_show (item); - gtk_menu_append (GTK_MENU (menu), item); - } - - gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME); -} - -void MainFrame::OnViewChange() -{ - OnViewNextview(); - //HandlePopup(this, IDR_POPUP_VIEW); -} - -void MainFrame::OnTexturesPopup() -{ - gpointer item = g_object_get_data (G_OBJECT (m_pWidget), "render_quality_menu"); - gtk_menu_popup (GTK_MENU (item), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME); -} - -void MainFrame::ToggleCamera() -{ - if (m_bCamPreview) - m_bCamPreview = false; - else - m_bCamPreview = true; -} - -void MainFrame::OnViewCameraupdate() -{ - Sys_UpdateWindows(W_CAMERA); -} - -void MainFrame::OnSelectMouserotate() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_select_mouserotate")); - g_bIgnoreCommands++; - - if (ActiveXY()) - { - if (ActiveXY()->ClipMode()) - OnViewClipper(); - if (ActiveXY()->RotateMode()) - { - // SetRotateMode(false) always works - ActiveXY()->SetRotateMode(false); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), FALSE); - } else - { - // may not work if no brush selected, see return value - if (ActiveXY()->SetRotateMode(true)) - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), TRUE); - else - // if MFC called, we need to set back to FALSE ourselves - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), FALSE); - } - } - g_bIgnoreCommands--; -} - -void MainFrame::OnSelectMousescale() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_select_mousescale")); - g_bIgnoreCommands++; - - if (ActiveXY()) - { - if (ActiveXY()->ClipMode()) - OnViewClipper(); - if (ActiveXY()->RotateMode()) - { - // SetRotateMode(false) always works - ActiveXY()->SetRotateMode(false); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), FALSE); - } - if (ActiveXY()->ScaleMode()) - { - ActiveXY()->SetScaleMode(false); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), FALSE); - } else - { - ActiveXY()->SetScaleMode(true); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), TRUE); - } - } - g_bIgnoreCommands--; -} - -void MainFrame::OnScalelockx() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_scalelockx")); - g_bIgnoreCommands++; - - if (g_nScaleHow & SCALE_X) - { - g_nScaleHow ^= SCALE_X; - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), FALSE); - } else - { - g_nScaleHow |= SCALE_X; - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), TRUE); - } - g_bIgnoreCommands--; -} - -void MainFrame::OnScalelocky() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_scalelocky")); - g_bIgnoreCommands++; - - if (g_nScaleHow & SCALE_Y) - { - g_nScaleHow ^= SCALE_Y; - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), FALSE); - } else - { - g_nScaleHow |= SCALE_Y; - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), TRUE); - } - g_bIgnoreCommands--; -} - -void MainFrame::OnScalelockz() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_scalelockz")); - g_bIgnoreCommands++; - - if (g_nScaleHow & SCALE_Z) - { - g_nScaleHow ^= SCALE_Z; - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), FALSE); - } else - { - g_nScaleHow |= SCALE_Z; - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), TRUE); - } - g_bIgnoreCommands--; -} - -void MainFrame::OnDontselectcurve() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_dontselectcurve")); - g_bIgnoreCommands++; - g_PrefsDlg.m_bSelectCurves ^= 1; - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_PrefsDlg.m_bSelectCurves) ? FALSE : TRUE); - g_bIgnoreCommands--; -} - -void MainFrame::OnPatchToggleBox() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_showboundingbox")); - g_bIgnoreCommands++; - g_bPatchShowBounds ^= 1; - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchShowBounds) ? TRUE : FALSE); - g_bIgnoreCommands--; - Sys_UpdateWindows(W_ALL); -} - -void MainFrame::OnPatchWireframe() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_wireframe")); - g_bIgnoreCommands++; - g_bPatchWireFrame ^= 1; - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchWireFrame) ? TRUE : FALSE); - g_bIgnoreCommands--; - Sys_UpdateWindows(W_ALL); -} - -void MainFrame::OnPatchBend() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_bend")); - g_bIgnoreCommands++; - Patch_BendToggle(); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchBendMode) ? TRUE : FALSE); - g_bIgnoreCommands--; - Sys_UpdateWindows(W_ALL); -} - -void MainFrame::OnPatchWeld() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_weld")); - g_bIgnoreCommands++; - g_bPatchWeld ^= 1; - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchWeld) ? TRUE : FALSE); - g_bIgnoreCommands--; - Sys_UpdateWindows(W_ALL); -} - -void MainFrame::OnPatchDrilldown() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_drilldown")); - g_bIgnoreCommands++; - g_bPatchDrillDown ^= 1; - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchDrillDown) ? TRUE : FALSE); - g_bIgnoreCommands--; - Sys_UpdateWindows(W_ALL); -} - -void MainFrame::OnShowEntities() -{ - gpointer item = g_object_get_data (G_OBJECT (m_pWidget), "view_entitiesas_menu"); // use pointer to existing menu object - gtk_menu_popup (GTK_MENU (item), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME); -} - -void MainFrame::OnDropGroupName() -{ - /* - char* name = DoNameDlg ("Name Selection"); - - if (name != NULL) - { - Select_Name (name); - Sys_UpdateWindows (W_ALL); - free (name); - } - */ -} - -void MainFrame::OnDropGroupNewgroup() -{ - -} - -void MainFrame::OnDropGroupRemove() -{ - /* - Select_AddToGroup("World"); - Sys_UpdateWindows (W_ALL); - */ -} - -// NOTE: it's called OnFaceFit() but we want to process everything here, faces and patches -void MainFrame::OnFaceFit() -{ - SurfaceDlgFitAll(); -} - -void MainFrame::OnDontselectmodel() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_dontselectmodel")); - g_bIgnoreCommands++; - g_PrefsDlg.m_bSelectModels ^= 1; - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_PrefsDlg.m_bSelectModels) ? FALSE : TRUE); - g_bIgnoreCommands--; -} - -void MainFrame::OnViewTexture() -{ - if (FloatingGroupDialog()) // QE4 style - { - if (inspector_mode == W_TEXTURE) - { - if (GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity)) - widget_delete_hide (g_qeglobals_gui.d_entity); - else - gtk_widget_show (g_qeglobals_gui.d_entity); - } else - { - gtk_widget_show (g_qeglobals_gui.d_entity); - SetInspectorMode (W_TEXTURE); - } - } -} - -void MainFrame::OnPatchInspector() -{ - TogglePatchInspector(); -} - -void MainFrame::OnCurveNegativeTextureX() -{ - Patch_InvertTexture(false); - //Sys_UpdateWindows(W_ALL); -} - -void MainFrame::OnCurveNegativeTextureY() -{ - Patch_InvertTexture(true); - //Sys_UpdateWindows(W_ALL); -} - -void MainFrame::OnCurveInsertcolumn() -{ - if (&selected_brushes == selected_brushes.next) - return; - Undo_Start("insert colum"); - Undo_AddBrushList(&selected_brushes); - //Patch_AdjustSelectedRowCols(0, 2); - Patch_AdjustSelected(true, true, true); - Sys_UpdateWindows(W_ALL); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurveInsertrow() -{ - if (&selected_brushes == selected_brushes.next) - return; - Undo_Start("insert row"); - Undo_AddBrushList(&selected_brushes); - //Patch_AdjustSelectedRowCols(2, 0); - Patch_AdjustSelected(true, false, true); - Sys_UpdateWindows(W_ALL); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurveDeletecolumn() -{ - if (&selected_brushes == selected_brushes.next) - return; - Undo_Start("delete column"); - Undo_AddBrushList(&selected_brushes); - Patch_AdjustSelected(false, true, true); - Sys_UpdateWindows(W_ALL); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnCurveDeleterow() -{ - if (&selected_brushes == selected_brushes.next) - return; - Undo_Start("delete row"); - Undo_AddBrushList(&selected_brushes); - Patch_AdjustSelected(false, false, true); - Sys_UpdateWindows(W_ALL); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnPatchTab() -{ - if (g_bPatchBendMode) - Patch_BendHandleTAB(); -// else if (g_bPatchInsertMode) -// Patch_InsDelHandleTAB(); - else - { - // check to see if the selected brush is part of a func group - // if it is, deselect everything and reselect the next brush - // in the group - brush_t *b2, *b = selected_brushes.next; - entity_t * e; - if (b != &selected_brushes) - { - if (strcmpi(b->owner->eclass->name, "worldspawn") != 0) - { - e = b->owner; - Select_Deselect(); - for (b2 = e->brushes.onext ; b2 != &e->brushes ; b2 = b2->onext) - { - if (b == b2) - { - b2 = b2->onext; - break; - } - } - if (b2 == &e->brushes) - b2 = b2->onext; - - Select_Brush(b2, false); - Sys_UpdateWindows(W_ALL); - } - } - } -} - -void MainFrame::OnCameraForward(bool keydown) -{ - if (g_PrefsDlg.m_bCamDiscrete && (m_pCamWnd && !m_pCamWnd->m_bFreeMove) ) - { - if(keydown) - { - VectorMA (m_pCamWnd->Camera()->origin, SPEED_MOVE, m_pCamWnd->Camera()->forward, m_pCamWnd->Camera()->origin); - int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); - Sys_UpdateWindows (nUpdate); - } - } - else { - if (keydown) - m_pCamWnd->Camera()->movementflags |= MOVE_FORWARD; - else - m_pCamWnd->Camera()->movementflags &= ~MOVE_FORWARD; - } -} - -void MainFrame::OnCameraBack(bool keydown) -{ - if (g_PrefsDlg.m_bCamDiscrete && (m_pCamWnd && !m_pCamWnd->m_bFreeMove) ) - { - if(keydown) - { - VectorMA (m_pCamWnd->Camera()->origin, -SPEED_MOVE, m_pCamWnd->Camera()->forward, m_pCamWnd->Camera()->origin); - int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); - Sys_UpdateWindows (nUpdate); - } - } - else { - if (keydown) - m_pCamWnd->Camera()->movementflags |= MOVE_BACK; - else - m_pCamWnd->Camera()->movementflags &= ~MOVE_BACK; - } -} - -void MainFrame::OnCameraLeft(bool keydown) -{ - if (m_pCamWnd) - { - if (m_pCamWnd->m_bFreeMove) - { - OnCameraStrafeleft(keydown); - return; - } - } - - if (g_PrefsDlg.m_bCamDiscrete) - { - if(keydown) - { - m_pCamWnd->Camera()->angles[1] += SPEED_TURN; - int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); - Sys_UpdateWindows (nUpdate); - } - } - else { - if (keydown) - m_pCamWnd->Camera()->movementflags |= MOVE_ROTLEFT; - else - m_pCamWnd->Camera()->movementflags &= ~MOVE_ROTLEFT; - } -} - -void MainFrame::OnCameraRight(bool keydown) -{ - if (m_pCamWnd) - { - if (m_pCamWnd->m_bFreeMove) - { - OnCameraStraferight(keydown); - return; - } - } - - if (g_PrefsDlg.m_bCamDiscrete) - { - if(keydown) - { - m_pCamWnd->Camera()->angles[1] -= SPEED_TURN; - int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); - Sys_UpdateWindows (nUpdate); - } - } - else { - if (keydown) - m_pCamWnd->Camera()->movementflags |= MOVE_ROTRIGHT; - else - m_pCamWnd->Camera()->movementflags &= ~MOVE_ROTRIGHT; - } -} - -void MainFrame::OnCameraUp() -{ - m_pCamWnd->Camera()->origin[2] += SPEED_MOVE; - int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY | W_Z) : (W_CAMERA); - Sys_UpdateWindows (nUpdate); -} - -void MainFrame::OnCameraDown() -{ - m_pCamWnd->Camera()->origin[2] -= SPEED_MOVE; - int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY | W_Z) : (W_CAMERA); - Sys_UpdateWindows (nUpdate); -} - -void MainFrame::OnCameraAngleup() -{ - m_pCamWnd->Camera()->angles[0] += SPEED_TURN; - if (m_pCamWnd->Camera()->angles[0] > 85) - m_pCamWnd->Camera()->angles[0] = 85; - Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); -} - -void MainFrame::OnCameraAngledown() -{ - m_pCamWnd->Camera()->angles[0] -= SPEED_TURN; - if (m_pCamWnd->Camera()->angles[0] < -85) - m_pCamWnd->Camera()->angles[0] = -85; - Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); -} - -void MainFrame::OnCameraStrafeleft(bool keydown) -{ - // FIXME: as soon as gtk supports proper keyup/down support, remove this bit - if (m_pCamWnd) - { - if (!m_pCamWnd->m_bFreeMove) - { - if(keydown) - { - VectorMA (m_pCamWnd->Camera()->origin, -SPEED_MOVE, m_pCamWnd->Camera()->right, m_pCamWnd->Camera()->origin); - int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); - Sys_UpdateWindows (nUpdate); - } - return; - } - } - - if (keydown) - m_pCamWnd->Camera()->movementflags |= MOVE_STRAFELEFT; - else - m_pCamWnd->Camera()->movementflags &= ~MOVE_STRAFELEFT; -} - -void MainFrame::OnCameraStraferight(bool keydown) -{ - // FIXME: as soon as gtk supports proper keyup/down support, remove this bit - if (m_pCamWnd) - { - if (!m_pCamWnd->m_bFreeMove) - { - if(keydown) - { - VectorMA (m_pCamWnd->Camera()->origin, SPEED_MOVE, m_pCamWnd->Camera()->right, m_pCamWnd->Camera()->origin); - int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); - Sys_UpdateWindows (nUpdate); - } - return; - } - } - - if (keydown) - m_pCamWnd->Camera()->movementflags |= MOVE_STRAFERIGHT; - else - m_pCamWnd->Camera()->movementflags &= ~MOVE_STRAFERIGHT; -} - -void MainFrame::OnGridToggle() -{ - g_qeglobals.d_showgrid = !g_qeglobals.d_showgrid; - Sys_UpdateWindows (W_XY|W_Z); -} - -void MainFrame::OnViewCrosshair() -{ - g_bCrossHairs ^= 1; - Sys_UpdateWindows (W_XY); -} - -void MainFrame::OnSelectionTextureRotateclock() -{ - Select_RotateTexture(abs(g_PrefsDlg.m_nRotation)); -} - -void MainFrame::OnSelectionTextureRotatecounter() -{ - Select_RotateTexture(-abs(g_PrefsDlg.m_nRotation)); -} - -void MainFrame::OnSelectionTextureScaleup() -{ - Select_ScaleTexture(0, g_qeglobals.d_savedinfo.m_SIIncrement.scale[1]); -} - -void MainFrame::OnSelectionTextureScaledown() -{ - Select_ScaleTexture(0, -g_qeglobals.d_savedinfo.m_SIIncrement.scale[1]); -} - -void MainFrame::OnSelectionTextureScaleLeft() -{ - Select_ScaleTexture(-g_qeglobals.d_savedinfo.m_SIIncrement.scale[0],0); -} - -void MainFrame::OnSelectionTextureScaleRight() -{ - Select_ScaleTexture(g_qeglobals.d_savedinfo.m_SIIncrement.scale[0],0); -} - -void MainFrame::OnSelectionTextureShiftleft() -{ - Select_ShiftTexture((int)-g_qeglobals.d_savedinfo.m_SIIncrement.shift[0], 0); -} - -void MainFrame::OnSelectionTextureShiftright() -{ - Select_ShiftTexture((int)g_qeglobals.d_savedinfo.m_SIIncrement.shift[0], 0); -} - -void MainFrame::OnSelectionTextureShiftup() -{ - Select_ShiftTexture(0, (int)g_qeglobals.d_savedinfo.m_SIIncrement.shift[1]); -} - -void MainFrame::OnSelectionTextureShiftdown() -{ - Select_ShiftTexture(0, (int)-g_qeglobals.d_savedinfo.m_SIIncrement.shift[1]); -} - -void MainFrame::OnGridPrev() -{ - GtkWidget *item; - if (g_qeglobals.d_gridsize == 1) - { - g_qeglobals.d_gridsize = 0.5; - g_qeglobals.d_bSmallGrid = true; - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_05")); - } else if (g_qeglobals.d_gridsize == 0.5) - { - g_qeglobals.d_gridsize = 0.25; - g_qeglobals.d_bSmallGrid = true; - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_025")); - } else if (g_qeglobals.d_gridsize > 1) - { - g_qeglobals.d_gridsize = (int)g_qeglobals.d_gridsize >> 1; - g_qeglobals.d_bSmallGrid = false; - - switch ((int)g_qeglobals.d_gridsize) - { - case 1: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_1")); break; - case 2: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_2")); break; - case 4: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_4")); break; - case 8: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_8")); break; - case 16: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_16")); break; - case 32: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_32")); break; - case 64: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_64")); break; - case 128: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_128")); break; - case 256: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_256")); break; - } - - } else - return; - - // SnapTToGrid option: need to check everywhere the grid size is changed - // this is a bit clumsy, have to do in OnGrid OnGridPrev and OnGridNext - if (g_PrefsDlg.m_bSnapTToGrid) - DoSnapTToGrid(); - - SetGridStatus(); - g_bIgnoreCommands++; - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - g_bIgnoreCommands--; - - Sys_UpdateWindows(W_XY | W_Z); -} - -void MainFrame::OnGridNext() -{ - GtkWidget *item; - if (g_qeglobals.d_gridsize == 0.25) - { - g_qeglobals.d_gridsize = 0.5; - g_qeglobals.d_bSmallGrid = true; - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_05")); - } else if (g_qeglobals.d_gridsize == 0.5) - { - g_qeglobals.d_gridsize = 1; - g_qeglobals.d_bSmallGrid = false; - item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_1")); - } else if (g_qeglobals.d_gridsize < 256) - { - g_qeglobals.d_gridsize = (int)g_qeglobals.d_gridsize << 1; - g_qeglobals.d_bSmallGrid = false; - - switch ((int)g_qeglobals.d_gridsize) - { - case 1: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_1")); break; - case 2: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_2")); break; - case 4: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_4")); break; - case 8: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_8")); break; - case 16: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_16")); break; - case 32: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_32")); break; - case 64: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_64")); break; - case 128: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_128")); break; - case 256: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_256")); break; - } - - } else - return; - - // SnapTToGrid option: need to check everywhere the grid size is changed - // this is a bit clumsy, have to do in OnGrid OnGridPrev and OnGridNext - if (g_PrefsDlg.m_bSnapTToGrid) - DoSnapTToGrid(); - - SetGridStatus(); - g_bIgnoreCommands++; - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - g_bIgnoreCommands--; - - Sys_UpdateWindows(W_XY | W_Z); -} - -void MainFrame::OnSelectionMovedown() -{ - if (&selected_brushes == selected_brushes.next) - return; - Undo_Start("move down"); - Undo_AddBrushList(&selected_brushes); - - vec3_t vAmt; - vAmt[0] = vAmt[1] = 0.0; - vAmt[2] = -g_qeglobals.d_gridsize; - Select_Move (vAmt); - Sys_UpdateWindows(W_CAMERA | W_XY | W_Z); - - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnSelectionMoveup() -{ - if (&selected_brushes == selected_brushes.next) - return; - Undo_Start("move up"); - Undo_AddBrushList(&selected_brushes); - - vec3_t vAmt; - vAmt[0] = vAmt[1] = 0.0; - vAmt[2] = g_qeglobals.d_gridsize; - Select_Move (vAmt); - Sys_UpdateWindows(W_CAMERA | W_XY | W_Z); - - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnSelectionPrint() -{ - for (brush_t* b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - Brush_Print(b); -} - -void MainFrame::OnSelectionTogglesizepaint() -{ - g_PrefsDlg.m_bSizePaint = !g_PrefsDlg.m_bSizePaint; - Sys_UpdateWindows(W_XY); -} - -void MainFrame::OnPatchNaturalize() -{ - Patch_NaturalizeSelected(); - Sys_UpdateWindows (W_ALL); -} - -void MainFrame::OnSnapToGrid() -{ - if (&selected_brushes == selected_brushes.next) - return; - Undo_Start("snap selection to grid"); - Undo_AddBrushList(&selected_brushes); - //Select_SnapToGrid(); - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - Patch_SnapToGrid(pb->pPatch); - else - Brush_SnapToGrid(pb); - } - Sys_UpdateWindows (W_ALL); - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -void MainFrame::OnSelectAll() -{ - Select_AllOfType(); -} - -void MainFrame::OnSelectionInvert() -{ - Select_Invert(); - Sys_UpdateWindows(W_XY | W_Z | W_CAMERA); -} - - -void PerformFiltering () -{ - brush_t *brush; - - // spog - deletes old filters list and creates new one when - // g_qeglobals.d_savedinfo.exclude is updated - g_qeglobals.d_savedinfo.filters = FilterListDelete(g_qeglobals.d_savedinfo.filters); - g_qeglobals.d_savedinfo.filters = FilterUpdate(g_qeglobals.d_savedinfo.filters); - - for ( brush = active_brushes.next; brush != &active_brushes; brush = brush->next ) - brush->bFiltered = FilterBrush( brush ); - - for ( brush = selected_brushes.next; brush != &selected_brushes; brush = brush->next ) - brush->bFiltered = FilterBrush( brush ); -} - -void MainFrame::OnFilterAreaportals() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_areaportals")); - g_bIgnoreCommands++; - if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_AREAPORTALS) & EXCLUDE_AREAPORTALS) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - else - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); - g_bIgnoreCommands--; - PerformFiltering(); - Sys_UpdateWindows (W_XY|W_CAMERA); -} - -void MainFrame::OnFilterCaulk() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_caulk")); - g_bIgnoreCommands++; - if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_CAULK) & EXCLUDE_CAULK) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - else - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); - g_bIgnoreCommands--; - PerformFiltering(); - Sys_UpdateWindows (W_XY|W_CAMERA); -} - -void MainFrame::OnFilterClips() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_clips")); - g_bIgnoreCommands++; - if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_CLIP) & EXCLUDE_CLIP) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - else - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); - g_bIgnoreCommands--; - PerformFiltering(); - Sys_UpdateWindows (W_XY|W_CAMERA); -} - -void MainFrame::OnFilterBotClips() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_botclips")); - g_bIgnoreCommands++; - if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_BOTCLIP) & EXCLUDE_BOTCLIP) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - else - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); - g_bIgnoreCommands--; - PerformFiltering(); - Sys_UpdateWindows (W_XY|W_CAMERA); -} - -void MainFrame::OnFilterStructural() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_structural")); - g_bIgnoreCommands++; - if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_STRUCTURAL) & EXCLUDE_STRUCTURAL) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - else - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); - g_bIgnoreCommands--; - PerformFiltering(); - Sys_UpdateWindows (W_XY|W_CAMERA); -} - -void MainFrame::OnFilterDetails() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_details")); - g_bIgnoreCommands++; - if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_DETAILS) & EXCLUDE_DETAILS) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - else - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); - g_bIgnoreCommands--; - PerformFiltering(); - Sys_UpdateWindows (W_XY|W_CAMERA); -} - -void MainFrame::OnFilterEntities() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_entities")); - g_bIgnoreCommands++; - if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_ENT) & EXCLUDE_ENT) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - else - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); - g_bIgnoreCommands--; - PerformFiltering(); - Sys_UpdateWindows (W_XY|W_CAMERA); -} - -void MainFrame::OnFilterHintsskips() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_hintsskips")); - g_bIgnoreCommands++; - if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_HINTSSKIPS) & EXCLUDE_HINTSSKIPS) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - else - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); - g_bIgnoreCommands--; - PerformFiltering(); - Sys_UpdateWindows (W_XY|W_CAMERA); -} - -void MainFrame::OnFilterLights() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_lights")); - g_bIgnoreCommands++; - if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_LIGHTS) & EXCLUDE_LIGHTS) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - else - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); - g_bIgnoreCommands--; - PerformFiltering(); - Sys_UpdateWindows (W_XY|W_CAMERA); -} - -void MainFrame::OnFilterLiquids() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_liquids")); - g_bIgnoreCommands++; - if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_LIQUIDS) & EXCLUDE_LIQUIDS) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - else - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); - g_bIgnoreCommands--; - PerformFiltering(); - Sys_UpdateWindows (W_XY|W_CAMERA); -} - -void MainFrame::OnFilterModels() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_models")); - g_bIgnoreCommands++; - if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_MODELS) & EXCLUDE_MODELS) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - else - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); - g_bIgnoreCommands--; - PerformFiltering(); - Sys_UpdateWindows (W_XY|W_CAMERA); -} - -void MainFrame::OnFilterPatches() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_patches")); - g_bIgnoreCommands++; - if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_CURVES) & EXCLUDE_CURVES) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - else - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); - g_bIgnoreCommands--; - PerformFiltering(); - Sys_UpdateWindows (W_XY|W_CAMERA); -} - -void MainFrame::OnFilterPaths() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_paths")); - g_bIgnoreCommands++; - if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_PATHS) & EXCLUDE_PATHS) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - else - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); - g_bIgnoreCommands--; - PerformFiltering(); - Sys_UpdateWindows (W_XY|W_CAMERA); -} - -void MainFrame::OnFilterClusterportals() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_clusterportals")); - g_bIgnoreCommands++; - if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_CLUSTERPORTALS) & EXCLUDE_CLUSTERPORTALS) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - else - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); - g_bIgnoreCommands--; - PerformFiltering(); - Sys_UpdateWindows (W_XY|W_CAMERA); -} - -void MainFrame::OnFilterLightgrid() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_lightgrid")); - g_bIgnoreCommands++; - if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_LIGHTGRID) & EXCLUDE_LIGHTGRID) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - else - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); - g_bIgnoreCommands--; - PerformFiltering(); - Sys_UpdateWindows (W_XY|W_CAMERA); -} - -void MainFrame::OnFilterTranslucent() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_translucent")); - g_bIgnoreCommands++; - if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_TRANSLUCENT) & EXCLUDE_TRANSLUCENT) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - else - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); - g_bIgnoreCommands--; - PerformFiltering(); - Sys_UpdateWindows (W_XY|W_CAMERA); -} - -void MainFrame::OnFilterTriggers() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_triggers")); - g_bIgnoreCommands++; - if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_TRIGGERS) & EXCLUDE_TRIGGERS) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - else - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); - g_bIgnoreCommands--; - PerformFiltering(); - Sys_UpdateWindows (W_XY|W_CAMERA); -} - -void MainFrame::OnFilterWorld() -{ - GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_world")); - g_bIgnoreCommands++; - if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_WORLD) & EXCLUDE_WORLD) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - else - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); - g_bIgnoreCommands--; - PerformFiltering(); - Sys_UpdateWindows (W_XY|W_CAMERA); -} - - - - - - - - -// ============================================================================= -// leo: Unused functions, not called anywhere from the code (need to check) - -void MainFrame::OnViewConsole() -{ - if (FloatingGroupDialog()) // QE4 style - { - if (inspector_mode == W_CONSOLE && CurrentStyle() != MainFrame::eFloating) // are we in console mode already? - { - if (GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity)) - widget_delete_hide (g_qeglobals_gui.d_entity); - else - gtk_widget_show (g_qeglobals_gui.d_entity); - } else - { - gtk_widget_show (g_qeglobals_gui.d_entity); - SetInspectorMode(W_CONSOLE); - } - } -} - -void MainFrame::OnCurveFreeze() -{ - Patch_Freeze(); -} - -void MainFrame::OnCurveUnFreeze() -{ - Patch_UnFreeze(false); -} - -void MainFrame::OnCurveUnFreezeAll() -{ - Patch_UnFreeze(true); -} - -void MainFrame::OnSelectReselect() -{ - Select_Reselect(); -} - -void MainFrame::OnSelectionTextureFit() -{ - // TODO: Add your command handler code here -} - -void MainFrame::OnPatchEnter() -{ - -} - -void MainFrame::OnDropGroupAddtoWorld() -{ - /* - Select_AddToGroup("World"); - Sys_UpdateWindows (W_ALL); - */ -} +/* +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 +*/ + +// +// Main Window for Q3Radiant +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" +#ifdef _WIN32 +extern "C" { +#include +#define COMPILE_MULTIMON_STUBS +#include +} +#endif +#include +#include +#include +#include +#if defined (__linux__) || defined (__APPLE__) + #include +#endif +#include "gtkmisc.h" +#include "groupdialog.h" +#include "patchdialog.h" +#include "filters.h" + +// use this to verbose what happens with the beyboard +#ifdef _DEBUG +// #define DBG_KBD +#endif + +// globals +CString g_strAppPath; ///< holds the full path of the executable +CString g_strDTDPath; ///< path to the DTD files +/*! +see http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=297 for the two below +*/ +CString g_pidFile; ///< the global .pid file (only for global part of the startup) +CString g_pidGameFile; ///< the game-specific .pid file +CString g_strBitmapsPath; // directory where the bitmaps are stored + +/*! +points to the game tools directory, for instance +C:\Program Files\Quake III Arena\GtkRadiant +(or other games) +this is one of the main variables that are configured by the game selection on startup +/plugins +/modules +and also q3map, bspc +*/ +CString g_strGameToolsPath; ///< this is set by g_PrefsDlg.mGamesDialog +CGameDescription *g_pGameDescription; ///< shortcut to g_PrefsDlg.mGamesDialog.m_pCurrentDescription +CString g_strPluginsDir; ///< name of plugins directory, always sub-directory of toolspath +CString g_strModulesDir; ///< name of modules directory, always sub-directory of toolspath + +/*! +directory for temp files +NOTE: on *nix this is were we check for .pid +*/ +CString g_strTempPath; +MainFrame* g_pParentWnd = NULL; // used to precast to CMainFrame +PrefsDlg g_Preferences; // global prefs instance +PrefsDlg& g_PrefsDlg = g_Preferences; // reference used throughout +int g_nUpdateBits = 0; // window update flags +bool g_bScreenUpdates = true; // whether window painting is active, used in a few places + // to disable updates for speed reasons + // both of the above should be made members of CMainFrame +int g_bIgnoreCommands; // Used to ignore commands when checking menus/toolbars +GSList *g_BSPFrontendCommands; // List of commands in the BSP menu + +const int CMD_TEXTUREWAD_END = CMD_TEXTUREWAD + MAX_TEXTUREDIRS - 1; +const int CMD_BSPCOMMAND_END = CMD_BSPCOMMAND + 127; + +extern bool g_bCrossHairs; +extern int g_argc; +extern char** g_argv; +extern PatchDialog g_PatchDialog; + +GtkAccelGroup* global_accel; + +void Select_Ungroup (); + +// command mapping stuff +// +// m_strCommand is the command string +// m_nKey is the GDK_??? equivelant +// m_nModifiers are key states as follows +// bit +// 1 - shift +// 2 - alt +// 4 - control +// 8 - press only +// +#define SPEED_MOVE 32 +#define SPEED_TURN 22.5 + +// NOTE: the menu item field is REQUIRED, Gtk uses it to bind the keyboard shortcut +// - if you add a command here and you don't want a menu item, use the "hidden" menu +// - if you decide to add a menu item, check if it's not in the "hidden" menu already +SCommandInfo g_Commands[] = +{ + {"CycleOutlineStyle", 'J', 0x00, ID_SELECTION_OUTLINESTYLE, "menu_selection_outlinestyle"}, + {"CSGMerge", 'U', 0x04, ID_SELECTION_CSGMERGE, "menu_selection_csgmerge"}, + {"CSGSubtract", 'U', 0x01, ID_SELECTION_CSGSUBTRACT, "menu_selection_csgsubstract"}, + // {"ViewGroups", 'G', 0x00, ID_VIEW_GROUPS, "menu_view_groups"}, (temporary disabled) + {"HideSelected", 'H', 0x00, ID_VIEW_HIDESHOW_HIDESELECTED, "menu_view_hideshow_hideselected"}, + {"ShowHidden", 'H', 0x01, ID_VIEW_HIDESHOW_SHOWHIDDEN, "menu_view_hideshow_showhidden"}, + {"BendMode", 'B', 0x00, ID_PATCH_BEND, "menu_patch_bend"}, + {"FitTexture", 'B', 0x01, IDC_BTN_FACEFIT, "menu_idc_btn_facefit"}, + {"ViewTextures", 'T', 0, ID_VIEW_TEXTURE, "menu_view_texture"}, + {"ThickenPatch", 'T', 0x04, ID_CURVE_THICKEN, "menu_curve_thicken"}, + {"MakeOverlayPatch", 'Y', 0, ID_CURVE_OVERLAY_SET, "menu_curve_overlay_set"}, + {"ClearPatchOverlays", 'L', 0x04, ID_CURVE_OVERLAY_CLEAR, "menu_curve_overlay_clear"}, + {"SurfaceInspector", 'S', 0, ID_TEXTURES_INSPECTOR, "menu_textures_inspector"}, + {"PatchInspector", 'S', 0x01, ID_PATCH_INSPECTOR, "menu_patch_inspector"}, + {"RedisperseRows", 'E', 0x04, ID_CURVE_REDISPERSE_ROWS, "menu_curve_redisperse_rows"}, + {"RedisperseIntermediateCols", 'E', 0x05, ID_CURVE_REDISPERSE_INTERMEDIATE_COLS, "menu_curve_redisperse_cols"}, + {"InvertCurveTextureX", 'I', 0x05, ID_CURVE_NEGATIVETEXTUREY, "menu_curve_negativetexturey"}, + {"InvertCurveTextureY", 'I', 0x01, ID_CURVE_NEGATIVETEXTUREX, "menu_curve_negativetexturex"}, + {"InvertCurve", 'I', 0x04, ID_CURVE_NEGATIVE, "menu_curve_negative"}, + {"IncPatchColumn", GDK_KP_Add, 0x05, ID_CURVE_INSERTCOLUMN, "menu_curve_insertcolumn"}, + {"IncPatchRow", GDK_KP_Add, 0x04, ID_CURVE_INSERTROW, "menu_curve_insertrow"}, + {"DecPatchColumn", GDK_KP_Subtract, 0x05, ID_CURVE_DELETECOLUMN, "menu_curve_deletecolumn"}, + {"DecPatchRow", GDK_KP_Subtract, 0x04, ID_CURVE_DELETEROW, "menu_curve_deleterow"}, + {"Patch TAB", GDK_Tab, 0x00, ID_PATCH_TAB, "menu_patch_tab"}, + {"Patch TAB", GDK_Tab, 0x01, ID_PATCH_TAB, "menu_patch_tab"}, + {"SelectNudgeDown", GDK_Down, 0x02, ID_SELECTION_SELECT_NUDGEDOWN, "menu_selection_select_nudgedown"}, + {"EntityColor",'K', 0, ID_MISC_SELECTENTITYCOLOR, "menu_misc_select_entitycolor"}, + {"CameraForward", GDK_Up, 0, ID_CAMERA_FORWARD, "menu_camera_forward"}, + {"CameraBack", GDK_Down, 0, ID_CAMERA_BACK, "menu_camera_back"}, + {"CameraLeft", GDK_Left, 0, ID_CAMERA_LEFT, "menu_camera_left"}, + {"CameraRight", GDK_Right, 0, ID_CAMERA_RIGHT, "menu_camera_right"}, + {"CameraUp", 'D', 0, ID_CAMERA_UP, "menu_camera_up"}, + {"CameraDown", 'C', 0, ID_CAMERA_DOWN, "menu_camera_down"}, + {"CameraAngleUp", 'A', 0, ID_CAMERA_ANGLEUP, "menu_camera_angleup"}, + {"CameraAngleDown", 'Z', 0, ID_CAMERA_ANGLEDOWN, "menu_camera_angledown"}, + {"CameraStrafeRight", GDK_period, 0, ID_CAMERA_STRAFERIGHT, "menu_camera_straferight"}, + {"CameraStrafeLeft", GDK_comma, 0, ID_CAMERA_STRAFELEFT, "menu_camera_strafeleft"}, + {"ToggleGrid", '0', 0, ID_GRID_TOGGLE, "menu_grid_toggle"}, + {"SetGrid1", '1', 0, ID_GRID_1, "menu_grid_1"}, + {"SetGrid2", '2', 0, ID_GRID_2, "menu_grid_2"}, + {"SetGrid4", '3', 0, ID_GRID_4, "menu_grid_4"}, + {"SetGrid8", '4', 0, ID_GRID_8, "menu_grid_8"}, + {"SetGrid16", '5', 0, ID_GRID_16, "menu_grid_16"}, + {"SetGrid32", '6', 0, ID_GRID_32, "menu_grid_32"}, + {"SetGrid64", '7', 0, ID_GRID_64, "menu_grid_64"}, + {"SetGrid128", '8', 0, ID_GRID_128, "menu_grid_128"}, + {"SetGrid256", '9', 0, ID_GRID_256, "menu_grid_256"}, + {"DragEdges", 'E', 0, ID_SELECTION_DRAGEDGES, "menu_selection_dragedges"}, + {"DragVertices", 'V', 0, ID_SELECTION_DRAGVERTECIES, "menu_selection_dragvertecies"}, + {"ViewEntityInfo", 'N', 0, ID_VIEW_ENTITY, "menu_view_entity"}, + // {"ViewConsole", 'O', 0, ID_VIEW_CONSOLE, "menu_0,"}, + {"CloneSelection", GDK_space, 0, ID_SELECTION_CLONE, "menu_selection_clone"}, + {"DeleteSelection", GDK_BackSpace, 0, ID_SELECTION_DELETE, "menu_selection_delete"}, + {"UnSelectSelection", GDK_Escape, 0, ID_SELECTION_DESELECT, "menu_selection_deselect"}, + {"CenterView", GDK_End, 0, ID_VIEW_CENTER, "menu_view_center"}, + {"ZoomOut", GDK_Insert, 0, ID_VIEW_ZOOMOUT, "menu_view_zoomout"}, + {"ZoomIn", GDK_Delete, 0, ID_VIEW_ZOOMIN, "menu_view_zoomin"}, + {"UpFloor", GDK_Prior, 0, ID_VIEW_UPFLOOR, "menu_view_upfloor"}, + {"DownFloor", GDK_Next, 0, ID_VIEW_DOWNFLOOR, "menu_view_downfloor"}, + {"ToggleClipper", 'X', 0, ID_VIEW_CLIPPER, "menu_view_clipper"}, + {"ToggleCrosshairs", 'X', 0x01, ID_VIEW_CROSSHAIR, "menu_view_crosshair"}, + {"TogTexLock", 'T', 0x01, ID_TOGGLE_LOCK, "menu_toggle_lock"}, + {"TogTexRotLock", 'R', 0x01, ID_TOGGLE_ROTATELOCK, "menu_toggle_rotatelock"}, + {"ToggleRealtime", 'R', 0x04, ID_VIEW_CAMERAUPDATE, "menu_view_cameraupdate"}, + {"EntityList", 'L', 0, ID_EDIT_ENTITYINFO, "menu_edit_entityinfo"}, + {"Preferences", 'P', 0, ID_PREFS, "menu_prefs"}, + {"ToggleCamera", 'C', 0x05, ID_TOGGLECAMERA, "menu_togglecamera"}, + {"ToggleConsole", 'O', 0, ID_TOGGLECONSOLE, "menu_toggleconsole"}, + {"ToggleView", 'V', 0x05, ID_TOGGLEVIEW, "menu_toggleview"}, + {"ToggleZ", 'Z', 0x05, ID_TOGGLEZ, "menu_togglez"}, + {"ConnectSelection", 'K', 0x04, ID_SELECTION_CONNECT, "menu_selection_connect"}, + {"Brush3Sided", '3', 0x04, ID_BRUSH_3SIDED, "menu_brush_3sided"}, + {"Brush4Sided", '4', 0x04, ID_BRUSH_4SIDED, "menu_brush_4sided"}, + {"Brush5Sided", '5', 0x04, ID_BRUSH_5SIDED, "menu_brush_5sided"}, + {"Brush6Sided", '6', 0x04, ID_BRUSH_6SIDED, "menu_brush_6sided"}, + {"Brush7Sided", '7', 0x04, ID_BRUSH_7SIDED, "menu_brush_7sided"}, + {"Brush8Sided", '8', 0x04, ID_BRUSH_8SIDED, "menu_brush_8sided"}, + {"Brush9Sided", '9', 0x04, ID_BRUSH_9SIDED, "menu_brush_9sided"}, + {"MatrixTranspose", 'M', 0x05, ID_CURVE_MATRIX_TRANSPOSE, "menu_curve_matrix_transpose"}, + {"MakeDetail", 'M', 0x04, ID_SELECTION_MAKE_DETAIL, "menu_selection_make_detail"}, + {"MapInfo", 'M', 0, ID_EDIT_MAPINFO, "menu_edit_mapinfo"}, + {"NextLeakSpot", 'K', 0x05, ID_MISC_NEXTLEAKSPOT, "menu_misc_nextleakspot"}, + {"PrevLeakSpot", 'L', 0x05, ID_MISC_PREVIOUSLEAKSPOT, "menu_misc_previousleakspot"}, + {"FileOpen", 'O', 0x04, ID_FILE_OPEN, "menu_file_open"}, + {"FileSave", 'S', 0x04, ID_FILE_SAVE, "menu_file_save"}, + //% {"Exit", 'X', 0x04, ID_FILE_EXIT, "menu_file_exit"}, // ydnar: Ctrl+X should be cut + {"CenterXYView", GDK_Tab, 0x05, ID_VIEW_CENTERVIEW, "menu_view_centerview"}, + {"NextView", GDK_Tab, 0x04, ID_VIEW_NEXTVIEW, "menu_view_nextview"}, + {"ClipSelected", GDK_Return, 0x00, ID_CLIP_SELECTED, "menu_clip_selected"}, + {"SplitSelected", GDK_Return, 0x01, ID_SPLIT_SELECTED, "menu_split_selected"}, + {"FlipClip", GDK_Return, 0x04, ID_FLIP_CLIP, "menu_flip_clip"}, + {"MouseRotate", 'R', 0x00, ID_SELECT_MOUSEROTATE, "menu_select_mouserotate"}, + {"Copy", 'C', 0x04, ID_EDIT_COPYBRUSH, "menu_edit_copybrush"}, + {"Paste", 'V', 0x04, ID_EDIT_PASTEBRUSH, "menu_edit_pastebrush"}, + {"PasteToCamera", 'V', RAD_ALT, ID_EDIT_PASTEBRUSHTOCAMERA, "menu_edit_pastebrushtocamera"}, + {"Undo", 'Z', 0x04, ID_EDIT_UNDO, "menu_edit_undo"}, + {"Redo", 'Y', 0x04, ID_EDIT_REDO, "menu_edit_redo"}, + {"ZZoomOut", GDK_Insert, 0x04, ID_VIEW_ZZOOMOUT, "menu_view_zzoomout"}, + {"ZZoomIn", GDK_Delete, 0x04, ID_VIEW_ZZOOMIN, "menu_view_zzoomin"}, + {"TexRotateClock", GDK_Next, 0x01, ID_SELECTION_TEXTURE_ROTATECLOCK, "menu_selection_texture_rotateclock"}, + {"TexRotateCounter", GDK_Prior, 0x01, ID_SELECTION_TEXTURE_ROTATECOUNTER, "menu_selection_texture_rotatecounter"}, + {"TexScaleUp", GDK_Up, 0x04, ID_SELECTION_TEXTURE_SCALEUP, "menu_selection_texture_scaleup"}, + {"TexScaleDown", GDK_Down, 0x04, ID_SELECTION_TEXTURE_SCALEDOWN, "menu_selection_texture_scaledown"}, + {"TexShiftLeft", GDK_Left, 0x01, ID_SELECTION_TEXTURE_SHIFTLEFT, "menu_selection_texture_shiftleft"}, + {"TexShiftRight", GDK_Right, 0x01, ID_SELECTION_TEXTURE_SHIFTRIGHT, "menu_selection_texture_shiftright"}, + {"TexShiftUp", GDK_Up, 0x01, ID_SELECTION_TEXTURE_SHIFTUP, "menu_selection_texture_shiftup"}, + {"TexShiftDown", GDK_Down, 0x01, ID_SELECTION_TEXTURE_SHIFTDOWN, "menu_selection_texture_shiftdown"}, + {"GridDown", '[', 0x00, ID_GRID_PREV, "menu_grid_prev"}, + {"GridUp", ']', 0x00, ID_GRID_NEXT, "menu_grid_next"}, + {"TexScaleLeft", GDK_Left, 0x04, ID_SELECTION_TEXTURE_SCALELEFT, "menu_selection_texture_scaleleft"}, + {"TexScaleRight", GDK_Right, 0x04, ID_SELECTION_TEXTURE_SCALERIGHT, "menu_selection_texture_scaleright"}, + {"CubicClipZoomOut", ']', 0x04, ID_VIEW_CUBEOUT, "menu_view_cubeout"}, + {"CubicClipZoomIn", '[', 0x04, ID_VIEW_CUBEIN, "menu_view_cubein"}, + {"ToggleCubicClip", '\\', 0x04, ID_VIEW_CUBICCLIPPING, "menu_view_cubicclipping"}, + {"MoveSelectionDOWN", GDK_KP_Subtract, 0x00, ID_SELECTION_MOVEDOWN, "menu_selection_movedown"}, + {"MoveSelectionUP", GDK_KP_Add, 0x00, ID_SELECTION_MOVEUP, "menu_selection_moveup"}, + {"DumpSelectedBrush", 'D', 0x01, ID_SELECTION_PRINT, "menu_selection_print"}, + {"ToggleSizePaint", 'Q', 0x00, ID_SELECTION_TOGGLESIZEPAINT, "menu_selection_togglesizepaint"}, + {"SelectNudgeLeft", GDK_Left, 0x02, ID_SELECTION_SELECT_NUDGELEFT, "menu_selection_select_nudgeleft"}, + {"SelectNudgeRight", GDK_Right, 0x02, ID_SELECTION_SELECT_NUDGERIGHT, "menu_selection_select_nudgeright"}, + {"SelectNudgeUp", GDK_Up, 0x02, ID_SELECTION_SELECT_NUDGEUP, "menu_selection_select_nudgeup"}, + {"CycleCapTexturePatch", 'N', 0x05, ID_CURVE_CYCLECAP, "menu_curve_cyclecap"}, + {"NaturalizePatch", 'N', 0x04, ID_PATCH_NATURALIZE, "menu_patch_naturalize"}, + {"SnapToGrid", 'G', 0x04, ID_SELECT_SNAPTOGRID, "menu_select_snaptogrid"}, + {"ShowAllTextures", 'A', 0x04, ID_TEXTURES_SHOWALL, "menu_textures_showall"}, + {"SelectAllOfType", 'A', 0x01, ID_SELECT_ALL, "menu_select_all"}, + {"CapCurrentCurve", 'C', 0x01, ID_CURVE_CAP, "menu_curve_cap"}, + {"MakeStructural", 'S', 0x05, ID_SELECTION_MAKE_STRUCTURAL, "menu_selection_make_structural"}, + {"RegionSetSelection", 'R', 0x05, ID_REGION_SETSELECTION, "menu_region_setselection"}, + {"ShowInUse", 'U', 0, ID_TEXTURES_SHOWINUSE, "menu_textures_showinuse"}, + {"InvertSelection", 'I', 0, ID_SELECTION_INVERT, "menu_selection_invert"}, + {"Sleep", 'P', 0x05, ID_FILE_SLEEP, "menu_file_sleep"}, + {"SimplePatchMesh", 'P', 0x01, ID_CURVE_SIMPLEPATCHMESH, "menu_simplepatchmesh"}, + {"FilterWorldBrushes", '1', RAD_ALT, ID_FILTER_WORLD, "menu_filter_world"}, + {"FilterEntities", '2', RAD_ALT, ID_FILTER_ENTITIES, "menu_filter_entities"}, + {"FilterAreaportals", '3', RAD_ALT, ID_FILTER_AREAPORTALS, "menu_filter_areaportals"}, + {"FilterTranslucent", '4', RAD_ALT, ID_FILTER_TRANSLUCENT, "menu_filter_translucent"}, + {"FilterLiquids", '5', RAD_ALT, ID_FILTER_LIQUIDS, "menu_filter_liquids"}, + {"FilterCaulk", '6', RAD_ALT , ID_FILTER_CAULK, "menu_filter_caulk"}, + {"FilterClips", '7', RAD_ALT, ID_FILTER_CLIPS, "menu_filter_clips"}, + {"FilterBotClips", 'M', RAD_ALT, ID_FILTER_BOTCLIPS, "menu_filter_botclips"}, + {"FilterPaths", '8', RAD_ALT, ID_FILTER_PATHS, "menu_filter_paths"}, + {"FilterClusterportals", '9', RAD_ALT, ID_FILTER_CLUSTERPORTALS, "menu_filter_clusterportals"}, + {"FilterLights", '0', RAD_ALT, ID_FILTER_LIGHTS, "menu_filter_lights"}, + {"FilterPatches", 'P', RAD_CONTROL, ID_FILTER_PATCHES, "menu_filter_patches"}, + {"FilterDetails", 'D', RAD_CONTROL, ID_FILTER_DETAILS, "menu_filter_details"}, + {"FilterStructural", 'D', RAD_CONTROL|RAD_SHIFT, ID_FILTER_STRUCTURAL, "menu_filter_structural"}, + {"FilterHintsSkips", 'H', RAD_CONTROL, ID_FILTER_HINTSSKIPS, "menu_filter_hintsskips"}, + {"FilterModels", 'M', RAD_SHIFT, ID_FILTER_MODELS, "menu_filter_models"}, + {"FilterTriggers", 'T', RAD_CONTROL|RAD_SHIFT, ID_FILTER_TRIGGERS, "menu_filter_triggers"}, + {"LoadPointfile", 'L', RAD_SHIFT, ID_FILE_POINTFILE, "menu_load_pointfile"}, + {"TextureWindowScaledown", GDK_Insert, RAD_ALT, ID_TEXTUREWINDOW_SCALEDOWN, "menu_texturewindow_scaledown"}, + {"TextureWindowScaleup", GDK_Delete, RAD_ALT, ID_TEXTUREWINDOW_SCALEUP, "menu_texturewindow_scaleup"}, +}; + +int g_nCommandCount = sizeof(g_Commands) / sizeof(SCommandInfo); + +SKeyInfo g_Keys[] = +{ + {"Space", GDK_space}, + {"Backspace", GDK_BackSpace}, + {"Escape", GDK_Escape}, + {"End", GDK_End}, + {"Insert", GDK_Insert}, + {"Delete", GDK_Delete}, + {"PageUp", GDK_Prior}, + {"PageDown", GDK_Next}, + {"Up", GDK_Up}, + {"Down", GDK_Down}, + {"Left", GDK_Left}, + {"Right", GDK_Right}, + {"F1", GDK_F1}, + {"F2", GDK_F2}, + {"F3", GDK_F3}, + {"F4", GDK_F4}, + {"F5", GDK_F5}, + {"F6", GDK_F6}, + {"F7", GDK_F7}, + {"F8", GDK_F8}, + {"F9", GDK_F9}, + {"F10", GDK_F10}, + {"F11", GDK_F11}, + {"F12", GDK_F12}, + {"Tab", GDK_Tab}, + {"Return", GDK_Return}, + {"Comma", GDK_comma}, + {"Period", GDK_period}, + {"Plus", GDK_KP_Add}, + {"Multiply", GDK_multiply}, + {"Subtract", GDK_KP_Subtract}, + {"NumPad0", GDK_KP_0}, + {"NumPad1", GDK_KP_1}, + {"NumPad2", GDK_KP_2}, + {"NumPad3", GDK_KP_3}, + {"NumPad4", GDK_KP_4}, + {"NumPad5", GDK_KP_5}, + {"NumPad6", GDK_KP_6}, + {"NumPad7", GDK_KP_7}, + {"NumPad8", GDK_KP_8}, + {"NumPad9", GDK_KP_9}, + {"[", 219}, + {"]", 221}, + {"\\", 220}, + {"Home", GDK_Home} +}; + +int g_nKeyCount = sizeof(g_Keys) / sizeof(SKeyInfo); + +// ============================================================================= +// global functions + +void WINAPI Sys_UpdateWindows (int nBits) +{ + g_nUpdateBits |= nBits; +} + +// ============================================================================= +// Static functions + +// Gef: Separate handling for keyup events +void HandleKeyUp (GtkWidget *widget, gpointer data) +{ + int id = GPOINTER_TO_INT (data); +#ifdef DBG_KBD + Sys_Printf("HandleKeyUp: %d\n", id); +#endif + + if(g_bIgnoreCommands) + return; + + switch (id) + { + case ID_CAMERA_FORWARD: g_pParentWnd->OnCameraForward (FALSE); break; + case ID_CAMERA_BACK: g_pParentWnd->OnCameraBack (FALSE); break; + case ID_CAMERA_LEFT: g_pParentWnd->OnCameraLeft (FALSE); break; + case ID_CAMERA_RIGHT: g_pParentWnd->OnCameraRight (FALSE); break; + case ID_CAMERA_STRAFELEFT: g_pParentWnd->OnCameraStrafeleft (FALSE); break; + case ID_CAMERA_STRAFERIGHT: g_pParentWnd->OnCameraStraferight (FALSE); break; + } +} + +gint HandleCommand (GtkWidget *widget, gpointer data) +{ + int id = GPOINTER_TO_INT (data); +#ifdef DBG_KBD + Sys_Printf("HandleCommand %d\n", id); +#endif + + if ( g_bIgnoreCommands ) { +#ifdef DBG_KBD + Sys_Printf( "g_bIgnoreCommands %d, returning FALSE\n", g_bIgnoreCommands ); +#endif + return FALSE; + } + + if (id >= CMD_TEXTUREWAD && id <= CMD_TEXTUREWAD_END) g_pParentWnd->OnTextureWad (id); + else if (id >= CMD_BSPCOMMAND && id <= CMD_BSPCOMMAND_END) g_pParentWnd->OnBspCommand (id); + else if (id >= ID_FILE_RECENT1 && id <= ID_FILE_RECENT4) g_pParentWnd->OnMru (id); + else if (id >= ID_VIEW_NEAREST && id <= ID_TEXTURES_FLATSHADE) + { + if (GTK_CHECK_MENU_ITEM (widget)->active) + g_pParentWnd->OnViewNearest (id); + } else if (id >= ID_GRID_025 && id <= ID_GRID_256) g_pParentWnd->OnGrid (id); + else if (id >= ID_PLUGIN_START && id <= ID_PLUGIN_END) + { + char *str; + gtk_label_get (GTK_LABEL (GTK_BIN (widget)->child), &str); + g_pParentWnd->OnPlugIn (id, str); + } else if (id >= ID_ENTITY_START && id <= ID_ENTITY_END) + { + char *str; + gtk_label_get (GTK_LABEL (GTK_BIN (widget)->child), &str); + g_pParentWnd->ActiveXY()->OnEntityCreate (str); + } + else switch (id) + { + case ID_FILE_NEW: g_pParentWnd->OnFileNew (); break; + case ID_FILE_SLEEP: g_pParentWnd->OnSleep(); break; + case ID_FILE_OPEN: g_pParentWnd->OnFileOpen (); break; + case ID_FILE_SAVE: g_pParentWnd->OnFileSave (); break; + case ID_FILE_SAVEAS: g_pParentWnd->OnFileSaveas (); break; + case ID_FILE_EXPORTMAP: g_pParentWnd->OnFileExportmap (); break; + case ID_FILE_SAVEREGION: g_pParentWnd->OnFileSaveregion (); break; + case ID_FILE_NEWPROJECT: g_pParentWnd->OnFileNewproject (); break; + case ID_FILE_LOADPROJECT: g_pParentWnd->OnFileLoadproject (); break; + case ID_FILE_PROJECTSETTINGS: g_pParentWnd->OnFileProjectsettings (); break; + case ID_FILE_POINTFILE: g_pParentWnd->OnFilePointfile (); break; + case ID_FILE_CHECKUPDATE: g_pParentWnd->OnFileCheckUpdate (); break; + case ID_FILE_EXIT: g_pParentWnd->OnFileExit (); break; + case ID_FILE_IMPORTMAP: g_pParentWnd->OnFileImportmap (); break; + case ID_EDIT_UNDO: g_pParentWnd->OnEditUndo (); break; + case ID_EDIT_REDO: g_pParentWnd->OnEditRedo (); break; + case ID_EDIT_COPYBRUSH: g_pParentWnd->OnEditCopybrush (); break; + case ID_EDIT_PASTEBRUSH: g_pParentWnd->OnEditPastebrush (); break; + case ID_EDIT_PASTEBRUSHTOCAMERA: g_pParentWnd->OnEditPastebrushToCamera (); break; + case ID_SELECTION_DELETE: g_pParentWnd->OnSelectionDelete (); break; + case ID_EDIT_MAPINFO: g_pParentWnd->OnEditMapinfo (); break; + case ID_EDIT_ENTITYINFO: g_pParentWnd->OnEditEntityinfo (); break; + case ID_BRUSH_SCRIPTS: g_pParentWnd->OnBrushScripts (); break; + case ID_EDIT_LOADPREFAB: g_pParentWnd->OnEditLoadprefab (); break; + case ID_EDIT_SAVEPREFAB: g_pParentWnd->OnEditSaveprefab (); break; + case ID_PREFS: g_pParentWnd->OnPrefs (); break; + case ID_TOGGLECAMERA: g_pParentWnd->OnTogglecamera (); break; + case ID_TOGGLECONSOLE: g_pParentWnd->OnToggleconsole (); break; + case ID_VIEW_ENTITY: g_pParentWnd->OnViewEntity (); break; + case ID_VIEW_GROUPS: g_pParentWnd->OnViewGroups (); break; + case ID_TOGGLEVIEW: g_pParentWnd->OnToggleview (); break; + case ID_TOGGLEVIEW_YZ: g_pParentWnd->OnToggleviewYz (); break; + case ID_TOGGLEVIEW_XZ: g_pParentWnd->OnToggleviewXz (); break; + case ID_TOGGLEZ: g_pParentWnd->OnTogglez (); break; + case ID_VIEW_CENTER: g_pParentWnd->OnViewCenter (); break; + case ID_VIEW_UPFLOOR: g_pParentWnd->OnViewUpfloor (); break; + case ID_VIEW_DOWNFLOOR: g_pParentWnd->OnViewDownfloor (); break; + case ID_VIEW_CENTERVIEW: g_pParentWnd->OnViewCenterview (); break; + case ID_VIEW_NEXTVIEW: g_pParentWnd->OnViewNextview (); break; + case ID_VIEW_XY: g_pParentWnd->OnViewXy (); break; + case ID_VIEW_SIDE: g_pParentWnd->OnViewSide (); break; + case ID_VIEW_FRONT: g_pParentWnd->OnViewFront (); break; + case ID_VIEW_100: g_pParentWnd->OnView100 (); break; + case ID_VIEW_ZOOMIN: g_pParentWnd->OnViewZoomin (); break; + case ID_VIEW_ZOOMOUT: g_pParentWnd->OnViewZoomout (); break; + case ID_VIEW_Z100: g_pParentWnd->OnViewZ100 (); break; + case ID_VIEW_ZZOOMIN: g_pParentWnd->OnViewZzoomin (); break; + case ID_VIEW_ZZOOMOUT: g_pParentWnd->OnViewZzoomout (); break; + case ID_VIEW_CUBEIN: g_pParentWnd->OnViewCubein (); break; + case ID_VIEW_CUBEOUT: g_pParentWnd->OnViewCubeout (); break; + case ID_VIEW_SHOWNAMES: g_pParentWnd->OnViewShownames (); break; + case ID_VIEW_SHOWBLOCKS: g_pParentWnd->OnViewShowblocks (); break; + case ID_VIEW_SHOWCOORDINATES: g_pParentWnd->OnViewShowcoordinates (); break; + case ID_VIEW_SHOWOUTLINE: g_pParentWnd->OnViewShowOutline (); break; + case ID_VIEW_SHOWAXES: g_pParentWnd->OnViewShowAxes (); break; + case ID_VIEW_SHOWWORKZONE: g_pParentWnd->OnViewShowWorkzone (); break; + case ID_VIEW_SHOWANGLES: g_pParentWnd->OnViewShowAngles (); break; + case ID_VIEW_HIDESHOW_HIDESELECTED: g_pParentWnd->OnViewHideshowHideselected (); break; + case ID_VIEW_HIDESHOW_SHOWHIDDEN: g_pParentWnd->OnViewHideshowShowhidden (); break; + case ID_VIEW_ENTITIESAS_BOUNDINGBOX: + case ID_VIEW_ENTITIESAS_WIREFRAME: + case ID_VIEW_ENTITIESAS_SELECTEDWIREFRAME: + case ID_VIEW_ENTITIESAS_SELECTEDSKINNED: + case ID_VIEW_ENTITIESAS_SKINNED: + case ID_VIEW_ENTITIESAS_SKINNEDANDBOXED: + g_pParentWnd->OnEntitiesSetViewAs(id); + break; + case ID_VIEW_CUBICCLIPPING: g_pParentWnd->OnViewCubicclipping (); break; + case ID_VIEW_OPENGLLIGHTING: g_pParentWnd->OnViewOpengllighting (); break; + case ID_SELECTION_DRAGEDGES: g_pParentWnd->OnSelectionDragedges (); break; + case ID_SELECTION_DRAGVERTECIES: g_pParentWnd->OnSelectionDragvertecies (); break; + case ID_SELECTION_CLONE: g_pParentWnd->OnSelectionClone (); break; + case ID_SELECTION_DESELECT: g_pParentWnd->OnSelectionDeselect (); break; + case ID_BRUSH_FLIPX: g_pParentWnd->OnBrushFlipx (); break; + case ID_BRUSH_FLIPY: g_pParentWnd->OnBrushFlipy (); break; + case ID_BRUSH_FLIPZ: g_pParentWnd->OnBrushFlipz (); break; + case ID_BRUSH_ROTATEX: g_pParentWnd->OnBrushRotatex (); break; + case ID_BRUSH_ROTATEY: g_pParentWnd->OnBrushRotatey (); break; + case ID_BRUSH_ROTATEZ: g_pParentWnd->OnBrushRotatez (); break; + case ID_SELECTION_ARBITRARYROTATION: g_pParentWnd->OnSelectionArbitraryrotation (); break; + case ID_SELECT_SCALE: g_pParentWnd->OnSelectScale (); break; + case ID_SELECTION_MAKEHOLLOW: g_pParentWnd->OnSelectionMakehollow (); break; + case ID_SELECTION_CSGSUBTRACT: g_pParentWnd->OnSelectionCsgsubtract (); break; + case ID_SELECTION_CSGMERGE: g_pParentWnd->OnSelectionCsgmerge (); break; + case ID_SELECTION_NOOUTLINE: g_pParentWnd->OnSelectionNoOutline (); break; + case ID_SELECTION_OUTLINESTYLE: g_pParentWnd->OnSelectionOutlineStyle (); break; + case ID_SELECTION_SELECTCOMPLETETALL: g_pParentWnd->OnSelectionSelectcompletetall (); break; + case ID_SELECTION_SELECTTOUCHING: g_pParentWnd->OnSelectionSelecttouching (); break; + case ID_SELECTION_SELECTPARTIALTALL: g_pParentWnd->OnSelectionSelectpartialtall (); break; + case ID_SELECTION_SELECTINSIDE: g_pParentWnd->OnSelectionSelectinside (); break; + case ID_SELECTION_SELECT_NUDGELEFT: g_pParentWnd->OnSelectionSelectNudgeleft (); break; + case ID_SELECTION_SELECT_NUDGERIGHT: g_pParentWnd->OnSelectionSelectNudgeright (); break; + case ID_SELECTION_SELECT_NUDGEUP: g_pParentWnd->OnSelectionSelectNudgeup (); break; + case ID_SELECTION_SELECT_NUDGEDOWN: g_pParentWnd->OnSelectionSelectNudgedown (); break; + case ID_VIEW_CLIPPER: g_pParentWnd->OnViewClipper (); break; + case ID_CLIP_SELECTED: g_pParentWnd->OnClipSelected (); break; + case ID_SPLIT_SELECTED: g_pParentWnd->OnSplitSelected (); break; + case ID_FLIP_CLIP: g_pParentWnd->OnFlipClip (); break; + case ID_SELECTION_CONNECT: g_pParentWnd->OnSelectionConnect (); break; + case ID_SELECTION_UNGROUPENTITY: g_pParentWnd->OnSelectionUngroupentity (); break; + case ID_SELECTION_MERGE: Select_MergeEntity(); break; + case ID_SELECTION_SEPERATE: Select_Seperate(); break; + case ID_SELECTION_MAKE_DETAIL: g_pParentWnd->OnSelectionMakeDetail (); break; + case ID_SELECTION_MAKE_STRUCTURAL: g_pParentWnd->OnSelectionMakeStructural (); break; + case ID_SNAPTOGRID: g_pParentWnd->OnSnaptogrid (); break; + case ID_TEXTURES_SHOWINUSE: g_pParentWnd->OnTexturesShowinuse (); break; + case ID_TEXTURES_SHOWALL: g_pParentWnd->OnTexturesShowall (); break; + case ID_TEXTURES_INSPECTOR: g_pParentWnd->OnTexturesInspector (); break; + case ID_TEXTURE_REPLACEALL: g_pParentWnd->OnTextureReplaceall (); break; + case ID_TOGGLE_LOCK: g_pParentWnd->OnToggleLock (); break; + case ID_TOGGLE_ROTATELOCK: g_pParentWnd->OnToggleRotatelock (); break; + case ID_TEXTURES_LOAD: g_pParentWnd->OnTexturesLoad (); break; + case ID_TEXTURES_RELOADSHADERS: g_pParentWnd->OnTexturesReloadshaders (); break; + case ID_TEXTURES_SHADERS_SHOW: g_pParentWnd->OnTexturesShadersShow (); break; + case ID_TEXTURES_TEXTUREWINDOWSCALE_200: + case ID_TEXTURES_TEXTUREWINDOWSCALE_100: + case ID_TEXTURES_TEXTUREWINDOWSCALE_50: + case ID_TEXTURES_TEXTUREWINDOWSCALE_25: + case ID_TEXTURES_TEXTUREWINDOWSCALE_10: + g_pParentWnd->SetTextureScale (id); + break; + case ID_TEXTURES_LOADLIST: g_pParentWnd->OnTexturesLoadlist (); break; + case ID_TEXTURES_SHADERLISTONLY: g_pParentWnd->OnTexturesShaderlistonly (); break; + case ID_TEXTUREWINDOW_SCALEUP: g_pParentWnd->OnTexturewindowScaleup (); break; + case ID_TEXTUREWINDOW_SCALEDOWN: g_pParentWnd->OnTexturewindowScaledown (); break; + case ID_MISC_BENCHMARK: g_pParentWnd->OnMiscBenchmark (); break; + case ID_COLOR_SETORIGINAL: g_pParentWnd->OnColorSetoriginal (); break; + case ID_COLOR_SETQER: g_pParentWnd->OnColorSetqer (); break; + case ID_COLOR_SETBLACK: g_pParentWnd->OnColorSetblack (); break; + case ID_COLOR_SETYDNAR: g_pParentWnd->OnColorSetydnar (); break; /* ydnar */ + case ID_TEXTUREBK: g_pParentWnd->OnTexturebk (); break; + case ID_COLORS_XYBK: g_pParentWnd->OnColorsXybk (); break; + case ID_COLORS_MAJOR: g_pParentWnd->OnColorsMajor (); break; + case ID_COLORS_MINOR: g_pParentWnd->OnColorsMinor (); break; + case ID_COLORS_GRIDTEXT: g_pParentWnd->OnColorsGridtext (); break; + case ID_COLORS_GRIDBLOCK: g_pParentWnd->OnColorsGridblock (); break; + case ID_COLORS_CAMERABACK: g_pParentWnd->OnColorsCameraBack (); break; + case ID_COLORS_BRUSH: g_pParentWnd->OnColorsBrush (); break; + case ID_COLORS_SELECTEDBRUSH: g_pParentWnd->OnColorsSelectedbrush (); break; + case ID_COLORS_SELECTEDBRUSH3D: g_pParentWnd->OnColorsSelectedbrush3D (); break; + case ID_COLORS_CLIPPER: g_pParentWnd->OnColorsClipper (); break; + case ID_COLORS_VIEWNAME: g_pParentWnd->OnColorsViewname (); break; + case ID_MISC_GAMMA: g_pParentWnd->OnMiscGamma (); break; + case ID_MISC_FINDBRUSH: g_pParentWnd->OnMiscFindbrush (); break; + case ID_MISC_NEXTLEAKSPOT: g_pParentWnd->OnMiscNextleakspot (); break; + case ID_MISC_PREVIOUSLEAKSPOT: g_pParentWnd->OnMiscPreviousleakspot (); break; + case ID_MISC_PRINTXY: g_pParentWnd->OnMiscPrintxy (); break; + case ID_MISC_SELECTENTITYCOLOR: g_pParentWnd->OnMiscSelectentitycolor (); break; + case ID_CONVERTCURVES: g_pParentWnd->OnConvertcurves (); break; + case ID_REGION_OFF: g_pParentWnd->OnRegionOff (); break; + case ID_REGION_SETXY: g_pParentWnd->OnRegionSetxy (); break; + case ID_REGION_SETTALLBRUSH: g_pParentWnd->OnRegionSettallbrush (); break; + case ID_REGION_SETBRUSH: g_pParentWnd->OnRegionSetbrush (); break; + case ID_REGION_SETSELECTION: g_pParentWnd->OnRegionSetselection (); break; + case ID_BRUSH_3SIDED: g_pParentWnd->OnBrush3sided (); break; + case ID_BRUSH_4SIDED: g_pParentWnd->OnBrush4sided (); break; + case ID_BRUSH_5SIDED: g_pParentWnd->OnBrush5sided (); break; + case ID_BRUSH_6SIDED: g_pParentWnd->OnBrush6sided (); break; + case ID_BRUSH_7SIDED: g_pParentWnd->OnBrush7sided (); break; + case ID_BRUSH_8SIDED: g_pParentWnd->OnBrush8sided (); break; + case ID_BRUSH_9SIDED: g_pParentWnd->OnBrush9sided (); break; + case ID_BRUSH_ARBITRARYSIDED: g_pParentWnd->OnBrushArbitrarysided (); break; + case ID_BRUSH_MAKECONE: g_pParentWnd->OnBrushMakecone (); break; + case ID_BRUSH_PRIMITIVES_SPHERE: g_pParentWnd->OnBrushPrimitivesSphere (); break; + case ID_CURVE_PATCHTUBE: g_pParentWnd->OnCurvePatchtube (); break; + case ID_CURVE_PATCHDENSETUBE: g_pParentWnd->OnCurvePatchdensetube (); break; + case ID_CURVE_PATCHVERYDENSETUBE: g_pParentWnd->OnCurvePatchverydensetube (); break; + case ID_CURVE_PATCHSQUARE: g_pParentWnd->OnCurvePatchsquare (); break; + case ID_CURVE_PATCHENDCAP: g_pParentWnd->OnCurvePatchendcap (); break; + case ID_CURVE_PATCHBEVEL: g_pParentWnd->OnCurvePatchbevel (); break; + case ID_CURVE_MOREENDCAPSBEVELS_SQUAREBEVEL: g_pParentWnd->OnCurveMoreendcapsbevelsSquarebevel (); break; + case ID_CURVE_MOREENDCAPSBEVELS_SQUAREENDCAP: g_pParentWnd->OnCurveMoreendcapsbevelsSquareendcap();break; + case ID_CURVE_PATCHCONE: g_pParentWnd->OnCurvePatchcone (); break; + case ID_CURVE_SIMPLEPATCHMESH: g_pParentWnd->OnCurveSimplepatchmesh (); break; + case ID_CURVE_INSERT_INSERTCOLUMN: g_pParentWnd->OnCurveInsertInsertcolumn (); break; + case ID_CURVE_INSERT_ADDCOLUMN: g_pParentWnd->OnCurveInsertAddcolumn (); break; + case ID_CURVE_INSERT_INSERTROW: g_pParentWnd->OnCurveInsertInsertrow (); break; + case ID_CURVE_INSERT_ADDROW: g_pParentWnd->OnCurveInsertAddrow (); break; + case ID_CURVE_DELETE_FIRSTCOLUMN: g_pParentWnd->OnCurveDeleteFirstcolumn (); break; + case ID_CURVE_DELETE_LASTCOLUMN: g_pParentWnd->OnCurveDeleteLastcolumn (); break; + case ID_CURVE_DELETE_FIRSTROW: g_pParentWnd->OnCurveDeleteFirstrow (); break; + case ID_CURVE_DELETE_LASTROW: g_pParentWnd->OnCurveDeleteLastrow (); break; + case ID_CURVE_NEGATIVE: g_pParentWnd->OnCurveNegative (); break; + case ID_CURVE_REDISPERSE_ROWS: g_pParentWnd->OnCurveRedisperseRows (); break; + case ID_CURVE_REDISPERSE_INTERMEDIATE_COLS: g_pParentWnd->OnCurveRedisperseIntermediateCols (); break; + case ID_CURVE_REDISPERSE_INTERMEDIATE_ROWS: g_pParentWnd->OnCurveRedisperseIntermediateRows (); break; + case ID_CURVE_MATRIX_TRANSPOSE: g_pParentWnd->OnCurveMatrixTranspose (); break; + case ID_CURVE_CAP: g_pParentWnd->OnCurveCap (); break; + case ID_CURVE_CYCLECAP: g_pParentWnd->OnCurveCyclecap (); break; + case ID_CURVE_OVERLAY_SET: g_pParentWnd->OnCurveOverlaySet (); break; + case ID_CURVE_OVERLAY_CLEAR: g_pParentWnd->OnCurveOverlayClear (); break; + case ID_CURVE_THICKEN: g_pParentWnd->OnCurveThicken (); break; + case ID_PLUGINS_REFRESH: g_pParentWnd->OnPluginsRefresh (); break; + case ID_HELP: g_pParentWnd->OnHelp (); break; + case ID_HELP_LINKS: g_pParentWnd->OnHelpLinks(); break; + case ID_HELP_BUGREPORT: g_pParentWnd->OnHelpBugreport(); break; + case ID_HELP_COMMANDLIST: g_pParentWnd->OnHelpCommandlist (); break; + case ID_HELP_ABOUT: g_pParentWnd->OnHelpAbout (); break; + case ID_DONTSELECTMODEL: g_pParentWnd->OnDontselectmodel (); break; + case ID_FILTER_AREAPORTALS: g_pParentWnd->OnFilterAreaportals (); break; + case ID_FILTER_CAULK: g_pParentWnd->OnFilterCaulk (); break; + case ID_FILTER_STRUCTURAL: g_pParentWnd->OnFilterStructural (); break; + case ID_FILTER_CLIPS: g_pParentWnd->OnFilterClips (); break; + case ID_FILTER_BOTCLIPS: g_pParentWnd->OnFilterBotClips (); break; + case ID_FILTER_DETAILS: g_pParentWnd->OnFilterDetails (); break; + case ID_FILTER_ENTITIES: g_pParentWnd->OnFilterEntities (); break; + case ID_FILTER_HINTSSKIPS: g_pParentWnd->OnFilterHintsskips (); break; + case ID_FILTER_LIGHTS: g_pParentWnd->OnFilterLights (); break; + case ID_FILTER_LIQUIDS: g_pParentWnd->OnFilterLiquids (); break; + case ID_FILTER_MODELS: g_pParentWnd->OnFilterModels (); break; + case ID_FILTER_PATCHES: g_pParentWnd->OnFilterPatches (); break; + case ID_FILTER_TRANSLUCENT: g_pParentWnd->OnFilterTranslucent (); break; + case ID_FILTER_TRIGGERS: g_pParentWnd->OnFilterTriggers (); break; + case ID_FILTER_WORLD: g_pParentWnd->OnFilterWorld (); break; + case ID_FILTER_PATHS: g_pParentWnd->OnFilterPaths (); break; + case ID_FILTER_CLUSTERPORTALS: g_pParentWnd->OnFilterClusterportals (); break; + case ID_FILTER_LIGHTGRID: g_pParentWnd->OnFilterLightgrid (); break; + + case ID_POPUP_SELECTION: g_pParentWnd->OnPopupSelection (); break; + case ID_VIEW_CHANGE: g_pParentWnd->OnViewChange (); break; + case ID_TEXTURES_POPUP: g_pParentWnd->OnTexturesPopup (); break; + case ID_VIEW_CAMERATOGGLE: g_pParentWnd->ToggleCamera (); break; + case ID_VIEW_CAMERAUPDATE: g_pParentWnd->OnViewCameraupdate (); break; + case ID_SELECT_MOUSEROTATE: g_pParentWnd->OnSelectMouserotate (); break; + case ID_SELECT_MOUSESCALE: g_pParentWnd->OnSelectMousescale (); break; + case ID_SCALELOCKX: g_pParentWnd->OnScalelockx (); break; + case ID_SCALELOCKY: g_pParentWnd->OnScalelocky (); break; + case ID_SCALELOCKZ: g_pParentWnd->OnScalelockz (); break; + case ID_DONTSELECTCURVE: g_pParentWnd->OnDontselectcurve (); break; + case ID_PATCH_SHOWBOUNDINGBOX: g_pParentWnd->OnPatchToggleBox (); break; + case ID_PATCH_WIREFRAME: g_pParentWnd->OnPatchWireframe (); break; + case ID_PATCH_BEND: g_pParentWnd->OnPatchBend (); break; + case ID_PATCH_WELD: g_pParentWnd->OnPatchWeld (); break; + case ID_PATCH_DRILLDOWN: g_pParentWnd->OnPatchDrilldown (); break; + case ID_DROP_GROUP_NAME: g_pParentWnd->OnDropGroupName (); break; + case ID_DROP_GROUP_NEWGROUP: g_pParentWnd->OnDropGroupNewgroup (); break; + case ID_DROP_GROUP_REMOVE: g_pParentWnd->OnDropGroupRemove (); break; + case ID_SHOW_ENTITIES: g_pParentWnd->OnShowEntities (); break; + + case IDC_BTN_FACEFIT: g_pParentWnd->OnFaceFit (); break; + case ID_VIEW_TEXTURE: g_pParentWnd->OnViewTexture (); break; + case ID_PATCH_INSPECTOR: g_pParentWnd->OnPatchInspector (); break; + case ID_CURVE_NEGATIVETEXTUREX: g_pParentWnd->OnCurveNegativeTextureX (); break; + case ID_CURVE_NEGATIVETEXTUREY: g_pParentWnd->OnCurveNegativeTextureY (); break; + case ID_CURVE_INSERTCOLUMN: g_pParentWnd->OnCurveInsertcolumn (); break; + case ID_CURVE_INSERTROW: g_pParentWnd->OnCurveInsertrow (); break; + case ID_CURVE_DELETECOLUMN: g_pParentWnd->OnCurveDeletecolumn (); break; + case ID_CURVE_DELETEROW: g_pParentWnd->OnCurveDeleterow (); break; + case ID_PATCH_TAB: g_pParentWnd->OnPatchTab (); break; + case ID_CAMERA_FORWARD: g_pParentWnd->OnCameraForward (TRUE); break; + case ID_CAMERA_BACK: g_pParentWnd->OnCameraBack (TRUE); break; + case ID_CAMERA_LEFT: g_pParentWnd->OnCameraLeft (TRUE); break; + case ID_CAMERA_RIGHT: g_pParentWnd->OnCameraRight (TRUE); break; + case ID_CAMERA_UP: g_pParentWnd->OnCameraUp (); break; + case ID_CAMERA_DOWN: g_pParentWnd->OnCameraDown (); break; + case ID_CAMERA_ANGLEUP: g_pParentWnd->OnCameraAngleup (); break; + case ID_CAMERA_ANGLEDOWN: g_pParentWnd->OnCameraAngledown (); break; + case ID_CAMERA_STRAFELEFT: g_pParentWnd->OnCameraStrafeleft (TRUE); break; + case ID_CAMERA_STRAFERIGHT: g_pParentWnd->OnCameraStraferight (TRUE); break; + case ID_GRID_TOGGLE: g_pParentWnd->OnGridToggle (); break; + case ID_VIEW_CONSOLE: g_pParentWnd->OnViewConsole (); break; + case ID_VIEW_CROSSHAIR: g_pParentWnd->OnViewCrosshair (); break; + case ID_SELECTION_TEXTURE_FIT: g_pParentWnd->OnSelectionTextureFit (); break; + case ID_SELECTION_TEXTURE_ROTATECLOCK: g_pParentWnd->OnSelectionTextureRotateclock (); break; + case ID_SELECTION_TEXTURE_ROTATECOUNTER: g_pParentWnd->OnSelectionTextureRotatecounter (); break; + case ID_SELECTION_TEXTURE_SCALEUP: g_pParentWnd->OnSelectionTextureScaleup (); break; + case ID_SELECTION_TEXTURE_SCALEDOWN: g_pParentWnd->OnSelectionTextureScaledown (); break; + case ID_SELECTION_TEXTURE_SHIFTLEFT: g_pParentWnd->OnSelectionTextureShiftleft (); break; + case ID_SELECTION_TEXTURE_SHIFTRIGHT: g_pParentWnd->OnSelectionTextureShiftright (); break; + case ID_SELECTION_TEXTURE_SHIFTUP: g_pParentWnd->OnSelectionTextureShiftup (); break; + case ID_SELECTION_TEXTURE_SHIFTDOWN: g_pParentWnd->OnSelectionTextureShiftdown (); break; + case ID_GRID_PREV: g_pParentWnd->OnGridPrev (); break; + case ID_GRID_NEXT: g_pParentWnd->OnGridNext (); break; + case ID_SELECTION_TEXTURE_SCALELEFT: g_pParentWnd->OnSelectionTextureScaleLeft (); break; + case ID_SELECTION_TEXTURE_SCALERIGHT: g_pParentWnd->OnSelectionTextureScaleRight (); break; + case ID_SELECTION_MOVEDOWN: g_pParentWnd->OnSelectionMovedown (); break; + case ID_SELECTION_MOVEUP: g_pParentWnd->OnSelectionMoveup (); break; + case ID_SELECTION_PRINT: g_pParentWnd->OnSelectionPrint (); break; + case ID_SELECTION_TOGGLESIZEPAINT: g_pParentWnd->OnSelectionTogglesizepaint (); break; + case ID_PATCH_NATURALIZE: g_pParentWnd->OnPatchNaturalize (); break; + case ID_SELECT_SNAPTOGRID: g_pParentWnd->OnSnapToGrid (); break; + case ID_SELECT_ALL: g_pParentWnd->OnSelectAll (); break; + case ID_SELECTION_INVERT: g_pParentWnd->OnSelectionInvert (); break; + } + + return TRUE; +} + +static gint timer (gpointer data) +{ + MainFrame *wnd = (MainFrame*)data; + wnd->OnTimer (); + return TRUE; +} + +static gint mainframe_delete (GtkWidget *widget, GdkEvent *event, gpointer data) +{ + MainFrame *wnd = (MainFrame*)data; + + wnd->OnDelete(); + + if (ConfirmModified()) + return FALSE; + + g_qeglobals_gui.d_edit = NULL; + + return TRUE; +} + +static void mainframe_destroy (GtkWidget *widget, gpointer data) +{ + MainFrame *wnd = (MainFrame*)data; + + // avoid saving prefs when the app is minimized + if (g_pParentWnd->IsSleeping()) + { + Sys_Printf("Shutdown while sleeping, not saving prefs\n"); + g_qeglobals.disable_ini = true; + } + + // NOTE TTimo this is very clumsy, in MainFrame::OnDestroy we might call SavePrefs again + // we will do more stuff in OnDestroy for window position saving too, so I guess this call is still relevant? + g_PrefsDlg.SavePrefs (); + + wnd->OnDestroy (); + + // shutdown modules + // NOTE: I've decided to do this before SavePrefs in case we broadcast some shutdown info + // and modules / plugins decide to save some stuff + g_pParentWnd->GetPlugInMgr().Shutdown(); + + delete wnd; + + QGL_Shutdown(); + g_PrefsDlg.Destroy (); + g_dlgSurface.Destroy (); + g_dlgFind.Destroy (); + g_PatchDialog.Destroy (); + + gtk_main_quit (); +} + +static gint mainframe_keypress (GtkWidget* widget, GdkEventKey* event, gpointer data) +{ + unsigned int code = gdk_keyval_to_upper(event->keyval); + + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=924 + if(code == GDK_ISO_Left_Tab) { + code = GDK_Tab; + } + +#ifdef DBG_KBD + Sys_Printf("key: %d (keyval: %d) (ctrl: %d)\n", code, event->keyval, event->state & GDK_CONTROL_MASK); +#endif + + // BUG: http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=865 + // return only if Texture Viewport is in main window, otherwise if Tex viewport is in it's own window + // the Filter GtkEntry won't release focus + if ( g_pParentWnd->GetTexWnd()->m_pFilter == gtk_window_get_focus(GTK_WINDOW(widget)) ) + if ( gtk_widget_is_focus( g_pParentWnd->GetTexWnd()->m_pFilter ) ) + return FALSE; + +#ifdef DBG_KBD + Sys_Printf("mainframe_keypress processing into a command\n"); +#endif + for (int i = 0; i < g_nCommandCount; i++) + { + if (g_Commands[i].m_nKey == code) // find a match? + { + // check modifiers + unsigned int nState = 0; + if (Sys_AltDown ()) + nState |= RAD_ALT; + if ((event->state & GDK_CONTROL_MASK) != 0) + nState |= RAD_CONTROL; + if ((event->state & GDK_SHIFT_MASK) != 0) + nState |= RAD_SHIFT; + if ((g_Commands[i].m_nModifiers & 0x7) == nState) + { + HandleCommand (NULL, GINT_TO_POINTER (g_Commands[i].m_nCommand)); + gtk_signal_emit_stop_by_name (GTK_OBJECT(widget), "key_press_event"); + return FALSE; + } + } + } + + return TRUE; +} + +static gint mainframe_keyrelease (GtkWidget* widget, GdkEventKey* event, gpointer data) +{ + unsigned int code = gdk_keyval_to_upper(event->keyval); + + if (gtk_accelerator_valid (event->keyval, (GdkModifierType)0)) + return TRUE; + + for (int i = 0; i < g_nCommandCount; i++) + { + if (g_Commands[i].m_nKey == code) // find a match? + { + if(!g_Commands[i].m_nModifiers) + { + // Gef: Only call the handler if it's a key that needs keyup events + switch (g_Commands[i].m_nCommand) + { + case ID_CAMERA_FORWARD: + case ID_CAMERA_BACK: + case ID_CAMERA_LEFT: + case ID_CAMERA_RIGHT: + case ID_CAMERA_STRAFELEFT: + case ID_CAMERA_STRAFERIGHT: + { + HandleKeyUp (NULL, GINT_TO_POINTER (g_Commands[i].m_nCommand)); + gtk_signal_emit_stop_by_name (GTK_OBJECT(widget), "key_release_event"); + } + + } + return FALSE; + } + } + } + + return TRUE; +} + + +// ============================================================================= +// Window creation functions + +void AddMenuItem (GtkWidget* item, unsigned int id) +{ + for (int i = 0; i < g_nCommandCount; i++) + if (g_Commands[i].m_nCommand == id) + { + g_object_set_data (G_OBJECT (g_pParentWnd->m_pWidget), g_Commands[i].m_strMenu, item); + break; + } +} + +void MainFrame::handle_help_command(int id) +{ + OpenURL(mHelpURLs[id]->GetBuffer()); +} + +/*! +needed for hooking in Gtk+ +*/ +void HandleHelpCommand (GtkWidget *widget, gpointer data) +{ + int id = GPOINTER_TO_INT (data); + g_pParentWnd->handle_help_command(id); +} + +void MainFrame::process_xlink (Str &FileName, char *menu_name, const char *base_url, GtkWidget *menu, GtkAccelGroup *accel) +{ + xmlDocPtr pDoc; + pDoc = xmlParseFile(FileName.GetBuffer()); + if (pDoc) + { + Sys_Printf("Processing .xlink file '%s'\n", FileName.GetBuffer()); + // create sub menu + GtkWidget* menu_in_menu = create_menu_in_menu_with_mnemonic(menu, menu_name); + // start walking the nodes, find the 'links' one + xmlNodePtr pNode = pDoc->children; + while (pNode && strcmp((const char*)pNode->name, "links")) + pNode=pNode->next; + if (pNode) + { + pNode = pNode->children; + while(pNode) + { + if (!strcmp((const char*)pNode->name, "item")) + { + // process the URL + Str *url; + if (strstr((char *)xmlGetProp(pNode, (xmlChar *)"url"), "http://")) + { + // complete URL + url = new Str; + *url = (char *)xmlGetProp(pNode, (xmlChar *)"url"); + } + else + { + // relative URL + url = new Str; + *url = base_url; + *url += (char *)xmlGetProp(pNode, (xmlChar *)"url"); + } + mHelpURLs.push_back(url); + create_menu_item_with_mnemonic (menu_in_menu, (char *)xmlGetProp(pNode, (xmlChar *)"name"), GTK_SIGNAL_FUNC(HandleHelpCommand), mHelpURLs.size()-1); + } + pNode=pNode->next; + } + } + xmlFreeDoc(pDoc); + } + else + { + Sys_Printf("'%s' not found / parse failed\n", FileName.GetBuffer()); + } +} + +void MainFrame::create_game_help_menu (GtkWidget *menu, GtkAccelGroup *accel) +{ + Str FileName; + list::iterator iGame; + + // start in the global dir + FileName = g_strAppPath; + FileName += "global.xlink"; + process_xlink(FileName, "General", g_strAppPath.GetBuffer(), menu, accel); + + for (iGame = g_PrefsDlg.mGamesDialog.mGames.begin(); iGame != g_PrefsDlg.mGamesDialog.mGames.end(); iGame++) + { + FileName = (*iGame)->mGameToolsPath; + FileName += "game.xlink"; + process_xlink(FileName, (*iGame)->mGameName, (*iGame)->mGameToolsPath.GetBuffer(), menu, accel); + } +} + +void MainFrame::create_main_menu (GtkWidget *window, GtkWidget *vbox) +{ + GtkWidget *handle_box, *menu_bar, *menu, *menu_in_menu, *menu_3, *item; + GtkAccelGroup *accel; + + g_bIgnoreCommands++; + accel = gtk_accel_group_new (); + global_accel = accel; + gtk_window_add_accel_group (GTK_WINDOW (window), accel); + + handle_box = gtk_handle_box_new (); + gtk_box_pack_start (GTK_BOX (vbox), handle_box, FALSE, FALSE, 0); + gtk_widget_show (handle_box); + + menu_bar = gtk_menu_bar_new (); + gtk_container_add (GTK_CONTAINER (handle_box), menu_bar); + gtk_widget_show (menu_bar); + + // File menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_File"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + create_menu_item_with_mnemonic (menu, "_New Map", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_NEW); + menu_separator (menu); + + //++timo temporary experimental stuff for sleep mode.. + item = create_menu_item_with_mnemonic (menu, "_Sleep", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_SLEEP); + g_object_set_data (G_OBJECT (window), "menu_file_sleep", item ); + menu_separator (menu); + // end experimental + + item = create_menu_item_with_mnemonic (menu, "_Open...", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_OPEN); + g_object_set_data (G_OBJECT (window), "menu_file_open", item); + create_menu_item_with_mnemonic (menu, "_Import...", // Hydra: give it it's proper name + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_IMPORTMAP); + item = create_menu_item_with_mnemonic (menu, "_Save", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_SAVE); + g_object_set_data (G_OBJECT (window), "menu_file_save", item); + create_menu_item_with_mnemonic (menu, "Save _as...", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_SAVEAS); + create_menu_item_with_mnemonic (menu, "Save s_elected...", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_EXPORTMAP); + menu_separator (menu); + item = create_menu_item_with_mnemonic (menu, "Save re_gion...", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_SAVEREGION); + g_object_set_data (G_OBJECT (window), "menu_file_saveregion", item); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "New p_roject...", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_NEWPROJECT); + create_menu_item_with_mnemonic (menu, "Load _project...", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_LOADPROJECT); + create_menu_item_with_mnemonic (menu, "Pro_ject settings...", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_PROJECTSETTINGS); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "_Pointfile...", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_POINTFILE); + menu_separator (menu); + item = create_menu_item_with_mnemonic (menu, "Recent Files", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_RECENT1); + g_object_set_data (G_OBJECT (item), "accel", accel); + gtk_widget_set_sensitive (item, FALSE); + MRU_AddWidget (item, 0); + item = create_menu_item_with_mnemonic (menu, "2", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_RECENT2); + gtk_widget_hide (item); + MRU_AddWidget (item, 1); + item = create_menu_item_with_mnemonic (menu, "3", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_RECENT3); + gtk_widget_hide (item); + MRU_AddWidget (item, 2); + item = create_menu_item_with_mnemonic (menu, "4", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_RECENT4); + gtk_widget_hide (item); + MRU_AddWidget (item, 3); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "Check for GtkRadiant update (web)", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_CHECKUPDATE); + + create_menu_item_with_mnemonic (menu, "E_xit", + GTK_SIGNAL_FUNC (HandleCommand), ID_FILE_EXIT); + + // Edit menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_Edit"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + item = create_menu_item_with_mnemonic (menu, "_Undo", + GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_UNDO); + g_object_set_data (G_OBJECT (window), "menu_edit_undo", item); + item = create_menu_item_with_mnemonic (menu, "_Redo", + GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_REDO); + g_object_set_data (G_OBJECT (window), "menu_edit_redo", item); + menu_separator (menu); + item = create_menu_item_with_mnemonic (menu, "_Copy", GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_COPYBRUSH); + item = create_menu_item_with_mnemonic (menu, "_Paste", GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_PASTEBRUSH); + item = create_menu_item_with_mnemonic (menu, "P_aste To Camera", GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_PASTEBRUSHTOCAMERA); + item = create_menu_item_with_mnemonic (menu, "_Delete", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_DELETE); + g_object_set_data (G_OBJECT (window), "menu_selection_delete", item); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "Map Info...", GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_MAPINFO); + create_menu_item_with_mnemonic (menu, "Entity Info...", GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_ENTITYINFO); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "Brush Scripts...", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_SCRIPTS); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "Load Pre_fab...", GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_LOADPREFAB); + create_menu_item_with_mnemonic (menu, "Save Selection as Prefab...", GTK_SIGNAL_FUNC (HandleCommand), ID_EDIT_SAVEPREFAB); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "Preferences...", GTK_SIGNAL_FUNC (HandleCommand), ID_PREFS); + + // View menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_View"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Toggle"); + create_menu_item_with_mnemonic (menu_in_menu, "Camera View", GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLECAMERA); + create_menu_item_with_mnemonic (menu_in_menu, "Console View", GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLECONSOLE); + item = create_menu_item_with_mnemonic (menu_in_menu, "Entity View", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ENTITY); + g_object_set_data (G_OBJECT (window), "menu_view_entity", item); + // create_menu_item_with_mnemonic (menu_in_menu, "Groups View", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_GROUPS); + create_menu_item_with_mnemonic (menu_in_menu, "XY (Top)", GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLEVIEW); + create_menu_item_with_mnemonic (menu_in_menu, "YZ (Side)", GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLEVIEW_YZ); + create_menu_item_with_mnemonic (menu_in_menu, "XZ (Front)", GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLEVIEW_XZ); + create_menu_item_with_mnemonic (menu_in_menu, "Z View", GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLEZ); + menu_separator (menu); + item = create_menu_item_with_mnemonic (menu, "_Center", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CENTER); + item = create_menu_item_with_mnemonic (menu, "_Center 2d", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CENTERVIEW); + item = create_menu_item_with_mnemonic (menu, "_Up Floor", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_UPFLOOR); + item = create_menu_item_with_mnemonic (menu, "_Down Floor", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_DOWNFLOOR); + menu_separator (menu); + item = create_menu_item_with_mnemonic (menu, "_Next (XY, YZ, XY)", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_NEXTVIEW); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Layout"); + create_menu_item_with_mnemonic (menu_in_menu, "XY (Top)", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_XY); + create_menu_item_with_mnemonic (menu_in_menu, "YZ", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SIDE); + create_menu_item_with_mnemonic (menu_in_menu, "XZ", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_FRONT); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Zoom"); + create_menu_item_with_mnemonic (menu_in_menu, "_XY 100%", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_100); + item = create_menu_item_with_mnemonic (menu_in_menu, "XY Zoom _In", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ZOOMIN); + item = create_menu_item_with_mnemonic (menu_in_menu, "XY Zoom _Out", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ZOOMOUT); + menu_separator (menu_in_menu); + create_menu_item_with_mnemonic (menu_in_menu, "_Z 100%", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_Z100); + item = create_menu_item_with_mnemonic (menu_in_menu, "Z Zoo_m In", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ZZOOMIN); + g_object_set_data (G_OBJECT (window), "menu_view_zzoomin", item); + item = create_menu_item_with_mnemonic (menu_in_menu, "Z Zoom O_ut", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ZZOOMOUT); + g_object_set_data (G_OBJECT (window), "menu_view_zzoomout", item); + menu_separator (menu_in_menu); + item = create_menu_item_with_mnemonic (menu_in_menu, "Cubic Clip Zoom In", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CUBEIN); + item = create_menu_item_with_mnemonic (menu_in_menu, "Cubic Clip Zoom Out", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CUBEOUT); + menu_separator (menu); + + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Show"); + item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show _Angles", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SHOWANGLES, FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_showangles", item); + item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show _Names", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SHOWNAMES, TRUE); + g_object_set_data (G_OBJECT (window), "menu_view_shownames", item); + item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show Blocks", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SHOWBLOCKS, FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_showblocks", item); + item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show C_oordinates", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SHOWCOORDINATES, TRUE); + g_object_set_data (G_OBJECT (window), "menu_view_showcoordinates", item); + item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show Window Outline", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SHOWOUTLINE, TRUE); + g_object_set_data (G_OBJECT (window), "menu_view_showoutline", item); + item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show ZBuffered Outline", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_NOOUTLINE, TRUE); + g_object_set_data (G_OBJECT (window), "menu_selection_nooutline", item); + item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show Axes", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SHOWAXES, TRUE); + g_object_set_data (G_OBJECT (window), "menu_view_showaxes", item); + item = create_check_menu_item_with_mnemonic (menu_in_menu, "Show Workzone", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_SHOWWORKZONE, FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_showworkzone", item); + + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Filter"); + create_check_menu_item_with_mnemonic (menu_in_menu, "World", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_WORLD, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Entities", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_ENTITIES, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Areaportals", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_AREAPORTALS, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Translucent", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_TRANSLUCENT, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Liquids", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_LIQUIDS, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Caulk", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_CAULK, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Clips", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_CLIPS, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Paths", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_PATHS, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Clusterportals", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_CLUSTERPORTALS, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Lights", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_LIGHTS, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Structural", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_STRUCTURAL, FALSE); + item = create_check_menu_item_with_mnemonic (menu_in_menu, "Lightgrid", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_LIGHTGRID, FALSE); + g_object_set_data (G_OBJECT (window), "menu_filter_lightgrid", item); + create_check_menu_item_with_mnemonic (menu_in_menu, "Patches", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_PATCHES, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Details", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_DETAILS, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Hints", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_HINTSSKIPS, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Models", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_MODELS, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Triggers", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_TRIGGERS, FALSE); + create_check_menu_item_with_mnemonic (menu_in_menu, "Botclips", GTK_SIGNAL_FUNC (HandleCommand), ID_FILTER_BOTCLIPS, FALSE); + + menu_separator (menu); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Hide/Show"); + create_menu_item_with_mnemonic (menu_in_menu, "Hide Selected", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_HIDESHOW_HIDESELECTED); + create_menu_item_with_mnemonic (menu_in_menu, "Show Hidden", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_HIDESHOW_SHOWHIDDEN); + menu_separator (menu); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Entities as"); + g_object_set_data (G_OBJECT (window), "view_entitiesas_menu", menu_in_menu); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, NULL, "Bounding box", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ENTITIESAS_BOUNDINGBOX,FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_entitiesas_boundingbox", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "Wireframe", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ENTITIESAS_WIREFRAME,FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_entitiesas_wireframe", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "Selected Wireframe", + GTK_SIGNAL_FUNC (HandleCommand),ID_VIEW_ENTITIESAS_SELECTEDWIREFRAME,FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_entitiesas_selectedwireframe", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "Selected Skinned", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ENTITIESAS_SELECTEDSKINNED,FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_entitiesas_selectedskinned", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "Skinned", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ENTITIESAS_SKINNED,FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_entitiesas_skinned", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "Skinned and Boxed", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_ENTITIESAS_SKINNEDANDBOXED,FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_entitiesas_skinnedandboxed", item); + menu_separator (menu); + item = create_check_menu_item_with_mnemonic (menu, "Cubic Clipping", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CUBICCLIPPING, TRUE); + g_object_set_data (G_OBJECT (window), "menu_view_cubicclipping", item); + menu_separator (menu); + item = create_check_menu_item_with_mnemonic (menu, "OpenGL Lighting", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_OPENGLLIGHTING, FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_opengllighting", item); + + // Selection menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_Selection"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Drag"); + create_menu_item_with_mnemonic (menu_in_menu, "Drag _Edges", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_DRAGEDGES); + create_menu_item_with_mnemonic (menu_in_menu, "Drag _Vertices", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_DRAGVERTECIES); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "_Clone", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_CLONE); + item = create_menu_item_with_mnemonic (menu, "Deselect", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_DESELECT); + item = create_menu_item_with_mnemonic (menu, "Invert", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_INVERT); +#ifndef QUAKE3 + create_menu_item_with_mnemonic (menu, "_Delete", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_DELETE); +#endif + menu_separator (menu); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Flip"); + create_menu_item_with_mnemonic (menu_in_menu, "Flip _X", + GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_FLIPX); + create_menu_item_with_mnemonic (menu_in_menu, "Flip _Y", + GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_FLIPY); + create_menu_item_with_mnemonic (menu_in_menu, "Flip _Z", + GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_FLIPZ); + menu_separator (menu); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Rotate"); + create_menu_item_with_mnemonic (menu_in_menu, "Rotate X", + GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_ROTATEX); + create_menu_item_with_mnemonic (menu_in_menu, "Rotate Y", + GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_ROTATEY); + create_menu_item_with_mnemonic (menu_in_menu, "Rotate Z", + GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_ROTATEZ); + create_menu_item_with_mnemonic (menu_in_menu, "Arbitrary rotation...", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_ARBITRARYROTATION); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "Scale...", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECT_SCALE); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "CSG"); + create_menu_item_with_mnemonic (menu_in_menu, "Make _Hollow", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MAKEHOLLOW); + create_menu_item_with_mnemonic (menu_in_menu, "CSG _Subtract", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_CSGSUBTRACT); + create_menu_item_with_mnemonic (menu_in_menu, "CSG _Merge", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_CSGMERGE); + menu_separator (menu); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Select"); + create_menu_item_with_mnemonic (menu_in_menu, "Select Complete _Tall", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTCOMPLETETALL); + create_menu_item_with_mnemonic (menu_in_menu, "Select T_ouching", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTTOUCHING); + create_menu_item_with_mnemonic (menu_in_menu, "Select _Partial Tall", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTPARTIALTALL); + create_menu_item_with_mnemonic (menu_in_menu, "Select _Inside", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTINSIDE); +#ifndef QUAKE3 + create_menu_item_with_mnemonic (menu_in_menu, "Nudge Left", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGELEFT); + create_menu_item_with_mnemonic (menu_in_menu, "Nudge Right", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGERIGHT); + create_menu_item_with_mnemonic (menu_in_menu, "Nudge Up", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGEUP); + create_menu_item_with_mnemonic (menu_in_menu, "Nudge Down", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGEDOWN); +#endif + menu_separator (menu); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Clipper"); + create_menu_item_with_mnemonic (menu_in_menu, "Toggle Clipper", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CLIPPER); + menu_separator (menu_in_menu); + create_menu_item_with_mnemonic (menu_in_menu, "Clip selection", + GTK_SIGNAL_FUNC (HandleCommand), ID_CLIP_SELECTED); + create_menu_item_with_mnemonic (menu_in_menu, "Split selection", + GTK_SIGNAL_FUNC (HandleCommand), ID_SPLIT_SELECTED); + create_menu_item_with_mnemonic (menu_in_menu, "Flip Clip orientation", + GTK_SIGNAL_FUNC (HandleCommand), ID_FLIP_CLIP); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "Connect entities", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_CONNECT); + create_menu_item_with_mnemonic (menu, "Ungroup entity", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_UNGROUPENTITY); + create_menu_item_with_mnemonic (menu, "Make detail", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MAKE_DETAIL); + create_menu_item_with_mnemonic (menu, "Make structural", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MAKE_STRUCTURAL); + + // BSP menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_Bsp"); + + menu_separator (menu); + g_object_set_data (G_OBJECT (window), "menu_bsp", menu); + + // Grid menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_Grid"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + item = create_radio_menu_item_with_mnemonic (menu, NULL, "Grid0.25", + GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_025, FALSE); + g_object_set_data (G_OBJECT (window), "menu_grid_025", item); + item = create_radio_menu_item_with_mnemonic (menu, item, "Grid0.5", + GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_05, FALSE); + g_object_set_data (G_OBJECT (window), "menu_grid_05", item); + item = create_radio_menu_item_with_mnemonic (menu, item, "Grid1", + GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_1, FALSE); + g_object_set_data (G_OBJECT (window), "menu_grid_1", item); + item = create_radio_menu_item_with_mnemonic (menu, item, "Grid2", + GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_2, FALSE); + g_object_set_data (G_OBJECT (window), "menu_grid_2", item); + item = create_radio_menu_item_with_mnemonic (menu, item, "Grid4", + GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_4, FALSE); + g_object_set_data (G_OBJECT (window), "menu_grid_4", item); + item = create_radio_menu_item_with_mnemonic (menu, item, "Grid8", + GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_8, TRUE); + g_object_set_data (G_OBJECT (window), "menu_grid_8", item); + item = create_radio_menu_item_with_mnemonic (menu, item, "Grid16", + GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_16, FALSE); + g_object_set_data (G_OBJECT (window), "menu_grid_16", item); + item = create_radio_menu_item_with_mnemonic (menu, item, "Grid32", + GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_32, FALSE); + g_object_set_data (G_OBJECT (window), "menu_grid_32", item); + item = create_radio_menu_item_with_mnemonic (menu, item, "Grid64", + GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_64, FALSE); + g_object_set_data (G_OBJECT (window), "menu_grid_64", item); + item = create_radio_menu_item_with_mnemonic (menu, item, "Grid128", + GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_128, FALSE); + g_object_set_data (G_OBJECT (window), "menu_grid_128", item); + item = create_radio_menu_item_with_mnemonic (menu, item, "Grid256", + GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_256, FALSE); + g_object_set_data (G_OBJECT (window), "menu_grid_256", item); + menu_separator (menu); + item = create_check_menu_item_with_mnemonic (menu, "Snap to grid", + GTK_SIGNAL_FUNC (HandleCommand), ID_SNAPTOGRID, TRUE); + g_object_set_data (G_OBJECT (window), "menu_snaptogrid", item); + + // Textures menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_Textures"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + item = create_check_menu_item_with_mnemonic (menu, "Show In _Use", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_SHOWINUSE, FALSE); + g_object_set_data (G_OBJECT (window), "menu_textures_showinuse", item); + item = create_check_menu_item_with_mnemonic (menu, "Show _All", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_SHOWALL, FALSE); + g_object_set_data (G_OBJECT (window), "menu_textures_showall", item); + menu_separator (menu); + item = create_check_menu_item_with_mnemonic (menu, "Show shaders", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_SHADERS_SHOW, FALSE); + g_object_set_data (G_OBJECT (window), "menu_textures_shaders_show", item); + item = create_menu_item_with_mnemonic (menu, "Flush & Reload Shaders", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_RELOADSHADERS); + g_object_set_data (G_OBJECT (window), "menu_textures_reloadshaders", item); + item = create_menu_item_with_mnemonic (menu, "Load directory...", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_LOAD); + g_object_set_data (G_OBJECT (window), "menu_textures_load", item); + item = create_menu_item_with_mnemonic (menu, "Directory list...", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_LOADLIST); + menu_separator (menu); + + item = create_menu_item_with_mnemonic (menu, "_Surface Inspector", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_INSPECTOR); + menu_separator (menu); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Render Quality"); + g_object_set_data (G_OBJECT (window), "render_quality_menu", menu_in_menu); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, NULL, "_Wireframe", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_WIREFRAME, FALSE); + g_object_set_data (G_OBJECT (window), "menu_textures_wireframe", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "_Flat shade", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_FLATSHADE, FALSE); + g_object_set_data (G_OBJECT (window), "menu_textures_flatshade", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "_Nearest", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_NEAREST, FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_nearest", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "Nearest _Mipmap", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_NEARESTMIPMAP, FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_nearestmipmap", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "_Linear", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_LINEAR, FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_linear", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "_Bilinear", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_BILINEAR, FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_bilinear", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "B_ilinear Mipmap", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_BILINEARMIPMAP, FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_bilinearmipmap", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "T_rilinear", + GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_TRILINEAR, FALSE); + g_object_set_data (G_OBJECT (window), "menu_view_trilinear", item); + create_menu_item_with_mnemonic (menu, "Find / Replace...", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURE_REPLACEALL); + + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Texture Lock"); + item = create_check_menu_item_with_mnemonic (menu_in_menu, "Moves", + GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLE_LOCK, TRUE); + g_object_set_data (G_OBJECT (window), "menu_toggle_lock", item); + item = create_check_menu_item_with_mnemonic (menu_in_menu, "Rotations", + GTK_SIGNAL_FUNC (HandleCommand), ID_TOGGLE_ROTATELOCK, TRUE); + g_object_set_data (G_OBJECT (window), "menu_toggle_rotatelock", item); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Texture Window Scale"); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, NULL, "200%", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_TEXTUREWINDOWSCALE_200, FALSE); + g_object_set_data (G_OBJECT (window), "menu_textures_texturewindowscale_200", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "100%", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_TEXTUREWINDOWSCALE_100, FALSE); + g_object_set_data (G_OBJECT (window), "menu_textures_texturewindowscale_100", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "50%", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_TEXTUREWINDOWSCALE_50, FALSE); + g_object_set_data (G_OBJECT (window), "menu_textures_texturewindowscale_50", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "25%", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_TEXTUREWINDOWSCALE_25, FALSE); + g_object_set_data (G_OBJECT (window), "menu_textures_texturewindowscale_25", item); + item = create_radio_menu_item_with_mnemonic (menu_in_menu, item, "10%", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_TEXTUREWINDOWSCALE_10, FALSE); + g_object_set_data (G_OBJECT (window), "menu_textures_texturewindowscale_10", item); + item = menu_separator (menu); + item = create_check_menu_item_with_mnemonic (menu, "shaderlist.txt only", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTURES_SHADERLISTONLY, FALSE); + g_object_set_data (G_OBJECT (window), "menu_textures_shaderlistonly", item); + item = menu_separator (menu); + g_object_set_data (G_OBJECT (window), "menu_textures_separator", item); + g_object_set_data (G_OBJECT (window), "menu_textures", menu); + + // Misc menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_Misc"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + create_menu_item_with_mnemonic (menu, "_Benchmark", GTK_SIGNAL_FUNC (HandleCommand), ID_MISC_BENCHMARK); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Colors"); + menu_3 = create_menu_in_menu_with_mnemonic (menu_in_menu, "Themes"); + create_menu_item_with_mnemonic (menu_3, "QE4 Original", GTK_SIGNAL_FUNC (HandleCommand), ID_COLOR_SETORIGINAL); + create_menu_item_with_mnemonic (menu_3, "Q3Radiant Original", GTK_SIGNAL_FUNC (HandleCommand), ID_COLOR_SETQER); + create_menu_item_with_mnemonic (menu_3, "Black and Green", GTK_SIGNAL_FUNC (HandleCommand), ID_COLOR_SETBLACK); + create_menu_item_with_mnemonic (menu_3, "Maya/Max/Lightwave Emulation", GTK_SIGNAL_FUNC (HandleCommand), ID_COLOR_SETYDNAR); + + menu_separator (menu_in_menu); + create_menu_item_with_mnemonic (menu_in_menu, "_Texture Background...", + GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTUREBK); + create_menu_item_with_mnemonic (menu_in_menu, "Grid Background...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_XYBK); + create_menu_item_with_mnemonic (menu_in_menu, "Grid Major...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_MAJOR); + create_menu_item_with_mnemonic (menu_in_menu, "Grid Minor...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_MINOR); + create_menu_item_with_mnemonic (menu_in_menu, "Grid Major Small...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_MAJOR_ALT); + create_menu_item_with_mnemonic (menu_in_menu, "Grid Minor Small...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_MINOR_ALT); + create_menu_item_with_mnemonic (menu_in_menu, "Grid Text...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_GRIDTEXT); + create_menu_item_with_mnemonic (menu_in_menu, "Grid Block...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_GRIDBLOCK); + create_menu_item_with_mnemonic (menu_in_menu, "Default Brush...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_BRUSH); + create_menu_item_with_mnemonic (menu_in_menu, "Camera Background...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_CAMERABACK); + create_menu_item_with_mnemonic (menu_in_menu, "Selected Brush...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_SELECTEDBRUSH); + create_menu_item_with_mnemonic (menu_in_menu, "Selected Brush (Camera)...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_SELECTEDBRUSH3D); + create_menu_item_with_mnemonic (menu_in_menu, "Clipper...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_CLIPPER); + create_menu_item_with_mnemonic (menu_in_menu, "Active View name...", + GTK_SIGNAL_FUNC (HandleCommand), ID_COLORS_VIEWNAME); + + create_menu_item_with_mnemonic (menu, "_Gamma...", + GTK_SIGNAL_FUNC (HandleCommand), ID_MISC_GAMMA); + create_menu_item_with_mnemonic (menu, "Find brush...", + GTK_SIGNAL_FUNC (HandleCommand), ID_MISC_FINDBRUSH); + item = create_menu_item_with_mnemonic (menu, "Next leak spot", + GTK_SIGNAL_FUNC (HandleCommand), ID_MISC_NEXTLEAKSPOT); + item = create_menu_item_with_mnemonic (menu, "Previous leak spot", + GTK_SIGNAL_FUNC (HandleCommand), ID_MISC_PREVIOUSLEAKSPOT); + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=394 +// create_menu_item_with_mnemonic (menu, "_Print XY View", GTK_SIGNAL_FUNC (HandleCommand), ID_MISC_PRINTXY); + item = create_menu_item_with_mnemonic (menu, "_Select Entity Color...", + GTK_SIGNAL_FUNC (HandleCommand), ID_MISC_SELECTENTITYCOLOR); + g_object_set_data (G_OBJECT (window), "menu_misc_selectentitycolor", item); + + // Region menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_Region"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + create_menu_item_with_mnemonic (menu, "_Off", + GTK_SIGNAL_FUNC (HandleCommand), ID_REGION_OFF); + create_menu_item_with_mnemonic (menu, "_Set XY", + GTK_SIGNAL_FUNC (HandleCommand), ID_REGION_SETXY); + create_menu_item_with_mnemonic (menu, "Set _Tall Brush", + GTK_SIGNAL_FUNC (HandleCommand), ID_REGION_SETTALLBRUSH); + create_menu_item_with_mnemonic (menu, "Set _Brush", + GTK_SIGNAL_FUNC (HandleCommand), ID_REGION_SETBRUSH); + create_menu_item_with_mnemonic (menu, "Set Se_lected Brushes", + GTK_SIGNAL_FUNC (HandleCommand), ID_REGION_SETSELECTION); + + // Brush menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_Brush"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + item = create_menu_item_with_mnemonic (menu, "3 sided", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_3SIDED); + item = create_menu_item_with_mnemonic (menu, "4 sided", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_4SIDED); + item = create_menu_item_with_mnemonic (menu, "5 sided", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_5SIDED); + item = create_menu_item_with_mnemonic (menu, "6 sided", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_6SIDED); + item = create_menu_item_with_mnemonic (menu, "7 sided", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_7SIDED); + item = create_menu_item_with_mnemonic (menu, "8 sided", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_8SIDED); + item = create_menu_item_with_mnemonic (menu, "9 sided", GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_9SIDED); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "Arbitrary sided...", + GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_ARBITRARYSIDED); + menu_separator (menu); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Primitives"); + create_menu_item_with_mnemonic (menu_in_menu, "Cone...", + GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_MAKECONE); + create_menu_item_with_mnemonic (menu_in_menu, "Sphere...", + GTK_SIGNAL_FUNC (HandleCommand), ID_BRUSH_PRIMITIVES_SPHERE); + + // Curve menu + if (!g_pGameDescription->mNoPatch) + { + menu = create_sub_menu_with_mnemonic (menu_bar, "_Curve"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + create_menu_item_with_mnemonic (menu, "Cylinder", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PATCHTUBE); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "More Cylinders"); + create_menu_item_with_mnemonic (menu_in_menu, "Dense Cylinder", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PATCHDENSETUBE); + create_menu_item_with_mnemonic (menu_in_menu, "Very Dense Cylinder", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PATCHVERYDENSETUBE); + create_menu_item_with_mnemonic (menu_in_menu, "Square Cylinder", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PATCHSQUARE); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "End cap", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PATCHENDCAP); + create_menu_item_with_mnemonic (menu, "Bevel", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PATCHBEVEL); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "More End caps, Bevels"); + create_menu_item_with_mnemonic (menu_in_menu, "Square Endcap", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_MOREENDCAPSBEVELS_SQUAREBEVEL); + create_menu_item_with_mnemonic (menu_in_menu, "Square Bevel", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_MOREENDCAPSBEVELS_SQUAREENDCAP); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "Cone", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PATCHCONE); + item = create_menu_item_with_mnemonic (menu, "Sphere", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_PRIMITIVES_SPHERE); + gtk_widget_set_sensitive (item, FALSE); + menu_separator (menu); + item = create_menu_item_with_mnemonic (menu, "Simple Patch Mesh...", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_SIMPLEPATCHMESH); + g_object_set_data (G_OBJECT (window), "menu_simplepatchmesh", item); + menu_separator (menu); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Insert"); + create_menu_item_with_mnemonic (menu_in_menu, "Insert (2) Columns", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_INSERT_INSERTCOLUMN); + create_menu_item_with_mnemonic (menu_in_menu, "Add (2) Columns", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_INSERT_ADDCOLUMN); + menu_separator (menu_in_menu); + create_menu_item_with_mnemonic (menu_in_menu, "Insert (2) Rows", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_INSERT_INSERTROW); + create_menu_item_with_mnemonic (menu_in_menu, "Add (2) Rows", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_INSERT_ADDROW); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Delete"); + create_menu_item_with_mnemonic (menu_in_menu, "First (2) Columns", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_DELETE_FIRSTCOLUMN); + create_menu_item_with_mnemonic (menu_in_menu, "Last (2) Columns", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_DELETE_LASTCOLUMN); + menu_separator (menu_in_menu); + create_menu_item_with_mnemonic (menu_in_menu, "First (2) Rows", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_DELETE_FIRSTROW); + create_menu_item_with_mnemonic (menu_in_menu, "Last (2) Rows", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_DELETE_LASTROW); + menu_separator (menu); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Matrix"); + create_menu_item_with_mnemonic (menu_in_menu, "Invert", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_NEGATIVE); + menu_3 = create_menu_in_menu_with_mnemonic (menu_in_menu, "Re-disperse"); + create_menu_item_with_mnemonic (menu_3, "Rows", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_REDISPERSE_ROWS); + create_menu_item_with_mnemonic (menu_3, "Cols (Intermediate)", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_REDISPERSE_INTERMEDIATE_COLS); + create_menu_item_with_mnemonic (menu_3, "Rows (Intermediate)", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_REDISPERSE_INTERMEDIATE_ROWS); + create_menu_item_with_mnemonic (menu_in_menu, "Transpose", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_MATRIX_TRANSPOSE); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "Cap Selection", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_CAP); + create_menu_item_with_mnemonic (menu, "Cycle Cap Texture", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_CYCLECAP); + menu_separator (menu); + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Overlay"); + create_menu_item_with_mnemonic (menu_in_menu, "Set", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_OVERLAY_SET); + create_menu_item_with_mnemonic (menu_in_menu, "Clear", + GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_OVERLAY_CLEAR); + menu_separator (menu); + create_menu_item_with_mnemonic (menu, "Thicken...", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_THICKEN); + } + // Plugins menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_Plugins"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + /* + create_menu_item_with_mnemonic (menu, "Refresh", GTK_SIGNAL_FUNC (HandleCommand), ID_PLUGINS_REFRESH); + */ + // NOTE: the seperator is used when doing a refresh of the list, everything past the seperator is removed + item = menu_separator (menu); + g_object_set_data (G_OBJECT (window), "menu_plugin_separator", item); + g_object_set_data (G_OBJECT (window), "menu_plugin", menu); + + // Help menu + menu = create_sub_menu_with_mnemonic (menu_bar, "_Help"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + item = create_menu_item_with_mnemonic (menu, "Manual", + GTK_SIGNAL_FUNC (HandleCommand), ID_HELP); + gtk_widget_add_accelerator (item, "activate", accel, GDK_F1, (GdkModifierType)0, GTK_ACCEL_VISIBLE); + + // this creates all the per-game drop downs for the game pack helps + // it will take care of hooking the Sys_OpenURL calls etc. + create_game_help_menu(menu, accel); + + // TTimo: this is in global.xlink now + //create_menu_item_with_mnemonic (menu, "Links", + // GTK_SIGNAL_FUNC (HandleCommand), ID_HELP_LINKS); + create_menu_item_with_mnemonic (menu, "Bug report", + GTK_SIGNAL_FUNC (HandleCommand), ID_HELP_BUGREPORT); + create_menu_item_with_mnemonic (menu, "Shortcuts list", + GTK_SIGNAL_FUNC (HandleCommand), ID_HELP_COMMANDLIST); + create_menu_item_with_mnemonic (menu, "_About", + GTK_SIGNAL_FUNC (HandleCommand), ID_HELP_ABOUT); + + + // leo: Hidden menu to make the accelerators work, + // this is a hack that needs to be changed later if someone has a better idea. + // NOTE TTimo + // maybe the better idea would be NOT to use any such accelerator scheme and do all key listening and interpret ourselves + menu = create_sub_menu_with_mnemonic (menu_bar, "Hidden"); + if (g_PrefsDlg.m_bDetachableMenus) + menu_tearoff (menu); + + gtk_widget_hide (gtk_menu_get_attach_widget (GTK_MENU (menu))); + + create_menu_item_with_mnemonic (menu, "BendMode", GTK_SIGNAL_FUNC (HandleCommand), ID_PATCH_BEND); + create_menu_item_with_mnemonic (menu, "FitTexture", GTK_SIGNAL_FUNC (HandleCommand), IDC_BTN_FACEFIT); + create_menu_item_with_mnemonic (menu, "ViewTextures", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_TEXTURE); + create_menu_item_with_mnemonic (menu, "PatchInspector", GTK_SIGNAL_FUNC (HandleCommand), ID_PATCH_INSPECTOR); + create_menu_item_with_mnemonic (menu, "InvertCurveTextureX", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_NEGATIVETEXTUREY); + create_menu_item_with_mnemonic (menu, "InvertCurveTextureY", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_NEGATIVETEXTUREX); + create_menu_item_with_mnemonic (menu, "IncPatchColumn", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_INSERTCOLUMN); + create_menu_item_with_mnemonic (menu, "IncPatchRow", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_INSERTROW); + create_menu_item_with_mnemonic (menu, "DecPatchColumn", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_DELETECOLUMN); + create_menu_item_with_mnemonic (menu, "DecPatchRow", GTK_SIGNAL_FUNC (HandleCommand), ID_CURVE_DELETEROW); + create_menu_item_with_mnemonic (menu, "Patch TAB", GTK_SIGNAL_FUNC (HandleCommand), ID_PATCH_TAB); + create_menu_item_with_mnemonic (menu, "Patch TAB", GTK_SIGNAL_FUNC (HandleCommand), ID_PATCH_TAB); + create_menu_item_with_mnemonic (menu, "SelectNudgeDown", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGEDOWN); + create_menu_item_with_mnemonic (menu, "CameraForward", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_FORWARD); + create_menu_item_with_mnemonic (menu, "CameraBack", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_BACK); + create_menu_item_with_mnemonic (menu, "CameraLeft", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_LEFT); + create_menu_item_with_mnemonic (menu, "CameraRight", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_RIGHT); + create_menu_item_with_mnemonic (menu, "CameraUp", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_UP); + create_menu_item_with_mnemonic (menu, "CameraDown", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_DOWN); + create_menu_item_with_mnemonic (menu, "CameraAngleUp", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_ANGLEUP); + create_menu_item_with_mnemonic (menu, "CameraAngleDown", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_ANGLEDOWN); + create_menu_item_with_mnemonic (menu, "CameraStrafeRight", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_STRAFERIGHT); + create_menu_item_with_mnemonic (menu, "CameraStrafeLeft", GTK_SIGNAL_FUNC (HandleCommand), ID_CAMERA_STRAFELEFT); + create_menu_item_with_mnemonic (menu, "ToggleGrid", GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_TOGGLE); + create_menu_item_with_mnemonic (menu, "ToggleCrosshairs", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CROSSHAIR); + create_menu_item_with_mnemonic (menu, "ToggleRealtime", GTK_SIGNAL_FUNC (HandleCommand), ID_VIEW_CAMERAUPDATE); + create_menu_item_with_mnemonic (menu, "MouseRotate", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECT_MOUSEROTATE); + create_menu_item_with_mnemonic (menu, "TexRotateClock", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_ROTATECLOCK); + create_menu_item_with_mnemonic (menu, "TexRotateCounter", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_ROTATECOUNTER); + create_menu_item_with_mnemonic (menu, "TexScaleUp", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SCALEUP); + create_menu_item_with_mnemonic (menu, "TexScaleDown", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SCALEDOWN); + create_menu_item_with_mnemonic (menu, "TexShiftLeft", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SHIFTLEFT); + create_menu_item_with_mnemonic (menu, "TexShiftRight", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SHIFTRIGHT); + create_menu_item_with_mnemonic (menu, "TexShiftUp", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SHIFTUP); + create_menu_item_with_mnemonic (menu, "TexShiftDown", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SHIFTDOWN); + create_menu_item_with_mnemonic (menu, "GridDown", GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_PREV); + create_menu_item_with_mnemonic (menu, "GridUp", GTK_SIGNAL_FUNC (HandleCommand), ID_GRID_NEXT); + create_menu_item_with_mnemonic (menu, "TexScaleLeft", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SCALELEFT); + create_menu_item_with_mnemonic (menu, "TexScaleRight", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TEXTURE_SCALERIGHT); + create_menu_item_with_mnemonic (menu, "MoveSelectionDOWN", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MOVEDOWN); + create_menu_item_with_mnemonic (menu, "MoveSelectionUP", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MOVEUP); + create_menu_item_with_mnemonic (menu, "DumpSelectedBrush", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_PRINT); + create_menu_item_with_mnemonic (menu, "ToggleSizePaint", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_TOGGLESIZEPAINT); + create_menu_item_with_mnemonic (menu, "SelectNudgeLeft", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGELEFT); + create_menu_item_with_mnemonic (menu, "SelectNudgeRight", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGERIGHT); + create_menu_item_with_mnemonic (menu, "SelectNudgeUp", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECT_NUDGEUP); + create_menu_item_with_mnemonic (menu, "NaturalizePatch", GTK_SIGNAL_FUNC (HandleCommand), ID_PATCH_NATURALIZE); + create_menu_item_with_mnemonic (menu, "SnapPatchToGrid", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECT_SNAPTOGRID); + create_menu_item_with_mnemonic (menu, "SelectAllOfType", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECT_ALL); + create_menu_item_with_mnemonic (menu, "CycleOutlineStyle", GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_OUTLINESTYLE); + create_menu_item_with_mnemonic (menu, "TextureWindowScaleup", GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTUREWINDOW_SCALEUP); + create_menu_item_with_mnemonic (menu, "TextureWindowScaledown", GTK_SIGNAL_FUNC (HandleCommand), ID_TEXTUREWINDOW_SCALEDOWN); + + g_bIgnoreCommands--; +} + +void MainFrame::create_main_toolbar (GtkWidget *window, GtkWidget *vbox) +{ + GtkWidget *handle_box, *toolbar, *w; + + handle_box = gtk_handle_box_new (); + gtk_box_pack_start (GTK_BOX (vbox), handle_box, FALSE, FALSE, 0); + gtk_widget_show (handle_box); + g_object_set_data (G_OBJECT (window), "tb_handle_box", handle_box); + + toolbar = gtk_toolbar_new (); + gtk_toolbar_set_orientation (GTK_TOOLBAR(toolbar), GTK_ORIENTATION_HORIZONTAL); + gtk_toolbar_set_style (GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS); + // gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), user_rc.toolbar_style); + gtk_container_add (GTK_CONTAINER (handle_box), toolbar); + + gtk_widget_show (toolbar); + + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "Open", "Open an existing map", "", + new_pixmap (window, "file_open.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_FILE_OPEN)); + g_object_set_data (G_OBJECT (window), "tb_file_open", w); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "Save", "Save the active map", "", + new_pixmap (window, "file_save.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_FILE_SAVE)); + g_object_set_data (G_OBJECT (window), "tb_file_save", w); + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "x-axis Flip", "", + new_pixmap (window, "brush_flipx.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_BRUSH_FLIPX)); + g_object_set_data (G_OBJECT (window), "tb_brush_flipx", w); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "x-axis Rotate", "", + new_pixmap (window, "brush_rotatex.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_BRUSH_ROTATEX)); + g_object_set_data (G_OBJECT (window), "tb_brush_rotatex", w); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "y-axis Flip", "", + new_pixmap (window, "brush_flipy.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_BRUSH_FLIPY)); + g_object_set_data (G_OBJECT (window), "tb_brush_flipy", w); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "y-axis Rotate", "", + new_pixmap (window, "brush_rotatey.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_BRUSH_ROTATEY)); + g_object_set_data (G_OBJECT (window), "tb_brush_rotatey", w); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "z-axis Flip", "", + new_pixmap (window, "brush_flipz.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_BRUSH_FLIPZ)); + g_object_set_data (G_OBJECT (window), "tb_brush_flipz", w); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "z-axis Rotate", "", + new_pixmap (window, "brush_rotatez.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_BRUSH_ROTATEZ)); + g_object_set_data (G_OBJECT (window), "tb_brush_rotatez", w); + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + + if (g_PrefsDlg.m_bWideToolbar) + { + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Complete Tall", "", + new_pixmap (window, "selection_selectcompletetall.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_SELECTION_SELECTCOMPLETETALL)); + g_object_set_data (G_OBJECT (window), "tb_selection_selectcompletetall", w); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Select Touching", "", + new_pixmap (window, "selection_selecttouching.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_SELECTION_SELECTTOUCHING)); + g_object_set_data (G_OBJECT (window), "tb_selection_selecttouching", w); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Select Partial Tall", "", + new_pixmap (window, "selection_selectpartialtall.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_SELECTION_SELECTPARTIALTALL)); + g_object_set_data (G_OBJECT (window), "tb_selection_selectpartialtall", w); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Select Inside", "", + new_pixmap (window, "selection_selectinside.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_SELECTION_SELECTINSIDE)); + g_object_set_data (G_OBJECT (window), "tb_selection_selectinside", w); + } else + { + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Selection", "", + new_pixmap (window, "popup_selection.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_POPUP_SELECTION)); + g_object_set_data (G_OBJECT (window), "tb_popup_selection", w); + } + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "CSG Subtract", "", + new_pixmap (window, "selection_csgsubtract.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SELECTION_CSGSUBTRACT)); + g_object_set_data (G_OBJECT (window), "tb_selection_csgsubtract", w); + + if (g_PrefsDlg.m_bWideToolbar) + { + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "CSG Merge", "", + new_pixmap (window, "selection_csgmerge.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SELECTION_CSGMERGE)); + g_object_set_data (G_OBJECT (window), "tb_selection_csgmerge", w); + } + + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Hollow", "", + new_pixmap (window, "selection_makehollow.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SELECTION_MAKEHOLLOW)); + g_object_set_data (G_OBJECT (window), "tb_selection_makehollow", w); + + if (g_PrefsDlg.m_bWideToolbar) + { + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Clipper", "", new_pixmap (window, "view_clipper.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_VIEW_CLIPPER)); + g_object_set_data (G_OBJECT (window), "tb_view_clipper", w); + } + + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Change views", "", + new_pixmap (window, "view_change.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_VIEW_CHANGE)); + g_object_set_data (G_OBJECT (window), "tb_view_change", w); + + if (!g_PrefsDlg.m_bWideToolbar) + { + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + } + + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Texture view mode", "", + new_pixmap (window, "textures_popup.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_TEXTURES_POPUP)); + g_object_set_data (G_OBJECT (window), "tb_textures_popup", w); + + if (g_PrefsDlg.m_bWideToolbar) + { + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Cubic clip the camera view", "", + new_pixmap (window, "view_cubicclipping.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_VIEW_CUBICCLIPPING)); + g_object_set_data (G_OBJECT (window), "tb_view_cubicclipping", w); + } + + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + + if (!g_PrefsDlg.m_bWideToolbar) + { + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Camera preview", "", new_pixmap (window, "view_cameratoggle.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_VIEW_CAMERATOGGLE)); + g_object_set_data (G_OBJECT (window), "tb_view_cameratoggle", w); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Update Camera", "", + new_pixmap (window, "view_cameraupdate.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_VIEW_CAMERAUPDATE)); + g_object_set_data (G_OBJECT (window), "tb_view_cameraupdate", w); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Cubic clip the camera view", "", + new_pixmap (window, "view_cubicclipping.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_VIEW_CUBICCLIPPING)); + g_object_set_data (G_OBJECT (window), "tb_view_cubicclipping", w); + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Entity inspector", "", new_pixmap (window, "view_entity.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_VIEW_ENTITY)); + g_object_set_data (G_OBJECT (window), "tb_view_entity", w); + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Clipper", "", new_pixmap (window, "view_clipper.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_VIEW_CLIPPER)); + g_object_set_data (G_OBJECT (window), "tb_view_clipper", w); + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + } + + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Free Rotation", "", new_pixmap (window, "select_mouserotate.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SELECT_MOUSEROTATE)); + g_object_set_data (G_OBJECT (window), "tb_select_mouserotate", w); + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Free Scaling", "", new_pixmap (window, "select_mousescale.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SELECT_MOUSESCALE)); + g_object_set_data (G_OBJECT (window), "tb_select_mousescale", w); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Scale X", "", new_pixmap (window, "scalelockx.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SCALELOCKX)); + g_object_set_data (G_OBJECT (window), "tb_scalelockx", w); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Scale Y", "", new_pixmap (window, "scalelocky.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SCALELOCKY)); + g_object_set_data (G_OBJECT (window), "tb_scalelocky", w); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Scale Z", "", new_pixmap (window, "scalelockz.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_SCALELOCKZ)); + g_object_set_data (G_OBJECT (window), "tb_scalelockz", w); + + if (g_PrefsDlg.m_bWideToolbar) + { + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Don't select model brushes", "", + new_pixmap (window, "dontselectmodel.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_DONTSELECTMODEL)); + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + g_object_set_data (G_OBJECT (window), "tb_dontselectmodel", w); + + if (!g_pGameDescription->mNoPatch) + { + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Don't select curved brushes", "", + new_pixmap (window, "dontselectcurve.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_DONTSELECTCURVE)); + g_object_set_data (G_OBJECT (window), "tb_dontselectcurve", w); + } + } + + // bug #292, patch toolbar option + if (g_PrefsDlg.m_bPatchToolbar) + { + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Show patch bounding box", "", + new_pixmap (window, "patch_showboundingbox.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_PATCH_SHOWBOUNDINGBOX)); + g_object_set_data (G_OBJECT (window), "tb_patch_showboundingbox", w); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Show patches as wireframes", "", + new_pixmap (window, "patch_wireframe.bmp"), + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (ID_PATCH_WIREFRAME)); + g_object_set_data (G_OBJECT (window), "tb_patch_wireframe", w); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Patch Bend mode", "", + new_pixmap (window, "patch_bend.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_PATCH_BEND)); + g_object_set_data (G_OBJECT (window), "tb_patch_bend", w); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Put caps on the current patch", "", + new_pixmap (window, "curve_cap.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_CURVE_CAP)); + g_object_set_data (G_OBJECT (window), "tb_curve_cap", w); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Welds equal patch points during moves", "", + new_pixmap (window, "patch_weld.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_PATCH_WELD)); + g_object_set_data (G_OBJECT (window), "tb_patch_weld", w); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, + "", "Selects drill down rows and columns", "", + new_pixmap (window, "patch_drilldown.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_PATCH_DRILLDOWN)); + g_object_set_data (G_OBJECT (window), "tb_patch_drilldown", w); + } + + if (g_PrefsDlg.m_bWideToolbar) + { + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + w = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), "", "Show Entities as", "", + new_pixmap (window, "show_entities.bmp"), GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ID_SHOW_ENTITIES)); + g_object_set_data (G_OBJECT (window), "tb_show_entities", w); + } + + /* + uh? that is OLD +#ifndef QUAKE3 + w = g_object_get_data (G_OBJECT (window), "tb_dontselectcurve"); + gtk_widget_hide (w); + w = g_object_get_data (G_OBJECT (window), "tb_patch_showboundingbox"); + gtk_widget_hide (w); + w = g_object_get_data (G_OBJECT (window), "tb_patch_weld"); + gtk_widget_hide (w); + w = g_object_get_data (G_OBJECT (window), "tb_patch_wireframe"); + gtk_widget_hide (w); +#endif + */ + + m_bCamPreview = true; + g_nScaleHow = (SCALE_X | SCALE_Y | SCALE_Z); +} + +void MainFrame::create_plugin_toolbar (GtkWidget *window, GtkWidget *vbox) +{ + GtkWidget *handle_box, *toolbar; + + handle_box = gtk_handle_box_new (); + gtk_box_pack_start (GTK_BOX (vbox), handle_box, FALSE, FALSE, 0); + if (g_PrefsDlg.m_bPluginToolbar) + gtk_widget_show (handle_box); + g_object_set_data (G_OBJECT (window), "tb_handle_box", handle_box); + + toolbar = gtk_toolbar_new(); + gtk_toolbar_set_orientation (GTK_TOOLBAR(toolbar), GTK_ORIENTATION_HORIZONTAL); + gtk_toolbar_set_style (GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS); + // gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), user_rc.toolbar_style); + gtk_container_add (GTK_CONTAINER (handle_box), toolbar); + g_object_set_data (G_OBJECT (window), "toolbar_plugin", toolbar); + gtk_widget_show (toolbar); +} + +void MainFrame::create_main_statusbar (GtkWidget *window, GtkWidget *vbox) +{ + GtkWidget *hbox, *hbox1; + GtkWidget *frame; + GtkWidget *label; + + hbox = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox); + gtk_widget_set_usize (hbox, -1, 24); + gtk_container_border_width (GTK_CONTAINER (hbox), 1); + gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, TRUE, 2); + + frame = gtk_frame_new ((char*)NULL); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + + hbox1 = gtk_hbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (frame), hbox1); + gtk_container_border_width (GTK_CONTAINER (hbox1), 0); + gtk_widget_show (hbox1); + + label = gtk_label_new (" Label "); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox1), label, FALSE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_padding (GTK_MISC (label), 3, 0); + m_pStatusLabel[0] = label; + + for (int i = 1; i < 6; i++) + { + frame = gtk_frame_new ((char*)NULL); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + + label = gtk_label_new (" Label "); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (frame), label); + m_pStatusLabel[i] = label; + } +} + +guint s_idle_id; +static gint mainframe_idle (gpointer user_data) +{ + g_pParentWnd->RoutineProcessing (); + return TRUE; +} + +static void Sys_Iconify (GtkWidget *w); +static void Sys_Restore (GtkWidget *w); + +inline void CHECK_RESTORE(GtkWidget* w) +{ + if (g_object_get_data (G_OBJECT (w), "was_mapped") != NULL) + gtk_widget_show (w); +} + + +// this is called when the window is restored from the iconified state +static void mainframe_map (GtkWidget *widget) +{ + if (g_pParentWnd->IsSleeping ()) + g_pParentWnd->OnSleep (); + + if ((g_pParentWnd->CurrentStyle() == MainFrame::eFloating) && (widget == g_pParentWnd->m_pWidget)) + { + // restore previously visible windows + CHECK_RESTORE (g_pParentWnd->GetCamWnd ()->m_pParent); + if (g_PrefsDlg.m_bFloatingZ) + CHECK_RESTORE (g_pParentWnd->GetZWnd ()->m_pParent); + CHECK_RESTORE (g_pParentWnd->GetXYWnd ()->m_pParent); + CHECK_RESTORE (g_pParentWnd->GetXZWnd ()->m_pParent); + CHECK_RESTORE (g_pParentWnd->GetYZWnd ()->m_pParent); + CHECK_RESTORE (g_pGroupDlg->m_pWidget); + } +} + +inline void CHECK_MINIMIZE(GtkWidget* w) +{ + g_object_set_data (G_OBJECT (w), "was_mapped", (void*)(GTK_WIDGET_VISIBLE (w) != 0)); + gtk_widget_hide (w); +} + +static void mainframe_unmap (GtkWidget *widget) +{ + + if ((g_pParentWnd->CurrentStyle() == MainFrame::eFloating) && (widget == g_pParentWnd->m_pWidget)) + { + // minimize all other windows when the main window is minimized + CHECK_MINIMIZE (g_pParentWnd->GetCamWnd ()->m_pParent); + if (g_PrefsDlg.m_bFloatingZ) + CHECK_MINIMIZE (g_pParentWnd->GetZWnd ()->m_pParent); + CHECK_MINIMIZE (g_pParentWnd->GetXYWnd ()->m_pParent); + CHECK_MINIMIZE (g_pParentWnd->GetXZWnd ()->m_pParent); + CHECK_MINIMIZE (g_pParentWnd->GetYZWnd ()->m_pParent); + CHECK_MINIMIZE (g_pGroupDlg->m_pWidget); + } +} + +static GtkWidget* create_floating (MainFrame* mainframe) +{ + GtkWidget *wnd = gtk_window_new (GTK_WINDOW_TOPLEVEL); + //if (mainframe->CurrentStyle() != MainFrame::eFloating) + gtk_window_set_transient_for (GTK_WINDOW (wnd), GTK_WINDOW (mainframe->m_pWidget)); + gtk_widget_set_events (wnd, GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK); + gtk_signal_connect (GTK_OBJECT (wnd), "delete_event", GTK_SIGNAL_FUNC (widget_delete_hide), NULL); + gtk_signal_connect (GTK_OBJECT (wnd), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_signal_connect (GTK_OBJECT (wnd), "key_press_event", + GTK_SIGNAL_FUNC (mainframe_keypress), mainframe); + gtk_signal_connect (GTK_OBJECT (wnd), "key_release_event", + GTK_SIGNAL_FUNC (mainframe_keyrelease), mainframe); + gtk_signal_connect (GTK_OBJECT (wnd), "map_event", + GTK_SIGNAL_FUNC (mainframe_map), mainframe); + + gtk_window_set_default_size (GTK_WINDOW (wnd), 100, 100); + +#ifdef DBG_WINDOWPOS + Sys_Printf("create_floating: %p, gtk_window_set_default_size 100, 100\n", wnd); +#endif + + return wnd; +} + +void console_populate_popup(GtkTextView* textview, GtkMenu* menu, gpointer user_data) +{ + menu_separator(GTK_WIDGET(menu)); + + GtkWidget* item = gtk_menu_item_new_with_label ("Clear"); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (Sys_ClearPrintf), NULL); + gtk_widget_show (item); + gtk_menu_append (GTK_MENU (menu), item); +} + +void console_construct(GtkWidget* textview) +{ + g_signal_connect(G_OBJECT(textview), "populate-popup", G_CALLBACK(console_populate_popup), NULL); +} + +extern MemStream g_Clipboard; + +void Clipboard_CopyMap() +{ + g_Clipboard.SetLength(0); + Map_Export (&g_Clipboard, "xmap", false, true); +} + +void Clipboard_PasteMap() +{ + if (g_Clipboard.GetLength() > 0) + { + g_Clipboard.Seek(0, SEEK_SET); + Map_Import(&g_Clipboard, "xmap", true); + } +} + +/*! +Platform-independent GTK clipboard support. +\todo Using GDK_SELECTION_CLIPBOARD fails on win32, so we use the win32 API directly for now. +*/ +#if defined (__linux__) || defined (__APPLE__) + +enum +{ + RADIANT_CLIPPINGS = 23, +}; + +static const GtkTargetEntry clipboard_targets[] = { + { "RADIANT_CLIPPINGS", 0, RADIANT_CLIPPINGS, }, +}; + +static void clipboard_get (GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, gpointer user_data_or_owner) +{ + guchar *buffer; + gint len; + GdkAtom type = GDK_NONE; + + len = g_Clipboard.GetLength(); + + if (!len) + { + buffer = NULL; + } else + { + buffer = g_Clipboard.GetBuffer (); + } + + if(info == clipboard_targets[0].info) + { + type = gdk_atom_intern(clipboard_targets[0].target, FALSE); + } + + gtk_selection_data_set (selection_data, type, 8, buffer, len); +} + +static void clipboard_clear (GtkClipboard *clipboard, gpointer user_data_or_owner) +{ +} + +static void clipboard_received (GtkClipboard *clipboard, GtkSelectionData *data, gpointer user_data) +{ + g_Clipboard.SetLength (0); + + if (data->length < 0) + Sys_FPrintf(SYS_ERR, "Error retrieving selection\n"); + else if(strcmp(gdk_atom_name(data->type), clipboard_targets[0].target) == 0) + g_Clipboard.Write (data->data, data->length); + + Clipboard_PasteMap(); +} + +void clipboard_copy() +{ + Clipboard_CopyMap(); + + GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); + + gtk_clipboard_set_with_data (clipboard, clipboard_targets, 1, clipboard_get, clipboard_clear, NULL); +} + +void clipboard_paste() +{ + GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); + + gtk_clipboard_request_contents (clipboard, gdk_atom_intern(clipboard_targets[0].target, FALSE), clipboard_received, NULL); +} + + +#elif defined(WIN32) + +void clipboard_copy() +{ + Clipboard_CopyMap(); + + bool bClipped = false; + UINT nClipboard = ::RegisterClipboardFormat("RadiantClippings"); + if (nClipboard > 0) + { + if (::OpenClipboard(NULL)) + { + EmptyClipboard(); + long lSize = g_Clipboard.GetLength(); + HANDLE h = ::GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, lSize + sizeof(long)); + if (h != NULL) + { + unsigned char *cp = reinterpret_cast(::GlobalLock(h)); + memcpy(cp, &lSize, sizeof(long)); + cp += sizeof(long); + g_Clipboard.Seek(0, SEEK_SET); + g_Clipboard.Read(cp, lSize); + ::GlobalUnlock(h); + ::SetClipboardData(nClipboard, h); + ::CloseClipboard(); + bClipped = true; + } + } + } + + if (!bClipped) + { + Sys_Printf("Unable to register Windows clipboard formats, copy/paste between editors will not be possible\n"); + } +} + +void clipboard_paste() +{ + bool bPasted = false; + UINT nClipboard = ::RegisterClipboardFormat("RadiantClippings"); + if (nClipboard > 0 && ::OpenClipboard(NULL)) + { + if(IsClipboardFormatAvailable(nClipboard)) + { + HANDLE h = ::GetClipboardData(nClipboard); + if (h) + { + g_Clipboard.SetLength(0); + unsigned char *cp = reinterpret_cast(::GlobalLock(h)); + long lSize = 0; + memcpy(&lSize, cp, sizeof(long)); + cp += sizeof(long); + g_Clipboard.Write(cp, lSize); + ::GlobalUnlock(h); + } + } + ::CloseClipboard(); + } + + Clipboard_PasteMap(); +} + +#endif + +void MainFrame::Copy() +{ + clipboard_copy(); +} + +void MainFrame::Paste() +{ + clipboard_paste(); + UpdateSurfaceDialog(); +} + + +#ifdef DBG_WINDOWPOS +GtkWidget *watchit = NULL; + +void CheckWatchit(char *msg) +{ + static int width = 0; + if ((watchit!=NULL) && (watchit->allocation.width != width)) + { + Sys_Printf("CheckWatchit %s: %d\n", msg, watchit->allocation.width); + width = watchit->allocation.width; + } +} +#endif + +#ifdef _WIN32 +BOOL CALLBACK m_pCountMonitor (HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) +{ + int *n = (int *) dwData; + + (*n)++; + + return TRUE; +} + +struct monitorInfo_s { + GdkRectangle *win_monitors; + int i_win_mon; +}; + +BOOL CALLBACK m_pEnumMonitor (HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) +{ + monitorInfo_s *monitorInfo = (monitorInfo_s *) dwData; + GdkRectangle *monitor; + MONITORINFOEX lpmi; + + monitor = monitorInfo->win_monitors + monitorInfo->i_win_mon; + + memset(&lpmi, 0, sizeof(MONITORINFOEX)); + lpmi.cbSize = sizeof(MONITORINFOEX); + + GetMonitorInfo( hMonitor, &lpmi ); + + if( lpmi.dwFlags & MONITORINFOF_PRIMARY ) { + RECT rect; + + SystemParametersInfo (SPI_GETWORKAREA, 0, &rect, 0); + monitor->x = rect.left; + monitor->y = rect.top; + monitor->width = rect.right - rect.left; + monitor->height = rect.bottom - rect.top; + + if (monitorInfo->i_win_mon != 0) + { + GdkRectangle temp = *monitor; + *monitor = monitorInfo->win_monitors[0]; + monitorInfo->win_monitors[0] = temp; + } + } else { + monitor->x = lpmi.rcMonitor.left; + monitor->y = lpmi.rcMonitor.top; + monitor->width = lpmi.rcMonitor.right - lpmi.rcMonitor.left; + monitor->height = lpmi.rcMonitor.bottom - lpmi.rcMonitor.top; + } + + monitorInfo->i_win_mon++; + + return TRUE; +} + +void PositionWindowOnPrimaryScreen(window_position_t& position) +{ + const GdkRectangle primaryMonitorRect = g_pParentWnd->GetPrimaryMonitorRect(); + + if( position.x <= primaryMonitorRect.x + 6 ) + position.x = primaryMonitorRect.x + 6; + else if( position.x >= ( primaryMonitorRect.x + primaryMonitorRect.width ) - 6 ) + position.x = primaryMonitorRect.x + 6; + + if( position.y <= primaryMonitorRect.y + 6 ) + position.y = primaryMonitorRect.y + 6; + else if( position.y >= ( primaryMonitorRect.y + primaryMonitorRect.height ) - 6 ) + position.y = primaryMonitorRect.y + 6; + + if( position.x + position.w >= ( primaryMonitorRect.x + primaryMonitorRect.width ) - 18 ) + position.w = primaryMonitorRect.width - 18; + if( position.y + position.h >= ( primaryMonitorRect.y + primaryMonitorRect.height ) - 18 ) + position.h = primaryMonitorRect.height - 18; +} +#endif + +GtkWidget* create_framed_widget(GtkWidget* widget) +{ + GtkWidget* frame = gtk_frame_new ((char*)NULL); + gtk_widget_show (frame); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + gtk_container_add (GTK_CONTAINER (frame), widget); + gtk_widget_show(widget); + return frame; +} + +gboolean entry_focus_in(GtkWidget *widget, GdkEventFocus *event, gpointer user_data) +{ + gtk_window_remove_accel_group (GTK_WINDOW (g_pParentWnd->m_pWidget), global_accel); + return FALSE; +} + +gboolean entry_focus_out(GtkWidget *widget, GdkEventFocus *event, gpointer user_data) +{ + gtk_window_add_accel_group (GTK_WINDOW (g_pParentWnd->m_pWidget), global_accel); + return FALSE; +} + +GtkWidget* create_framed_texwnd(TexWnd* texwnd) +{ + GtkWidget* frame = gtk_frame_new ((char*)NULL); + gtk_widget_show (frame); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + + GtkWidget* hbox = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (frame), hbox); + + GtkWidget* w = gtk_vscrollbar_new (GTK_ADJUSTMENT (gtk_adjustment_new (0,0,0,1,1,1))); + gtk_widget_show (w); + gtk_box_pack_end (GTK_BOX (hbox), w, FALSE, TRUE, 0); + g_qeglobals_gui.d_texture_scroll = w; + + GtkWidget* texbox = gtk_vbox_new (FALSE, 0); + gtk_widget_show (texbox); + gtk_box_pack_start (GTK_BOX (hbox), texbox, TRUE, TRUE, 0); + + w = gtk_entry_new (); + gtk_box_pack_start (GTK_BOX (texbox), w, FALSE, FALSE, 0); + texwnd->m_pFilter = w; + g_signal_connect(G_OBJECT(w), "focus_in_event", G_CALLBACK(entry_focus_in), NULL); + g_signal_connect(G_OBJECT(w), "focus_out_event", G_CALLBACK(entry_focus_out), NULL); + + w = texwnd->GetWidget (); + gtk_box_pack_start (GTK_BOX (texbox), w, TRUE, TRUE, 0); + gtk_widget_show (w); + + return frame; +} + +static ZWnd *create_floating_zwnd(MainFrame *mainframe) +{ + ZWnd *pZWnd = new ZWnd (); + GtkWidget* wnd = create_floating (mainframe); + + gtk_window_set_title (GTK_WINDOW (wnd), "Z"); + + pZWnd->m_pParent = wnd; + + { + GtkWidget* frame = create_framed_widget(pZWnd->GetWidget()); + gtk_container_add (GTK_CONTAINER (wnd), frame); + } + + gtk_widget_realize (wnd); + + // turn OFF minimize and maximize boxes. + // Must be *after* realize, or wnd->window is NULL + // should do the right thing on *nix, need to verify. + gdk_window_set_decorations ( wnd->window, + GdkWMDecoration(GDK_DECOR_ALL | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE ) ); + //TODO 50 by observation, will vary depending on decoration sizes + { + GdkGeometry geometry; + geometry.min_width = 50; + //we only care about width, but have to set this too, or get nasty bugs + geometry.min_height = 10; + gdk_window_set_geometry_hints( wnd->window,&geometry,GDK_HINT_MIN_SIZE); + } + +#ifdef _WIN32 + if( g_PrefsDlg.m_bStartOnPrimMon ) { + PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.posZWnd ); + } +#endif + load_window_pos (wnd, g_PrefsDlg.mWindowInfo.posZWnd); + + if (g_PrefsDlg.m_bZVis) + gtk_widget_show (wnd); + + return pZWnd; +} + +static const int gutter = 12; + +void MainFrame::Create () +{ + GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + m_pWidget = window; + gtk_widget_set_events (window, GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + GTK_SIGNAL_FUNC (mainframe_delete), this); + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (mainframe_destroy), this); + gtk_signal_connect (GTK_OBJECT (window), "key_press_event", + GTK_SIGNAL_FUNC (mainframe_keypress), this); + gtk_signal_connect (GTK_OBJECT (window), "key_release_event", + GTK_SIGNAL_FUNC (mainframe_keyrelease), this); + gtk_signal_connect (GTK_OBJECT (window), "map_event", + GTK_SIGNAL_FUNC (mainframe_map), this); + gtk_signal_connect (GTK_OBJECT (window), "unmap_event", + GTK_SIGNAL_FUNC (mainframe_unmap), this); + + g_qeglobals_gui.d_main_window = window; + +#ifdef _WIN32 + // calculate gdk offset + int n_win_monitors = 0; + + monitorInfo_s monitorInfo; + + // detect multiple monitors + EnumDisplayMonitors (NULL, NULL, m_pCountMonitor, reinterpret_cast(&n_win_monitors)); + + monitorInfo.win_monitors = new GdkRectangle [ n_win_monitors ]; + monitorInfo.i_win_mon = 0; + EnumDisplayMonitors (NULL, NULL, m_pEnumMonitor, reinterpret_cast(&monitorInfo)); + + gdk_offset_x = G_MININT; + gdk_offset_y = G_MININT; + + // calculate offset + for( monitorInfo.i_win_mon = 0; monitorInfo.i_win_mon < n_win_monitors; monitorInfo.i_win_mon++ ) { + gdk_offset_x = MAX (gdk_offset_x, -monitorInfo.win_monitors[monitorInfo.i_win_mon].x); + gdk_offset_y = MAX (gdk_offset_y, -monitorInfo.win_monitors[monitorInfo.i_win_mon].y); + } + + Sys_Printf( "GDK's coordinate system is offset by %d over the x-axis and %d over the y-axis from Windows' coordinate system.\n", gdk_offset_x, gdk_offset_y ); + + if( g_PrefsDlg.m_bStartOnPrimMon ) + { + // get gdk monitors + GdkDisplay *display; + GdkScreen *screen; + gint n_gdk_monitors = 0; + gint i_mon; + GdkRectangle rect; + + // detect multiple monitors + display = gdk_display_get_default (); + Sys_Printf( "GDK detects that server %s manages %d screens\n", gdk_display_get_name (display), gdk_display_get_n_screens (display) ); + + screen = gdk_display_get_screen( display, 1 ); + n_gdk_monitors = gdk_screen_get_n_monitors( screen ); + + Sys_Printf( "GDK detects that screen 1 has %d monitors\n", n_gdk_monitors ); + + for( i_mon = 0; i_mon < n_gdk_monitors; i_mon++ ) { + memset( &rect, 0, sizeof(rect) ); + gdk_screen_get_monitor_geometry( screen, i_mon, &rect ); + Sys_Printf( " monitor %d: x: %d y: %d w: %d h: %d\n", i_mon, rect.x, rect.y, rect.width, rect.height ); + + if( i_mon == 0 ) { + memcpy( &primaryMonitorRect, &rect, sizeof(primaryMonitorRect) ); + } + } + + PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.position ); + } + else { + primaryMonitorRect.x = primaryMonitorRect.y = 0; + primaryMonitorRect.width = gdk_screen_width (); + primaryMonitorRect.height = gdk_screen_height (); + } + +#endif + + load_window_pos(window, g_PrefsDlg.mWindowInfo.position); + + GtkWidget* vbox = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + create_main_menu (window, vbox); + MRU_Load (); + create_main_toolbar (window, vbox); + create_plugin_toolbar (window,vbox); + + m_nCurrentStyle = g_PrefsDlg.m_nView; + + g_pGroupDlg->Create (); + OnPluginsRefresh(); + + CreateQEChildren(); + + gtk_widget_show (window); + + // not needed on win32, it's in the .rc +#ifndef _WIN32 + { + GdkPixmap *pixmap; + GdkBitmap *mask; + load_pixmap ("icon.bmp", window, &pixmap, &mask); + gdk_window_set_icon (window->window, NULL, pixmap, mask); + } +#endif + + if (CurrentStyle() == eRegular || CurrentStyle() == eRegularLeft) + { + { + GtkWidget* vsplit = gtk_vpaned_new (); + m_pSplits[0] = vsplit; + gtk_box_pack_start (GTK_BOX (vbox), vsplit, TRUE, TRUE, 0); + gtk_widget_show (vsplit); + + { + GtkWidget* hsplit = gtk_hpaned_new (); + m_pSplits[2] = hsplit; + gtk_paned_add1 (GTK_PANED (vsplit), hsplit); + gtk_widget_show (hsplit); + + { + GtkWidget* hsplit2 = gtk_hpaned_new (); + m_pSplits[3] = hsplit2; + gtk_paned_add2 (GTK_PANED (hsplit), hsplit2); + gtk_widget_show (hsplit2); + + { + GtkWidget* vsplit2 = gtk_vpaned_new (); + m_pSplits[1] = vsplit2; + if (CurrentStyle() == eRegular) + gtk_paned_add2 (GTK_PANED (hsplit2), vsplit2); + else + gtk_paned_add1 (GTK_PANED (hsplit), vsplit2); + gtk_widget_show (vsplit2); + + // camera + m_pCamWnd = new CamWnd (); + { + GtkWidget* frame = create_framed_widget(m_pCamWnd->GetWidget()); + gtk_paned_add1 (GTK_PANED (vsplit2), frame); + } + + // xy + m_pXYWnd = new XYWnd (); + m_pXYWnd->SetViewType(XY); + { + GtkWidget* frame = create_framed_widget(m_pXYWnd->GetWidget ()); + gtk_paned_add1 (GTK_PANED (hsplit2), frame); + } + + // z + m_pZWnd = new ZWnd (); + { + GtkWidget* frame = create_framed_widget(m_pZWnd->GetWidget ()); + if (CurrentStyle() == eRegular) + gtk_paned_add1 (GTK_PANED (hsplit), frame); + else + gtk_paned_add2 (GTK_PANED (hsplit2), frame); + } + + // textures + m_pTexWnd = new TexWnd (); + { + GtkWidget* frame = create_framed_texwnd(m_pTexWnd); + gtk_paned_add2 (GTK_PANED (vsplit2), frame); + } + + // console + { + GtkWidget* scr = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN); + gtk_widget_show (scr); + gtk_paned_pack2 (GTK_PANED (vsplit), scr, FALSE, TRUE); + + { + GtkWidget* text = gtk_text_view_new (); + gtk_widget_set_size_request(text, 0, -1); // allow shrinking + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD); + gtk_text_view_set_editable (GTK_TEXT_VIEW(text), FALSE); + gtk_container_add (GTK_CONTAINER (scr), text); + gtk_widget_show (text); + g_qeglobals_gui.d_edit = text; + } + } + } + } + } + } + + gtk_paned_set_position (GTK_PANED (m_pSplits[0]), g_PrefsDlg.mWindowInfo.nXYHeight+28); + + if (CurrentStyle() == eRegular) + { + gtk_paned_set_position (GTK_PANED (m_pSplits[2]), g_PrefsDlg.mWindowInfo.nZWidth); + gtk_paned_set_position (GTK_PANED (m_pSplits[3]), g_PrefsDlg.mWindowInfo.nXYWidth); + } + else + { + gtk_paned_set_position (GTK_PANED (m_pSplits[2]), g_PrefsDlg.mWindowInfo.nCamWidth); + while (gtk_events_pending ()) gtk_main_iteration (); + gtk_paned_set_position (GTK_PANED (m_pSplits[3]), g_PrefsDlg.mWindowInfo.nXYWidth); + } + + while (gtk_events_pending ()) gtk_main_iteration (); + + gtk_paned_set_position (GTK_PANED (m_pSplits[1]), g_PrefsDlg.mWindowInfo.nCamHeight); + } + else if (CurrentStyle() == eFloating) + { + { + GtkWidget* wnd = create_floating (this); + gtk_window_set_title (GTK_WINDOW (wnd), "Camera"); + +#ifdef _WIN32 + if( g_PrefsDlg.m_bStartOnPrimMon ) { + PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.posCamWnd ); + } +#endif + load_window_pos (wnd, g_PrefsDlg.mWindowInfo.posCamWnd); + + gtk_widget_show (wnd); + + m_pCamWnd = new CamWnd (); + + { + GtkWidget* frame = create_framed_widget(m_pCamWnd->GetWidget ()); + gtk_container_add (GTK_CONTAINER (wnd), frame); + } + + m_pCamWnd->m_pParent = wnd; + } + + if (g_PrefsDlg.m_bFloatingZ) + { + m_pZWnd = create_floating_zwnd(this); + + { + GtkWidget* wnd = create_floating (this); + gtk_window_set_title (GTK_WINDOW (wnd), "XY View"); + +#ifdef _WIN32 + if( g_PrefsDlg.m_bStartOnPrimMon ) { + PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.posXYWnd ); + } +#endif + load_window_pos (wnd, g_PrefsDlg.mWindowInfo.posXYWnd); + + m_pXYWnd = new XYWnd (); + m_pXYWnd->SetViewType(XY); + + { + GtkWidget* frame = create_framed_widget(m_pXYWnd->GetWidget()); + gtk_container_add (GTK_CONTAINER (wnd), frame); + } + + m_pXYWnd->m_pParent = wnd; + + gtk_widget_show (wnd); + } + } + else + { + GtkWidget* wnd = create_floating (this); + gtk_window_set_title (GTK_WINDOW (wnd), "XY View"); + +#ifdef _WIN32 + if( g_PrefsDlg.m_bStartOnPrimMon ) { + PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.posXYWnd ); + } +#endif + load_window_pos (wnd, g_PrefsDlg.mWindowInfo.posXYWnd); + + m_pZWnd = new ZWnd (); + m_pZWnd->m_pParent = wnd; + + m_pXYWnd = new XYWnd (); + m_pXYWnd->SetViewType(XY); + m_pXYWnd->m_pParent = wnd; + + + { + GtkWidget* hsplit = gtk_hpaned_new (); + m_pSplits[0] = hsplit; + gtk_container_add (GTK_CONTAINER (wnd), hsplit); + gtk_widget_show (hsplit); + + { + GtkWidget* frame = create_framed_widget(m_pZWnd->GetWidget()); + gtk_paned_add1 (GTK_PANED (hsplit), frame); + } + { + GtkWidget* frame = create_framed_widget(m_pXYWnd->GetWidget()); + gtk_paned_add2 (GTK_PANED (hsplit), frame); + } + } + + gtk_widget_show (wnd); + + gtk_paned_set_position (GTK_PANED (m_pSplits[0]), g_PrefsDlg.mWindowInfo.nZFloatWidth); + } + + { + GtkWidget* wnd = create_floating (this); + gtk_window_set_title (GTK_WINDOW (wnd), "XZ View"); + +#ifdef _WIN32 + if( g_PrefsDlg.m_bStartOnPrimMon ) { + PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.posXZWnd ); + } +#endif + load_window_pos (wnd, g_PrefsDlg.mWindowInfo.posXZWnd); + + m_pXZWnd = new XYWnd (); + m_pXZWnd->m_pParent = wnd; + m_pXZWnd->SetViewType(XZ); + + { + GtkWidget* frame = create_framed_widget(m_pXZWnd->GetWidget()); + gtk_container_add (GTK_CONTAINER (wnd), frame); + } + + if (g_PrefsDlg.m_bXZVis) + gtk_widget_show (wnd); + } + + { + GtkWidget* wnd = create_floating (this); + gtk_window_set_title (GTK_WINDOW (wnd), "YZ View"); + +#ifdef _WIN32 + if( g_PrefsDlg.m_bStartOnPrimMon ) { + PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.posYZWnd ); + } +#endif + load_window_pos (wnd, g_PrefsDlg.mWindowInfo.posYZWnd); + + m_pYZWnd = new XYWnd (); + m_pYZWnd->m_pParent = wnd; + m_pYZWnd->SetViewType(YZ); + + { + GtkWidget* frame = create_framed_widget(m_pYZWnd->GetWidget()); + gtk_container_add (GTK_CONTAINER (wnd), frame); + } + + if (g_PrefsDlg.m_bYZVis) + gtk_widget_show (wnd); + } + + m_pTexWnd = new TexWnd (); + { + GtkWidget* frame = create_framed_texwnd(m_pTexWnd); + m_pTexWnd->m_pParent = g_pGroupDlg->m_pWidget; + + { + GtkWidget* w = gtk_label_new ("Textures"); + gtk_widget_show (w); + gtk_notebook_insert_page (GTK_NOTEBOOK (g_pGroupDlg->m_pNotebook), frame, w, 1); + } + } + + g_pGroupDlg->Show (); + } + else // 4 way + { + { + GtkWidget* hsplit = gtk_hpaned_new (); + m_pSplits[0] = hsplit; + gtk_box_pack_start (GTK_BOX (vbox), hsplit, TRUE, TRUE, 0); + gtk_widget_show (hsplit); + + { + GtkWidget* vsplit1 = gtk_vpaned_new (); + m_pSplits[1] = vsplit1; + gtk_paned_add1 (GTK_PANED (hsplit), vsplit1); + gtk_widget_show (vsplit1); + + { + GtkWidget* vsplit2 = gtk_vpaned_new (); + m_pSplits[2] = vsplit2; + gtk_paned_add2 (GTK_PANED (hsplit), vsplit2); + gtk_widget_show (vsplit2); + + m_pCamWnd = new CamWnd (); + { + GtkWidget* frame = create_framed_widget(m_pCamWnd->GetWidget()); + gtk_paned_add1 (GTK_PANED (vsplit1), frame); + } + + m_pXYWnd = new XYWnd (); + m_pXYWnd->SetViewType(XY); + { + GtkWidget* frame = create_framed_widget(m_pXYWnd->GetWidget()); + gtk_paned_add1 (GTK_PANED (vsplit2), frame); + } + + m_pYZWnd = new XYWnd (); + m_pYZWnd->SetViewType(YZ); + { + GtkWidget* frame = create_framed_widget(m_pYZWnd->GetWidget()); + gtk_paned_add2 (GTK_PANED (vsplit1), frame); + } + + m_pXZWnd = new XYWnd (); + m_pXZWnd->SetViewType(XZ); + { + GtkWidget* frame = create_framed_widget(m_pXZWnd->GetWidget()); + gtk_paned_add2 (GTK_PANED (vsplit2), frame); + } + } + } + } + + // g_qeglobals_gui.d_edit = NULL; + + { + m_pTexWnd = new TexWnd (); + GtkWidget* frame = create_framed_texwnd(m_pTexWnd); + + { + GtkWidget* w = gtk_label_new ("Textures"); + gtk_widget_show (w); + gtk_notebook_insert_page (GTK_NOTEBOOK (g_pGroupDlg->m_pNotebook), frame, w, 1); + } + } + + m_pTexWnd->m_pParent = g_pGroupDlg->m_pWidget; +// gtk_widget_realize (m_pTexWnd->GetWidget ()); + m_pZWnd = create_floating_zwnd(this); + + while (gtk_events_pending ()) + gtk_main_iteration (); + + { + int x = GTK_PANED (m_pSplits[0])->max_position/2 - gutter; + gtk_paned_set_position (GTK_PANED (m_pSplits[0]), x); + } + + { + int y = GTK_PANED (m_pSplits[1])->max_position/2 - gutter; + gtk_paned_set_position (GTK_PANED (m_pSplits[1]), y); + gtk_paned_set_position (GTK_PANED (m_pSplits[2]), y); + } + } + + if(g_PrefsDlg.mWindowInfo.nState & GDK_WINDOW_STATE_MAXIMIZED) + gtk_window_maximize(GTK_WINDOW(window)); + + gtk_widget_show (window); + + Texture_Init(); + + if (m_pXYWnd) // this is always true? + { + m_pXYWnd->SetActive(true); + } + m_bSplittersOK = true; + Texture_SetMode(g_qeglobals.d_savedinfo.iTexMenu); + + g_pParentWnd->OnEntitiesSetViewAs(0); + +// m_wndTextureBar.Create (vbox); + create_main_statusbar (window, vbox); + + LoadCommandMap(); + ShowMenuItemKeyBindings(window); + + if (g_qeglobals_gui.d_edit != NULL) + console_construct(g_qeglobals_gui.d_edit); + + // bool load_last = FALSE; + + SetGridStatus(); + SetButtonMenuStates(); + + // m_bShowShader and m_bTextureShaderlistOnly have a menu checkbox, update it now + GtkWidget *item; + g_bIgnoreCommands++; + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_shaders_show")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bShowShaders ? TRUE : FALSE); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_shaderlistonly")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bTexturesShaderlistOnly ? TRUE : FALSE); + g_bIgnoreCommands--; + +// if (g_PrefsDlg.m_bTextureBar) +// gtk_widget_show (m_wndTextureBar.m_pWidget); + + SetActiveXY(m_pXYWnd); + + s_idle_id = gtk_timeout_add (25, mainframe_idle, this); + + QGL_InitExtensions (); + + if (g_PrefsDlg.mLocalPrefs.mbEmpty) + { + g_PrefsDlg.mLocalPrefs.mbEmpty = false; + g_PrefsDlg.SavePrefs(); + } + + // remove the pid file + remove (g_pidGameFile.GetBuffer ()); + + Sys_Printf ("Entering message loop\n"); + + m_bDoLoop = true; + + m_nTimer = gtk_timeout_add (1000, timer, this); +} + +// ============================================================================= +// MainFrame class + +MainFrame::MainFrame() +{ + m_bDoLoop = false; + m_bSplittersOK = false; + g_pParentWnd = this; + m_pXYWnd = (XYWnd*)NULL; + m_pCamWnd = NULL; + m_pTexWnd = (TexWnd*)NULL; + m_pZWnd = (ZWnd*)NULL; + m_pYZWnd = (XYWnd*)NULL; + m_pXZWnd = (XYWnd*)NULL; + m_pActiveXY = (XYWnd*)NULL; + m_bCamPreview = true; + m_pWatchBSP = NULL; + for (int n = 0; n < 6; n++) + m_pStatusLabel[n] = NULL; + m_bNeedStatusUpdate = false; + m_nTimer = 0; + m_bSleeping = false; + Create (); +} + +MainFrame::~MainFrame() +{ + while (g_BSPFrontendCommands) + { + free (g_BSPFrontendCommands->data); + g_BSPFrontendCommands = g_slist_remove (g_BSPFrontendCommands, g_BSPFrontendCommands->data); + } +} + +void MainFrame::ReleaseContexts () +{ + if (m_pXYWnd) + m_pXYWnd->DestroyContext (); + if (m_pYZWnd) + m_pYZWnd->DestroyContext (); + if (m_pXZWnd) + m_pXZWnd->DestroyContext (); + if (m_pCamWnd) + m_pCamWnd->DestroyContext (); + if (m_pTexWnd) + m_pTexWnd->DestroyContext (); + if (m_pZWnd) + m_pZWnd->DestroyContext (); +} + +void MainFrame::CreateContexts () +{ + if (m_pCamWnd) + m_pCamWnd->CreateContext (); + if (m_pXYWnd) + m_pXYWnd->CreateContext (); + if (m_pYZWnd) + m_pYZWnd->CreateContext (); + if (m_pXZWnd) + m_pXZWnd->CreateContext (); + if (m_pTexWnd) + m_pTexWnd->CreateContext (); + if (m_pZWnd) + m_pZWnd->CreateContext (); +} + +static void Sys_Iconify (GtkWidget *w) +{ + // we might not have been realized yet + if (w->window == NULL) + return; + + if (!GTK_WIDGET_MAPPED (w)) + return; + +#if defined (__linux__) || defined (__APPLE__) + Sys_FPrintf(SYS_WRN, "FIXME: Sys_Iconify\n"); +#if 0 + XWindowAttributes xattr; + GdkWindowPrivate *Private; + + Private = (GdkWindowPrivate*)w->window; + g_object_set_data (G_OBJECT (w), "was_mapped", GINT_TO_POINTER (0)); + + if (!Private->destroyed) + { + xattr.map_state = IsUnmapped; + XGetWindowAttributes(Private->xdisplay, Private->xwindow, &xattr); + + if (xattr.map_state != IsUnmapped) + g_object_set_data (G_OBJECT (w), "was_mapped", GINT_TO_POINTER (1)); + + XIconifyWindow (Private->xdisplay, Private->xwindow, 0); + } +#endif +#endif + +#ifdef _WIN32 + ShowWindow ((HWND)GDK_WINDOW_HWND (w->window), SW_MINIMIZE); +#endif +} + +static void Sys_Restore (GtkWidget *w) +{ + // we might not have been realized yet + if (w->window == NULL) + return; + + if (!GTK_WIDGET_VISIBLE (w)) + return; + +#if defined (__linux__) || defined (__APPLE__) + Sys_FPrintf(SYS_WRN, "FIXME: Sys_Restore\n"); + #if 0 + XWindowAttributes xattr; + GdkWindowPrivate *Private; + + Private = (GdkWindowPrivate*)w->window; + + xattr.map_state = IsUnmapped; + XGetWindowAttributes(Private->xdisplay, Private->xwindow, &xattr); + + if (xattr.map_state == IsUnmapped) + XMapRaised (Private->xdisplay, Private->xwindow); + #endif +#endif + +#ifdef _WIN32 + ShowWindow ((HWND)GDK_WINDOW_HWND (w->window), SW_RESTORE); +#endif +} + +#ifdef _DEBUG +//#define DBG_SLEEP +#endif + +void RefreshModelSkin (GSList **pModels, entitymodel_t *model) +{ + //++timo FIXME: the are some bogus entitymodel_t that appear in the list cause of buggy HasModel + // so we avoid the fucked up ones, assuming they are at the end + if (!model->strSkin) + { +#ifdef DBG_SLEEP + Sys_Printf("Dropping model %p with empty skin in RefreshModelSkin\n", model); +#endif + + // and also keeping it so we have an actual count of empty models + g_slist_append (*pModels, model); + return; + } + // do we have this model already? + if (g_slist_find (*pModels, model)) + { +#ifdef DBG_SLEEP + + // looks like we don't have the filename for the model, only the skin name and tris.. so we put the adress + Sys_Printf("Already processed model: %p %s\n", model, ((GString *)model->strSkin)->str); +#endif + return; + } + model->nTextureBind = Texture_LoadSkin(((GString *)model->strSkin)->str, &model->nSkinWidth, &model->nSkinHeight ); + if (model->nTextureBind != -1) + Sys_Printf("LOADED SKIN: %s\n", ((GString *)model->strSkin)->str ); + else + Sys_Printf("Load skin failed: %s\n", ((GString *)model->strSkin)->str ); + *pModels = g_slist_append (*pModels, model); +#ifdef DBG_SLEEP + Sys_Printf("Processed model %p %s\n", model, ((GString *)model->strSkin)->str); +#endif +} + +void MainFrame::OnSleep() +{ + m_bSleeping ^= 1; + if (m_bSleeping) + { + // useful when trying to debug crashes in the sleep code + Sys_Printf("Going into sleep mode..\n"); + + Sys_Printf("Dispatching sleep msg..."); + DispatchRadiantMsg (RADIANT_SLEEP); + Sys_Printf("Done.\n"); + + if (CurrentStyle() == eSplit) + Sys_Iconify (m_pZWnd->m_pParent); + + Sys_Iconify (m_pWidget); + Select_Deselect(); + QERApp_FreeShaders (); + g_bScreenUpdates = false; + + // release contexts + Sys_Printf("Releasing contexts..."); + ReleaseContexts(); + Sys_Printf("Done.\n"); + + // free all the skins in the caches + // their GL resources have been freed but the structs are not, so Radiant would think they are still valid + g_lstSkinCache.RemoveAll(); + } else + { + Sys_Printf("Waking up\n"); + if (CurrentStyle() == eSplit) + Sys_Restore (m_pZWnd->m_pParent); + + Sys_Restore (m_pWidget); + + // create contexts + Sys_Printf("Creating contexts..."); + CreateContexts(); + Sys_Printf("Done.\n"); + + Sys_Printf("Making current on camera..."); + m_pCamWnd->MakeCurrent (); + Sys_Printf("Done.\n"); + + Sys_Printf("Reloading shaders..."); + // reload the shader scripts and textures + QERApp_ReloadShaders (); + // current shader + // NOTE: we are kinda making it loop on itself, it will update the pShader and scroll the texture window + Texture_SetTexture (&g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef, false, NULL, false); + Sys_Printf("Done.\n"); + + // rebuild the patches by setting the bDirty flag on them + for (brush_t* b=active_brushes.next ; b != &active_brushes ; b=b->next) + { + if (b->patchBrush) + b->pPatch->bDirty = true; + } + + Sys_Printf("Reloading skins..."); + // we have purged all the skins before going to sleep + // to rebuild, go through everything that needs a skin and call Texture_LoadSkin + // namely, all entitymodel_t + // since there's no direct list we go through entities to get the eclass_t and from there the entitymodel_t + // (a single eclass_t can reference several entitymodel_t) + // FIXME: and what's up with md3Class then? what is it used for? +/* + eclass_t *e; + entity_t *ent; + GSList *Models = NULL; + for (ent = entities.next; ent != &entities; ent = ent->next) + { + // if it's a model with skin then the fixedsize flag must be on + // only if there IS a model .. we are not trying to load + if (ent->eclass->fixedsize) + { + if (ent->eclass->model) + { +#ifdef DBG_SLEEP + if (ent->md3Class) + Sys_Printf("WARNING: unexpected ent->md3Class!=NULL with ent->eclass->model!=NULL\n"); +#endif + entitymodel_t *model; + for (model = ent->eclass->model; model; model=model->pNext) + RefreshModelSkin (&Models, model); + } else if (ent->md3Class) + { + entitymodel_t *model; + for (model = ent->md3Class->model; model; model=model->pNext) + RefreshModelSkin (&Models, model); + } +#ifdef DBG_SLEEP + else + Sys_Printf("WARNING: entity %p %s with fixedsize and no model no md3Class\n", ent, ent->eclass->name); +#endif + } + } +#ifdef DBG_SLEEP + for (e = g_md3Cache; e ; e = e->next) + { + entitymodel_t *model; + for (model = e->model; model; model=model->pNext) + if (!g_slist_find (Models, model)) + { + Sys_Printf("model %p ", model); + if (model->strSkin) + Sys_Printf("%s not found in main loop\n", ((GString *)model->strSkin)->str); + else + Sys_Printf("not found in main loop (no skin)\n"); + } + } +#endif + // clean the model list + g_slist_free (Models); +*/ + Sys_Printf("Done.\n"); + + // bring back the GL font + gtk_glwidget_create_font (m_pCamWnd->GetWidget ()); + + g_bScreenUpdates = true; + + Sys_Printf("Dispatching wake msg..."); + DispatchRadiantMsg (RADIANT_WAKEUP); + Sys_Printf("Done\n"); + } +} + +void WINAPI QERApp_Sleep() +{ + g_pParentWnd->OnSleep(); +} + +/*! +NOTE TTimo +the exit path is a bit complicated, I guess we have to run the window pos saving in OnDelete +and not in OnDestroy because the info may be lost already? +\todo try sinking OnDelete into OnDestroy and see if it breaks anything +*/ +void MainFrame::OnDelete () +{ + save_window_pos(m_pWidget, g_PrefsDlg.mWindowInfo.position); + + // surface inspector and patch inspector + save_window_pos (g_dlgSurface.GetWidget(), g_PrefsDlg.mWindowInfo.posSurfaceWnd); + save_window_pos (g_PatchDialog.GetWidget(), g_PrefsDlg.mWindowInfo.posPatchWnd); + + // entity inspector / group dialog + // NOTE TTimo do we have to save a different window depending on the view mode? + save_window_pos (g_pGroupDlg->m_pWidget, g_PrefsDlg.mWindowInfo.posEntityWnd); + + if (g_PrefsDlg.m_bFloatingZ) + save_window_pos (m_pZWnd->m_pParent, g_PrefsDlg.mWindowInfo.posZWnd); + else + g_PrefsDlg.mWindowInfo.nZFloatWidth = GTK_PANED (m_pSplits[0])->child1_size; + + if (CurrentStyle() == eFloating) + { + save_window_pos (m_pCamWnd->m_pParent, g_PrefsDlg.mWindowInfo.posCamWnd); + save_window_pos (m_pXYWnd->m_pParent, g_PrefsDlg.mWindowInfo.posXYWnd); + save_window_pos (m_pXZWnd->m_pParent, g_PrefsDlg.mWindowInfo.posXZWnd); + save_window_pos (m_pYZWnd->m_pParent, g_PrefsDlg.mWindowInfo.posYZWnd); + } + + g_PrefsDlg.mWindowInfo.nState = gdk_window_get_state(g_pParentWnd->m_pWidget->window); +} + +void MainFrame::OnDestroy () +{ + // shut down console output first + // (we'll still get the info if we are running a log file anyway) + g_qeglobals_gui.d_edit = NULL; + +#ifdef _DEBUG + Sys_Printf("MainFrame::OnDestroy\n"); +#endif + if (s_idle_id) + gtk_timeout_remove (s_idle_id); + if (m_nTimer) + gtk_timeout_remove (m_nTimer); + + if (!g_qeglobals.disable_ini) + { + Sys_Printf("Start writing prefs\n"); + Sys_Printf("MRU_Save... "); + MRU_Save (); + Sys_Printf("OK\n"); + + gpointer w; + + w = g_object_get_data (G_OBJECT (g_pGroupDlg->m_pWidget), "split1"); + g_PrefsDlg.mWindowInfo.nEntitySplit1 = GTK_PANED (w)->child1_size; + w = g_object_get_data (G_OBJECT (g_pGroupDlg->m_pWidget), "split2"); + g_PrefsDlg.mWindowInfo.nEntitySplit2 = GTK_PANED (w)->child1_size; + + if (!FloatingGroupDialog()) + { + GtkWidget *vsplit, *hsplit, *vsplit2, *hsplit2; + + vsplit = m_pSplits[0]; + vsplit2 = m_pSplits[1]; + hsplit = m_pSplits[2]; + hsplit2 = m_pSplits[3]; + + g_PrefsDlg.mWindowInfo.nXYHeight = GTK_PANED (vsplit)->child1_size; + g_PrefsDlg.mWindowInfo.nXYWidth = GTK_PANED (hsplit2)->child1_size; + + if(CurrentStyle() == eRegular) + g_PrefsDlg.mWindowInfo.nZWidth = GTK_PANED (hsplit)->child1_size; + else + g_PrefsDlg.mWindowInfo.nCamWidth = GTK_PANED (hsplit)->child1_size; + + g_PrefsDlg.mWindowInfo.nCamHeight = GTK_PANED (vsplit2)->child1_size; + } else + { + if (g_PrefsDlg.m_bFloatingZ || CurrentStyle() == eSplit) + { + if (GTK_WIDGET_VISIBLE (m_pZWnd->m_pParent)) + g_PrefsDlg.m_bZVis = TRUE; + else + g_PrefsDlg.m_bZVis = FALSE; + } + } + g_PrefsDlg.SavePrefs(); + Sys_Printf("Done prefs\n"); + } + + // spog - this may be better in another place.. + // deletes filters list and assigns g_qeglobals.d_savedinfo.filters = NULL + g_qeglobals.d_savedinfo.filters = FilterListDelete(g_qeglobals.d_savedinfo.filters); + + delete m_pXYWnd; m_pXYWnd = NULL; + delete m_pYZWnd; m_pYZWnd = NULL; + delete m_pXZWnd; m_pXZWnd = NULL; + delete m_pZWnd; m_pZWnd = NULL; + delete m_pTexWnd; m_pTexWnd = NULL; + delete m_pCamWnd; m_pCamWnd = NULL; + + if (g_pGroupDlg->m_pWidget) + { + //!\todo fix "Gtk-CRITICAL **: file gtknotebook.c: line 4643 (gtk_notebook_get_tab_label): assertion `GTK_IS_WIDGET (child)' failed" + gtk_widget_destroy (g_pGroupDlg->m_pWidget); + g_pGroupDlg->m_pWidget = NULL; + } + + if (strcmpi(currentmap, "unnamed.map") != 0) + { + g_PrefsDlg.m_strLastMap = currentmap; + g_PrefsDlg.SavePrefs (); + } + Sys_Printf("CleanUpEntities..."); + CleanUpEntities(); + Sys_Printf("Done.\n"); + + Sys_Printf("Releasing brushes..."); + while (active_brushes.next != &active_brushes) + Brush_Free (active_brushes.next, false); + while (selected_brushes.next != &selected_brushes) + Brush_Free (selected_brushes.next, false); + while (filtered_brushes.next != &filtered_brushes) + Brush_Free (filtered_brushes.next, false); + Sys_Printf("Done.\n"); + + Sys_Printf("Releasing entities..."); + while (entities.next != &entities) + Entity_Free (entities.next); + Sys_Printf("Done.\n"); + + epair_t* pEPair = g_qeglobals.d_project_entity->epairs; + while (pEPair) + { + epair_t* pNextEPair = pEPair->next; + free (pEPair->key); + free (pEPair->value); + free (pEPair); + pEPair = pNextEPair; + } + + entity_t* pEntity = g_qeglobals.d_project_entity->next; + while (pEntity != NULL && pEntity != g_qeglobals.d_project_entity) + { + entity_t* pNextEntity = pEntity->next; + Entity_Free(pEntity); + pEntity = pNextEntity; + } + + Sys_Printf("Freeing world entity..."); + if (world_entity) + Entity_Free(world_entity); + Sys_Printf("Done.\n"); + + Sys_Printf("Shutdown VFS..."); + vfsShutdown (); + Sys_Printf("Done.\n"); + + Sys_Printf("FreeShaders..."); + QERApp_FreeShaders(); + Sys_Printf("Done.\n"); +} + +// TTimo: now using profile.cpp code +void MainFrame::LoadCommandMap() +{ + FILE *f; + CString strINI; + bool bUserCmdList = false; + int nLen; + // verbose a little: count of user commands we recognized + int iCount = 0; + int iOverrideCount = 0; + int j; + + +#if defined (__linux__) || defined (__APPLE__) + strINI = g_PrefsDlg.m_rc_path->str; +#elif defined(WIN32) + strINI = g_strGameToolsPath; +#else +#error "WTF are you compiling this on" +#endif + AddSlash (strINI); + strINI += "shortcuts.ini"; + + f = fopen (strINI.GetBuffer(), "r"); + if (f != NULL) + { + fclose(f); + // loop through all the commands + for (int i = 0; i < g_nCommandCount; i++) + { + char value[1024]; + if (read_var( strINI.GetBuffer(), "Commands", g_Commands[i].m_strCommand, value )) + { + if (!bUserCmdList) + { + Sys_Printf("Found user's shortcuts list at %s\n", strINI.GetBuffer() ); + bUserCmdList = true; + } + CString strBuff; + strBuff = value; + strBuff.TrimLeft(); + strBuff.TrimRight(); + strBuff.MakeLower(); + int nSpecial = strBuff.Find("+alt"); + g_Commands[i].m_nModifiers = 0; + if (nSpecial >= 0) + { + g_Commands[i].m_nModifiers |= RAD_ALT; + FindReplace(strBuff, "+alt", ""); + } + nSpecial = strBuff.Find("+ctrl"); + if (nSpecial >= 0) + { + g_Commands[i].m_nModifiers |= RAD_CONTROL; + FindReplace(strBuff, "+ctrl", ""); + } + nSpecial = strBuff.Find("+shift"); + if (nSpecial >= 0) + { + g_Commands[i].m_nModifiers |= RAD_SHIFT; + FindReplace(strBuff, "+shift", ""); + } + strBuff.TrimLeft(); + strBuff.TrimRight(); + strBuff.MakeUpper(); + // strBuff has been cleaned of it's modifiers .. switch between a regular key and a virtual one + // based on length + nLen = strBuff.GetLength(); + if (nLen == 1) // most often case.. deal with first + { + g_Commands[i].m_nKey = __toascii(strBuff.GetAt(0)); + iCount++; + } else // special key + { + for (j = 0; j < g_nKeyCount; j++) + { + if (strBuff.CompareNoCase(g_Keys[j].m_strName) == 0) + { + g_Commands[i].m_nKey = g_Keys[j].m_nVKKey; + iCount++; + break; + } + } + if (j == g_nKeyCount) + { + Sys_Printf("WARNING: failed to parse user command %s\n", value); + continue; + } + } + // maybe this new shortcut is overriding another one + // then we need to disable the other binded key + for (j = 0; j < g_nCommandCount; j++) + { + if (j == i) + continue; + if (g_Commands[i].m_nKey == g_Commands[j].m_nKey && g_Commands[i].m_nModifiers == g_Commands[j].m_nModifiers) + { + // found! + g_Commands[j].m_nKey = 0; + // verbose + iOverrideCount++; + // it's the only one + break; + } + } + } + } + if (iOverrideCount) + Sys_Printf("User's command list overrides %d default commands\n", iOverrideCount); + Sys_Printf("Parsed %d custom shortcuts\n", iCount ); + } + else + Sys_Printf("Looked for a '%s' keyboard shortcuts file, not found\n", strINI.GetBuffer()); +} + +// TTimo: an m_nKey can be set to zero if there's no shorcut binded +// we also output the count of commands that are not binded .. dunno if it's much use .. +// (non-binded keys are usually keys that were defined by shortcuts overriden by user prefs) +void MainFrame::ShowMenuItemKeyBindings(GtkWidget* window) +{ + //!\todo Find a better way to get the global accelerator group.. + GtkAccelGroup *accel = GTK_ACCEL_GROUP(gtk_accel_groups_from_object(G_OBJECT(window))->data); + gpointer item; + guint mods; + int i; + int iCount = 0; + + for (i = 0; i < g_nCommandCount; i++) + { + if (g_Commands[i].m_nKey == 0) + { + iCount++; + continue; + } + + item = g_object_get_data (G_OBJECT (m_pWidget), g_Commands[i].m_strMenu); + if (item == NULL) + { + Sys_FPrintf (SYS_WRN, "WARNING: keyboard shortcuts init, no menu item found for command: \"%s\"\n", + g_Commands[i].m_strCommand); + continue; + } + + mods = 0; + if (g_Commands[i].m_nModifiers) // are there modifiers present? + { + if (g_Commands[i].m_nModifiers & RAD_SHIFT) + mods |= GDK_SHIFT_MASK; + if (g_Commands[i].m_nModifiers & RAD_ALT) + mods |= GDK_MOD1_MASK; + if (g_Commands[i].m_nModifiers & RAD_CONTROL) + mods |= GDK_CONTROL_MASK; + } + + // GTK won't add accelerators for some keys (ex.: delete), so we have to do it manually + if (gtk_accelerator_valid (g_Commands[i].m_nKey, (GdkModifierType)mods)) + { +#ifdef DBG_KBD + // NOTE TTimo this is the important place where all the shortcuts are binded + Sys_Printf("Calling gtk_widget_add_accelerator on command: %s menu: %s key: %d mods: %d\n", g_Commands[i].m_strCommand, g_Commands[i].m_strMenu, g_Commands[i].m_nKey, mods); +#endif + gtk_widget_add_accelerator (GTK_WIDGET (item), "activate", accel, g_Commands[i].m_nKey, + (GdkModifierType)mods, GTK_ACCEL_VISIBLE); + } else + { + GtkAccelLabel *accel_label = GTK_ACCEL_LABEL (GTK_BIN (item)->child); + GString *gstring; + gboolean had_mod; + + g_free (accel_label->accel_string); + accel_label->accel_string = NULL; + + gstring = g_string_new (accel_label->accel_string); + g_string_append (gstring, " "); + + had_mod = FALSE; + if (mods & GDK_SHIFT_MASK) + { + g_string_append (gstring, "Shft"); + had_mod = TRUE; + } + if (mods & GDK_CONTROL_MASK) + { + if (had_mod) + g_string_append (gstring, "+"); + g_string_append (gstring, "Ctl"); + had_mod = TRUE; + } + if (mods & GDK_MOD1_MASK) + { + if (had_mod) + g_string_append (gstring, "+"); + g_string_append (gstring, "Alt"); + had_mod = TRUE; + } + + if (had_mod) + g_string_append (gstring, "+"); + if (g_Commands[i].m_nKey < 0x80 || (g_Commands[i].m_nKey > 0x80 && g_Commands[i].m_nKey <= 0xff)) + { + switch (g_Commands[i].m_nKey) + { + case ' ': + g_string_append (gstring, "Space"); + break; + case '\\': + g_string_append (gstring, "Backslash"); + break; + default: + g_string_append_c (gstring, toupper (g_Commands[i].m_nKey)); + break; + } + } else + { + gchar *tmp; + + tmp = gtk_accelerator_name (g_Commands[i].m_nKey, (GdkModifierType)0); + if (tmp[0] != 0 && tmp[1] == 0) + tmp[0] = toupper (tmp[0]); + g_string_append (gstring, tmp); + g_free (tmp); + } + + g_free (accel_label->accel_string); + accel_label->accel_string = gstring->str; + g_string_free (gstring, FALSE); + + if (!accel_label->accel_string) + accel_label->accel_string = g_strdup (""); + + gtk_widget_queue_resize (GTK_WIDGET (accel_label)); + } + } + + if (iCount) + Sys_Printf("%d commands not bound to a key\n", iCount); +} + +void MainFrame::CreateQEChildren() +{ + // load the project file + if (g_argc > 1) + { + Sys_Printf("loading project file from the command line: %s\n", g_argv[1]); + if (!QE_LoadProject(g_argv[1])) + Error("Unable to load project file %s\n", g_argv[1]); + } + else + { + const char* filename = NULL; + char buf[PATH_MAX]; + const char *r; + bool bTriedTemplate = false; + + if (g_PrefsDlg.m_nLastProjectVer != 0 && g_PrefsDlg.m_nLastProjectVer != PROJECT_VERSION) { + // we need to regenerate from template + Sys_Printf("last project has version %d, this binary wants version %d - regenerating from the template\n", g_PrefsDlg.m_nLastProjectVer, PROJECT_VERSION); + g_PrefsDlg.m_strLastProject = ""; + } + + r = g_PrefsDlg.m_strLastProject.GetBuffer(); + + while(r == NULL || *r == '\0' || access(r, R_OK) != 0 || !QE_LoadProject(r)) + { + if(!bTriedTemplate) + { + // try default project location + bTriedTemplate = true; + // for all OSes, we look for the template in the base installation (no homepath here) + strcpy(buf, g_pGameDescription->mEnginePath.GetBuffer()); + strcat(buf, g_pGameDescription->mBaseGame.GetBuffer()); + strcat(buf, "/scripts/"); + strcat(buf, PROJECT_TEMPLATE_NAME); + r = buf; + } + else + { + gtk_MessageBox (NULL, "Failed to load project file.\nPlease enter a valid project file.", "Load Project"); + + filename = file_dialog (m_pWidget, TRUE, "Choose Project File", buf, "project"); + if (filename != NULL) + r = filename; + else + Error("Cannot continue without loading a project..."); + } + } + } + + QE_Init (); +} + +void MainFrame::OnTimer() +{ + GdkModifierType mask; + + gdk_window_get_pointer (NULL, NULL, NULL, &mask); + + if ((mask & (GDK_BUTTON1_MASK|GDK_BUTTON2_MASK|GDK_BUTTON3_MASK)) == 0) + { + QE_CountBrushesAndUpdateStatusBar(); + QE_CheckAutoSave(); + } + + // see MainFrame::UpdateStatusText below + if (m_bNeedStatusUpdate) + { + for (int n = 0; n < 6; n++) + { + if (m_strStatus[n].GetLength() >= 0 && m_pStatusLabel[n] != NULL) + gtk_label_set_text (GTK_LABEL (m_pStatusLabel[n]), m_strStatus[n]); + } + m_bNeedStatusUpdate = false; + } +} + +void MainFrame::UpdateStatusText() +{ + m_bNeedStatusUpdate = true; +} + +void MainFrame::SetStatusText(int nPane, const char* pText) +{ + if (pText && nPane <= 5 && nPane >= 0) + { + m_strStatus[nPane] = pText; + UpdateStatusText(); + } +} +void MainFrame::SetButtonMenuStates() +{ + GtkWidget *item; + g_bIgnoreCommands++; + + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showangles")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_qeglobals.d_savedinfo.show_angles); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_shownames")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_qeglobals.d_savedinfo.show_names); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showcoordinates")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_qeglobals.d_savedinfo.show_coordinates); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showoutline")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_qeglobals.d_savedinfo.show_outline); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_selection_nooutline")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_ZBUF)); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showaxes")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_qeglobals.d_savedinfo.show_axis); + //item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showpath")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS) ? FALSE : TRUE); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_clusterportals")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLUSTERPORTALS) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_lightgrid")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_LIGHTGRID) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_world")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_WORLD) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_entities")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_ENT) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_areaportals")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_AREAPORTALS) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_translucent")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_TRANSLUCENT) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_liquids")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_LIQUIDS) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_caulk")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_clips")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_botclips")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_structural")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_STRUCTURAL) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_paths")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_clusterportals")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLUSTERPORTALS) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_lightgrid")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_LIGHTGRID) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_lights")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_LIGHTS) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_patches")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CURVES) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_details")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_DETAILS) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_hintsskips")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_HINTSSKIPS) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_models")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_MODELS) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_triggers")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (g_qeglobals.d_savedinfo.exclude & EXCLUDE_TRIGGERS) != 0); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_toggle_lock")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (g_PrefsDlg.m_bTextureLock) ? TRUE : FALSE); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_toggle_rotatelock")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (g_PrefsDlg.m_bRotateLock) ? TRUE : FALSE); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_cubicclipping")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (g_PrefsDlg.m_bCubicClipping) ? TRUE : FALSE); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_opengllighting")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (g_PrefsDlg.m_bGLLighting) ? TRUE : FALSE); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_snaptogrid")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (!g_PrefsDlg.m_bNoClamp) ? TRUE : FALSE); + + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_view_cubicclipping")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_PrefsDlg.m_bCubicClipping) ? TRUE : FALSE); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_dontselectmodel")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_PrefsDlg.m_bSelectModels) ? FALSE : TRUE); + + if (!g_pGameDescription->mNoPatch) + { + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_dontselectcurve")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_PrefsDlg.m_bSelectCurves) ? FALSE : TRUE); + + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_showboundingbox")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchShowBounds) ? TRUE : FALSE); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_weld")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchWeld) ? TRUE : FALSE); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_drilldown")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchDrillDown) ? TRUE : FALSE); + } + + int id, n = g_PrefsDlg.m_nTextureScale; + switch (n) + { + case 10 : id = ID_TEXTURES_TEXTUREWINDOWSCALE_10; break; + case 25 : id = ID_TEXTURES_TEXTUREWINDOWSCALE_25; break; + case 50 : id = ID_TEXTURES_TEXTUREWINDOWSCALE_50; break; + case 200 : id = ID_TEXTURES_TEXTUREWINDOWSCALE_200; break; + default : id = ID_TEXTURES_TEXTUREWINDOWSCALE_100; break; + } + SetTextureScale (id); + + // FIXME TTimo cleaned up .. the right place to do this in QE_LoadProject? +/* + if (g_qeglobals.d_project_entity) + { + FillTextureMenu(); // redundant but i'll clean it up later.. yeah right.. + FillBSPMenu(); + } + */ + g_bIgnoreCommands--; +} + +void MainFrame::UpdateWindows(int nBits) +{ + if (!g_bScreenUpdates) + return; +#ifdef DBG_WINDOWPOS + static int bean_count = 0; + char bean_buf[100]; + sprintf(bean_buf,"UpdateWindows %d",bean_count); + CheckWatchit(bean_buf); + bean_count++; +#endif + + if (nBits & (W_XY | W_XY_OVERLAY)) + { + if (m_pXYWnd) + m_pXYWnd->RedrawWindow (); + if (m_pXZWnd) + m_pXZWnd->RedrawWindow (); + if (m_pYZWnd) + m_pYZWnd->RedrawWindow (); + } + + if (nBits & W_CAMERA || ((nBits & W_CAMERA_IFON) && m_bCamPreview)) + { + if (m_pCamWnd) + m_pCamWnd->RedrawWindow (); + } + + if (nBits & (W_Z | W_Z_OVERLAY)) + { + if (m_pZWnd) + m_pZWnd->RedrawWindow (); + } + + if (nBits & W_TEXTURE) + { + if (m_pTexWnd) + m_pTexWnd->RedrawWindow (); + } +#ifdef DBG_WINDOWPOS + sprintf(bean_buf,"%d (end UpdateWidows)",bean_count); + CheckWatchit(bean_buf); +#endif +} + +void MainFrame::RoutineProcessing() +{ +#ifdef DBG_WINDOWPOS + static int bean_count = 0; + char bean_buf[100]; + sprintf(bean_buf,"RoutineProcessing %d",bean_count); + CheckWatchit(bean_buf); + bean_count++; +#endif + + if (m_bDoLoop) + { + double time = 0.0; + double oldtime = 0.0; + double delta= 0.0; + +/* // checking KeyState works right + static short a1,a2; + a2 = GetKeyState(VK_MENU); + if (a1!=a2) + { + Sys_Printf("VK_MENU: %d\n",a2); + a1 = a2; + } + static short b1,b2; + b2 = GetKeyState(VK_UP); + if (b1!=b2) + { + Sys_Printf("VK_UP: %d\n",b2); + b1 = b2; + } */ + + time = Sys_DoubleTime (); + delta = time - oldtime; + oldtime = time; + if (delta > 0.2) + delta = 0.2; + + // update the BSP process watcher + if (m_pWatchBSP) + m_pWatchBSP->RoutineProcessing(); + + // run time dependant behavior + if (m_pCamWnd) + m_pCamWnd->Cam_MouseControl(delta); + + if (g_nUpdateBits) + { + int nBits = g_nUpdateBits; // this is done to keep this routine from being + g_nUpdateBits = 0; // re-entered due to the paint process.. only + UpdateWindows(nBits); // happens in rare cases but causes a stack overflow + } +/* + // Enable/disable the menu items + GtkWidget *item; + + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_cameraupdate")); + gtk_widget_set_sensitive (item, (m_bCamPreview == false)); + if (!g_PrefsDlg.m_bWideToolbar) + { + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_view_cameraupdate")); + gtk_widget_set_sensitive (item, (m_bCamPreview == false)); + } + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_edit_undo")); + gtk_widget_set_sensitive (item, Undo_UndoAvailable()); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_edit_redo")); + gtk_widget_set_sensitive (item, Undo_RedoAvailable()); + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_file_saveregion")); + gtk_widget_set_sensitive (item, region_active); + g_bIgnoreCommands++; + // update the toolbar before displaying the menu: + // show in use check box + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_showinuse")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), !g_bShowAllShaders); + // show all check box + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_showall")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_bShowAllShaders); + g_bIgnoreCommands--; + */ + } +#ifdef DBG_WINDOWPOS + sprintf(bean_buf,"%d (end RoutineProcessing)",bean_count); + CheckWatchit(bean_buf); +#endif +} + +void MainFrame::DoWatchBSP() +{ + // network monitoring of the BSP process + if (!m_pWatchBSP) + m_pWatchBSP = new CWatchBSP(); +} + +void MainFrame::CleanPlugInMenu() +{ + GtkWidget *menu, *sep; + GList *lst; + + // delete everything after the separator + menu = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_plugin")); + sep = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_plugin_separator")); + m_nNextPlugInID = ID_PLUGIN_START; + + lst = g_list_find (gtk_container_children (GTK_CONTAINER (menu)), sep); + while (lst->next) + { + gtk_container_remove (GTK_CONTAINER (menu), GTK_WIDGET (lst->next->data)); + lst = g_list_find (gtk_container_children (GTK_CONTAINER (menu)), sep); + } +} + +void MainFrame::AddPlugInMenuItem(IPlugIn* pPlugIn) +{ + GtkWidget *menu, *item, *parent; + const char *menuText; + + parent = gtk_menu_item_new_with_label (pPlugIn->getMenuName()); + gtk_widget_show (parent); + gtk_container_add (GTK_CONTAINER (g_object_get_data (G_OBJECT (m_pWidget), "menu_plugin")), parent); + + int nCount = pPlugIn->getCommandCount(); + if (nCount > 0) + { + menu = gtk_menu_new (); + while (nCount > 0) + { + menuText = pPlugIn->getCommand(--nCount); + if (menuText != NULL && strlen(menuText) > 0) + { + if (!strcmp(menuText, "-")) + { + item = gtk_menu_item_new (); + gtk_widget_set_sensitive (item, FALSE); + } else + { + item = gtk_menu_item_new_with_label (menuText); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (m_nNextPlugInID)); + } + gtk_widget_show (item); + gtk_container_add (GTK_CONTAINER (menu), item); + pPlugIn->addMenuID(m_nNextPlugInID++); + } + } + gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent), menu); + } +} + +void MainFrame::OnPlugIn(unsigned int nID, char* str) +{ + m_PlugInMgr.Dispatch(nID, str); +} + +inline GtkToolbarChildType gtktoolbarchildtype_for_toolbarbuttontype(IToolbarButton::EType type) +{ + switch(type) + { + case IToolbarButton::eSpace: + return GTK_TOOLBAR_CHILD_SPACE; + case IToolbarButton::eButton: + return GTK_TOOLBAR_CHILD_BUTTON; + case IToolbarButton::eToggleButton: + return GTK_TOOLBAR_CHILD_TOGGLEBUTTON; + case IToolbarButton::eRadioButton: + return GTK_TOOLBAR_CHILD_RADIOBUTTON; + } + Error("invalid toolbar button type"); + return (GtkToolbarChildType)0; +} + +void toolbar_insert(GtkWidget *toolbar, const char* image, const char* text, const char* tooltip, IToolbarButton::EType type, GtkSignalFunc handler, gpointer data) +{ + GtkWidget *w, *pixmap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + + load_plugin_bitmap(image, (void **)&gdkpixmap, (void **)&mask); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_pixmap_unref (mask); + w = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), gtktoolbarchildtype_for_toolbarbuttontype(type), NULL, text, tooltip, "", GTK_WIDGET (pixmap), handler, data); +} + +void SignalToolbarButton(GtkWidget *widget, gpointer data) +{ + const_cast(reinterpret_cast(data))->activate(); +} + +void MainFrame::AddPlugInToolbarButton(const IToolbarButton* button) +{ + GtkWidget*const toolbar = GTK_WIDGET(g_object_get_data (G_OBJECT (m_pWidget), "toolbar_plugin")); + toolbar_insert(toolbar, button->getImage(), button->getText(), button->getTooltip(), button->getType(), GTK_SIGNAL_FUNC(SignalToolbarButton), reinterpret_cast(const_cast(button))); +} + +void MainFrame::OnSelectionSelectNudgedown() +{ + NudgeSelection(3, g_qeglobals.d_gridsize); +} + +void MainFrame::OnSelectionSelectNudgeleft() +{ + NudgeSelection(0, g_qeglobals.d_gridsize); +} + +void MainFrame::OnSelectionSelectNudgeright() +{ + NudgeSelection(2, g_qeglobals.d_gridsize); +} + +void MainFrame::OnSelectionSelectNudgeup() +{ + NudgeSelection(1, g_qeglobals.d_gridsize); +} + +void MainFrame::NudgeSelection(int nDirection, float fAmount) +{ + if (ActiveXY()->RotateMode()) + { + int nAxis = 0; + if (ActiveXY()->GetViewType() == XY) + { + nAxis = 2; + } else + if (g_pParentWnd->ActiveXY()->GetViewType() == XZ) + { + nAxis = 1; + fAmount = -fAmount; + } + + if (nDirection == 2 || nDirection == 3) + { + fAmount = -fAmount; + } + + float fDeg = -fAmount; + float fAdj = fAmount; + + g_pParentWnd->ActiveXY()->Rotation()[nAxis] += fAdj; + CString strStatus; + strStatus.Format("Rotation x:: %.1f y:: %.1f z:: %.1f", g_pParentWnd->ActiveXY()->Rotation()[0], + g_pParentWnd->ActiveXY()->Rotation()[1], g_pParentWnd->ActiveXY()->Rotation()[2]); + g_pParentWnd->SetStatusText(2, strStatus); + Select_RotateAxis(nAxis, fDeg, false, true); + Sys_UpdateWindows (W_ALL); + } else + if (ActiveXY()->ScaleMode()) + { + if (nDirection == 0 || nDirection == 3) + { + fAmount = -fAmount; + } + vec3_t v; + v[0] = v[1] = v[2] = 1.0; + if (fAmount > 0) + { + v[0] = 1.1f; + v[1] = 1.1f; + v[2] = 1.1f; + } else + { + v[0] = 0.9f; + v[1] = 0.9f; + v[2] = 0.9f; + } + + Select_Scale((g_nScaleHow & SCALE_X) ? v[0] : 1.0, + (g_nScaleHow & SCALE_Y) ? v[1] : 1.0, + (g_nScaleHow & SCALE_Z) ? v[2] : 1.0); + Sys_UpdateWindows (W_ALL); + } else + { + // 0 - left, 1 - up, 2 - right, 3 - down + int nDim; + if (nDirection == 0) + { + nDim = ActiveXY()->GetViewType() == YZ ? 1 : 0; + fAmount = -fAmount; + } else if (nDirection == 1) + { + nDim = ActiveXY()->GetViewType() == XY ? 1 : 2; + } else if (nDirection == 2) + { + nDim = ActiveXY()->GetViewType() == YZ ? 1 : 0; + } else + { + nDim = ActiveXY()->GetViewType() == XY ? 1 : 2; + fAmount = -fAmount; + } + Nudge(nDim, fAmount); + } +} + +void MainFrame::Nudge(int nDim, float fNudge) +{ + vec3_t vMove; + vMove[0] = vMove[1] = vMove[2] = 0; + vMove[nDim] = fNudge; + + if((g_qeglobals.d_select_mode == sel_vertex || + g_qeglobals.d_select_mode == sel_curvepoint) + && g_qeglobals.d_num_move_points) + Select_NudgePoint(vMove, true); + else + Select_Move(vMove, true); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::SetGridStatus() +{ + CString strStatus; + char c1; + char c2; + c1 = (g_PrefsDlg.m_bTextureLock) ? 'M' : ' '; + c2 = (g_PrefsDlg.m_bRotateLock) ? 'R' : ' '; + strStatus.Format("G:%g R:%i C:%i L:%c%c", g_qeglobals.d_gridsize, + g_PrefsDlg.m_nRotation, g_PrefsDlg.m_nCubicScale, c1, c2); + SetStatusText(4, strStatus); +} + +void MainFrame::UpdatePatchToolbarButtons() +{ + GtkWidget *item; + g_bIgnoreCommands++; + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_bend")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchBendMode) ? TRUE : FALSE); +// item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_insdel")); +// gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchInsertMode) ? TRUE : FALSE); + g_bIgnoreCommands--; +} + +// ============================================================================= +// Command handlers + +void MainFrame::OnFileNew() +{ + if (ConfirmModified()) + Map_New (); +} + +void MainFrame::OnFileOpen() +{ + if (!ConfirmModified()) + return; + + const char *str; + char buf[NAME_MAX]; + + strcpy(buf, g_qeglobals.m_strHomeMaps.GetBuffer()); + strcat(buf, "maps/"); + + str = file_dialog (m_pWidget, TRUE, "Open Map", buf, MAP_MAJOR); + + if (str != NULL) + { + strcpy(currentmap,str); + MRU_AddFile (str); + Map_LoadFile(str); + } +} + +void MainFrame::OnFileImportmap() +{ + const char *str; + char buf[NAME_MAX]; + + strcpy(buf, g_qeglobals.m_strHomeMaps.GetBuffer()); + strcat(buf, "maps/"); + + str = file_dialog (m_pWidget, TRUE, "Import Map", buf, MAP_MAJOR); + + if (str != NULL) + { + Map_ImportFile(str); + } +} + +void MainFrame::OnFileSave() +{ + if (!strcmp(currentmap, "unnamed.map")) + OnFileSaveas(); + else + Map_SaveFile (currentmap, false); +} + +void MainFrame::OnFileSaveas() +{ + const char* str; + char buf[NAME_MAX]; + + strcpy(buf, g_qeglobals.m_strHomeMaps.GetBuffer()); + strcat(buf, "maps/"); + + str = file_dialog (g_pParentWnd->m_pWidget, FALSE, "Save Map", buf, MAP_MAJOR); + + if (str != NULL) + { + strcpy (currentmap, str); + MRU_AddFile (str); + Map_SaveFile (str, false); // ignore region + } +} + +void MainFrame::OnFileExportmap() +{ + const char* str; + char buf[NAME_MAX]; + + strcpy(buf, g_qeglobals.m_strHomeMaps.GetBuffer()); + strcat(buf, "maps/"); + + str = file_dialog (m_pWidget, FALSE, "Export Selection", buf, MAP_MAJOR); + + if (str != NULL) + { + Map_SaveSelected (str); + } +} + +void MainFrame::OnFileSaveregion() +{ + const char* str; + char buf[NAME_MAX]; + + strcpy(buf, g_qeglobals.m_strHomeMaps.GetBuffer()); + strcat(buf, "maps/"); + + str = file_dialog (g_pParentWnd->m_pWidget, FALSE, "Export Region", buf, MAP_MAJOR); + + if (str != NULL) + { + Map_SaveFile (str, true); // ignore region + } +} + +void MainFrame::OnFileNewproject() +{ + char* name = DoNewProjectDlg (); + + // create a new project: + // create directories and grab current project, save it in new project tree in scripts/user.qe4 + // on linux we create under ~/.q3a, on win32 under strEnginePath + // NOTE: working on a seperate project file might be broken, never did much experiment with that.. + if ((name != NULL) && (strlen (name) > 0)) + { + CString strNewBasePath; + + // NOTE TTimo this would probably not work right on *nix + strNewBasePath = g_pGameDescription->mEnginePath.GetBuffer(); // assume paths end with '/' + strNewBasePath += name; + strNewBasePath += "/"; + + CString strProjToLoad; + CString strMapToLoad; + + // if the dir exists, ask the user if they want to continue anyway + if (Q_mkdir (strNewBasePath.GetBuffer(), 0755) != 0) + { + CString strMsg; + strMsg.Format("The directory name %s already exists\nContinue anyway ?\n", strNewBasePath.GetBuffer ()); + Sys_Printf(strMsg); + if (gtk_MessageBox(m_pWidget, strMsg, "Error", MB_YESNO) != IDYES) + { + Sys_Printf("New Project cancelled, directory already exists for project\n"); + free (name); + return; + } + } + + CString strDir; + strDir = strNewBasePath; + strDir += "maps/"; + Q_mkdir (strDir.GetBuffer(), 0755); + + strDir = strNewBasePath; + strDir += "textures/"; + Q_mkdir (strDir.GetBuffer(), 0755); + + strDir = strNewBasePath; + strDir += "scripts/"; + Q_mkdir (strDir.GetBuffer(), 0755); + + // print a warning for total conversions, since setting the basepath when required files are + // not there _will_ break things (ie; textures/radiant/notex.tga, scripts/entities.def) + Sys_FPrintf(SYS_WRN, "*** Note: basepath unchanged\n"); + + SetKeyValue( g_qeglobals.d_project_entity, "gamename", name); + + strDir = strNewBasePath; + strDir += "maps/autosave.map"; + SetKeyValue( g_qeglobals.d_project_entity, "autosave", strDir.GetBuffer() ); + + // state that this is a user project file, no templating + SetKeyValue( g_qeglobals.d_project_entity, "user_project", "1" ); + // create the project file + strProjToLoad = strNewBasePath; + strProjToLoad += "scripts/"; + strProjToLoad += name; + strProjToLoad += "."; + strProjToLoad += PROJECT_FILETYPE; + QE_SaveProject(strProjToLoad.GetBuffer()); + free (name); + } +} + +void MainFrame::OnFileLoadproject() +{ + if (ConfirmModified()) + ProjectDialog (); +} + +void MainFrame::OnFileProjectsettings() +{ + DoProjectSettings(); +} + +void MainFrame::OnFilePointfile() +{ + if (g_qeglobals.d_pointfile_display_list) + Pointfile_Clear (); + else + Pointfile_Check (); +} + +void MainFrame::OnMru(unsigned int nID) +{ + if (ConfirmModified()) + MRU_Activate (nID - ID_FILE_RECENT1); +} + +void MainFrame::OnFileExit() +{ + if (ConfirmModified()) + { + // stop printing during shutdown + // NOTE: we should cleanly release GL contexts and stuff when exiting + + OnDelete(); + + g_qeglobals_gui.d_edit = NULL; + gtk_widget_destroy (m_pWidget); + } +} + +void MainFrame::OnFileCheckUpdate() + +{ + // build the URL + Str URL; + URL = "http://www.qeradiant.com/index.php?data=dlupdate&query_dlup=1"; +#ifdef _WIN32 + URL += "&OS_dlup=1"; +#else + URL += "&OS_dlup=2"; +#endif + URL += "&Version_dlup=" RADIANT_VERSION; + g_PrefsDlg.mGamesDialog.AddPacksURL(URL); + OpenURL(URL.GetBuffer()); +} + +void MainFrame::OnEditUndo() +{ + Undo_Undo(); +} + +void MainFrame::OnEditRedo() +{ + Undo_Redo(); +} + +void MainFrame::OnEditCopybrush() +{ + Copy(); +} + +void MainFrame::OnEditPastebrush() +{ + Select_Deselect(); + + Undo_Start("paste"); + + Paste(); + + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnEditPastebrushToCamera() +{ + Select_Deselect(); + if (ActiveXY()) + { + vec3_t mid, camorigin, delta; + + ActiveXY()->Paste(); + + // Work out the delta + Select_GetMid( mid ); + + // Snap camera origin to grid + VectorCopy( m_pCamWnd->Camera()->origin, camorigin ); + camorigin[0] = floor(camorigin[0] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + camorigin[1] = floor(camorigin[1] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + camorigin[2] = floor(camorigin[2] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + + VectorSubtract( camorigin, mid, delta ); + + // Move to camera + Select_Move( delta, false ); + + Undo_Start("paste to camera"); + Undo_EndBrushList(&selected_brushes); + Undo_End(); + } +} + +void MainFrame::OnSelectionDelete() +{ + brush_t *brush; + //if (ActiveXY()) + // ActiveXY()->UndoCopy(); + Undo_Start("delete"); + Undo_AddBrushList(&selected_brushes); + //add all deleted entities to the undo + for (brush = selected_brushes.next; brush != &selected_brushes; brush = brush->next) + { + Undo_AddEntity(brush->owner); + } + // NOTE: Select_Delete does NOT delete entities + Select_Delete(); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnEditMapinfo() +{ + DoMapInfo (); +} + +void MainFrame::OnEditEntityinfo() +{ + DoEntityList (); +} + +void MainFrame::OnBrushScripts() +{ + DoScriptsDlg (); +} + +void MainFrame::OnEditLoadprefab() +{ + const char *filename; + CString CurPath; + + if (g_PrefsDlg.m_strPrefabPath.GetLength() > 0) + { + CurPath = g_PrefsDlg.m_strPrefabPath; + AddSlash (CurPath); + } + + filename = file_dialog (m_pWidget, TRUE, "Import Prefab", CurPath.GetBuffer(), MAP_MAJOR); + + if (filename != NULL) + { + Map_ImportFile(filename); + } +} + +void MainFrame::OnEditSaveprefab() +{ + const char *filename; + CString CurPath; + + if (g_PrefsDlg.m_strPrefabPath.GetLength() > 0) + { + CurPath = g_PrefsDlg.m_strPrefabPath; + } else + { + char tmp[PATH_MAX]; + getcwd (tmp, PATH_MAX); + CurPath = tmp; + } + AddSlash (CurPath); + + filename = file_dialog (m_pWidget, FALSE, "Export Prefab", CurPath.GetBuffer(), MAP_MAJOR); + if (filename != NULL) + { + Map_SaveSelected(filename); + } +} + +void MainFrame::OnPrefs() +{ + int nView = g_PrefsDlg.m_nView; + bool bToolbar = g_PrefsDlg.m_bWideToolbar; + bool bPluginToolbar = g_PrefsDlg.m_bPluginToolbar; + int nShader = g_PrefsDlg.m_nShader; + int nTextureQuality = g_PrefsDlg.m_nTextureQuality; + int nLightRadiuses = g_PrefsDlg.m_nLightRadiuses; + g_PrefsDlg.LoadPrefs(); + + if (g_PrefsDlg.DoModal() == IDOK) + { + if ((g_PrefsDlg.m_nLatchedView != nView) || + (g_PrefsDlg.m_bLatchedDetachableMenus != g_PrefsDlg.m_bDetachableMenus) || + (g_PrefsDlg.m_bLatchedWideToolbar != bToolbar) || + (g_PrefsDlg.m_bLatchedPatchToolbar != bToolbar) || + (g_PrefsDlg.m_bLatchedPluginToolbar != bPluginToolbar) || + (g_PrefsDlg.m_nLatchedShader != nShader) || + (g_PrefsDlg.m_nLatchedTextureQuality != nTextureQuality) + || (g_PrefsDlg.m_bLatchedFloatingZ != g_PrefsDlg.m_bFloatingZ) + ) + gtk_MessageBox(m_pWidget, "You must restart Radiant for the changes to take effect."); + + // if the view mode was switched to floating, set the Z window on by default + // this was originally intended as a bug fix, but the fix is elsewhere .. anyway making sure we force Z on each time is good + // (and we simply hope there will be a SavePrefs before we die) + if ((g_PrefsDlg.m_nView != nView) && ((EViewStyle)g_PrefsDlg.m_nView == (EViewStyle)eFloating)) + { + g_PrefsDlg.m_bZVis = true; + } + + if (m_pTexWnd) + m_pTexWnd->UpdatePrefs(); + + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_snaptogrid")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + (!g_PrefsDlg.m_bNoClamp) ? TRUE : FALSE); + g_bIgnoreCommands--; + } +} + +void MainFrame::OnTogglecamera() +{ + if (CurrentStyle() == eFloating) // floating views + { + if (m_pCamWnd && m_pCamWnd->m_pParent) + { + if (GTK_WIDGET_VISIBLE (m_pCamWnd->m_pParent)) + widget_delete_hide (m_pCamWnd->m_pParent); + else + gtk_widget_show (m_pCamWnd->m_pParent); + } + } else + { + if (GTK_WIDGET_VISIBLE (m_pCamWnd->GetWidget ())) + gtk_widget_hide (m_pCamWnd->GetWidget ()); + else + gtk_widget_show (m_pCamWnd->GetWidget ()); + } +} + +void MainFrame::OnToggleconsole() +{ + if (FloatingGroupDialog()) // QE4 style + { + if (inspector_mode == W_CONSOLE) + { + if (GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity)) + widget_delete_hide (g_qeglobals_gui.d_entity); + else + gtk_widget_show (g_qeglobals_gui.d_entity); + } else + { + gtk_widget_show (g_qeglobals_gui.d_entity); + SetInspectorMode(W_CONSOLE); + } + } +} + +// trigger the entity inspector on/off +void MainFrame::OnViewEntity() +{ + // make sure we're working with the current selection (bugzilla #436) + if( ! GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity)) + Select_Reselect(); + + if (!FloatingGroupDialog()) + { + if (GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity) && inspector_mode == W_ENTITY) + widget_delete_hide (g_qeglobals_gui.d_entity); + else + { + gtk_widget_show (g_qeglobals_gui.d_entity); + SetInspectorMode(W_ENTITY); + } + } else + { + if (inspector_mode == W_ENTITY) + { + if (GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity)) + widget_delete_hide (g_qeglobals_gui.d_entity); + else + gtk_widget_show (g_qeglobals_gui.d_entity); + } else + { + gtk_widget_show (g_qeglobals_gui.d_entity); + SetInspectorMode(W_ENTITY); + } + } +} + +void MainFrame::OnViewGroups() +{ + if (!FloatingGroupDialog()) + { + if (GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity) && inspector_mode == W_GROUP) + widget_delete_hide (g_qeglobals_gui.d_entity); + else + { + gtk_widget_show (g_qeglobals_gui.d_entity); + SetInspectorMode(W_GROUP); + } + } else + { + if (inspector_mode == W_GROUP && CurrentStyle() != MainFrame::eFloating) + { + if (GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity)) + widget_delete_hide (g_qeglobals_gui.d_entity); + else + gtk_widget_show (g_qeglobals_gui.d_entity); + } else + { + gtk_widget_show (g_qeglobals_gui.d_entity); + SetInspectorMode(W_GROUP); + } + } +} + +void MainFrame::OnToggleview() +{ + if (CurrentStyle() == eFloating) // QE4 style + { + if (m_pXYWnd && m_pXYWnd->m_pParent) + { + if (GTK_WIDGET_VISIBLE (m_pXYWnd->m_pParent)) + widget_delete_hide (m_pXYWnd->m_pParent); + else + gtk_widget_show (m_pXYWnd->m_pParent); + } + } +} + +void MainFrame::OnToggleviewXz() +{ + if (CurrentStyle() == eFloating) // QE4 style + { + if (m_pXZWnd && m_pXZWnd->m_pParent) + { + // get windowplacement doesn't actually save this so we will here + g_PrefsDlg.m_bXZVis = GTK_WIDGET_VISIBLE (m_pXZWnd->m_pParent); + if (g_PrefsDlg.m_bXZVis) + widget_delete_hide (m_pXZWnd->m_pParent); + else + gtk_widget_show (m_pXZWnd->m_pParent); + g_PrefsDlg.m_bXZVis ^= 1; + g_PrefsDlg.SavePrefs (); + } + } +} + +void MainFrame::OnToggleviewYz() +{ + if (CurrentStyle() == eFloating) // QE4 style + { + if (m_pYZWnd && m_pYZWnd->m_pParent) + { + g_PrefsDlg.m_bYZVis = GTK_WIDGET_VISIBLE (m_pYZWnd->m_pParent); + if (g_PrefsDlg.m_bYZVis) + widget_delete_hide (m_pYZWnd->m_pParent); + else + gtk_widget_show (m_pYZWnd->m_pParent); + g_PrefsDlg.m_bYZVis ^= 1; + g_PrefsDlg.SavePrefs (); + } + } +} + +void MainFrame::OnTogglez() +{ + if ( g_pParentWnd->FloatingGroupDialog() ) // QE4 style + { + if (m_pZWnd && m_pZWnd->m_pParent) + { + if (GTK_WIDGET_VISIBLE (m_pZWnd->m_pParent)) + widget_delete_hide (m_pZWnd->m_pParent); + else + gtk_widget_show (m_pZWnd->m_pParent); + g_PrefsDlg.m_bZVis ^= 1; + g_PrefsDlg.SavePrefs (); + } + } else { + Sys_FPrintf( SYS_WRN, "Z view toggle is only valid in floating views\n" ); + } +} + +void MainFrame::OnViewCenter() +{ + m_pCamWnd->Camera()->angles[ROLL] = m_pCamWnd->Camera()->angles[PITCH] = 0; + m_pCamWnd->Camera()->angles[YAW] = 22.5 * floor((m_pCamWnd->Camera()->angles[YAW]+11)/22.5); + Sys_UpdateWindows (W_CAMERA | W_XY_OVERLAY); +} + +void MainFrame::OnViewUpfloor() +{ + m_pCamWnd->Cam_ChangeFloor (true); +} + +void MainFrame::OnViewDownfloor() +{ + m_pCamWnd->Cam_ChangeFloor (false); +} + +void MainFrame::OnViewCenterview() +{ + if(CurrentStyle() == eSplit) + { + GetXYWnd()->PositionView(); + GetXZWnd()->PositionView(); + GetYZWnd()->PositionView(); + Sys_UpdateWindows (W_XY|W_XZ|W_YZ); + } + else { + m_pXYWnd->PositionView(); + Sys_UpdateWindows (W_XY); + } +} + +void MainFrame::OnViewNextview() +{ + if (CurrentStyle() == eSplit) + { + GetXYWnd()->PositionView(); + GetXZWnd()->PositionView(); + GetYZWnd()->PositionView(); + Sys_UpdateWindows (W_XY|W_XZ|W_YZ); + } + else { + if (m_pXYWnd->GetViewType() == XY) + m_pXYWnd->SetViewType(XZ); + else + if (m_pXYWnd->GetViewType() == XZ) + m_pXYWnd->SetViewType(YZ); + else + m_pXYWnd->SetViewType(XY); + m_pXYWnd->PositionView(); + Sys_UpdateWindows (W_XY); + } +} + +void MainFrame::OnViewXy() +{ + if(!FloatingGroupDialog()) + { + m_pXYWnd->SetViewType(XY); + m_pXYWnd->PositionView(); + } + Sys_UpdateWindows (W_XY); +} + +void MainFrame::OnViewSide() +{ + if (!FloatingGroupDialog()) + { + m_pXYWnd->SetViewType(XZ); + m_pXYWnd->PositionView(); + } + Sys_UpdateWindows (W_XY); +} + +void MainFrame::OnViewFront() +{ + if (!FloatingGroupDialog()) + { + m_pXYWnd->SetViewType(YZ); + m_pXYWnd->PositionView(); + } + Sys_UpdateWindows (W_XY); +} + +void MainFrame::OnView100() +{ + if (m_pXYWnd) + m_pXYWnd->SetScale(1); + if (m_pXZWnd) + m_pXZWnd->SetScale(1); + if (m_pYZWnd) + m_pYZWnd->SetScale(1); + Sys_UpdateWindows (W_XY|W_XY_OVERLAY); +} + +void MainFrame::OnViewZoomin() +{ + if (m_pXYWnd && m_pXYWnd->Active()) + { + m_pXYWnd->SetScale(m_pXYWnd->Scale() * 5.0 / 4); + if (m_pXYWnd->Scale() > 30) + m_pXYWnd->SetScale(30); + } + + if (m_pXZWnd && m_pXZWnd->Active()) + { + m_pXZWnd->SetScale(m_pXZWnd->Scale() * 5.0 / 4); + if (m_pXZWnd->Scale() > 30) + m_pXZWnd->SetScale(30); + } + + if (m_pYZWnd && m_pYZWnd->Active()) + { + m_pYZWnd->SetScale(m_pYZWnd->Scale() * 5.0 / 4); + if (m_pYZWnd->Scale() > 30) + m_pYZWnd->SetScale(30); + } + + Sys_UpdateWindows (W_XY|W_XY_OVERLAY); +} + +// NOTE: the zoom out factor is 4/5, we could think about customizing it +// we don't go below a zoom factor corresponding to 10% of the max world size +// (this has to be computed against the window size) +void MainFrame::OnViewZoomout() +{ + float min_scale; + if (m_pXYWnd && m_pXYWnd->Active()) + { + m_pXYWnd->SetScale(m_pXYWnd->Scale() * 4.0 / 5); + min_scale = MIN(m_pXYWnd->Width(),m_pXYWnd->Height()) / ( 1.1 * (g_MaxWorldCoord-g_MinWorldCoord)); + if (m_pXYWnd->Scale() < min_scale) m_pXYWnd->SetScale (min_scale); + } + + if (m_pXZWnd && m_pXZWnd->Active()) + { + m_pXZWnd->SetScale(m_pXZWnd->Scale() * 4.0 / 5); + min_scale = MIN(m_pXZWnd->Width(),m_pXZWnd->Height()) / ( 1.1 * (g_MaxWorldCoord-g_MinWorldCoord)); + if (m_pXZWnd->Scale() < min_scale) m_pXZWnd->SetScale (min_scale); + } + + if (m_pYZWnd && m_pYZWnd->Active()) + { + m_pYZWnd->SetScale(m_pYZWnd->Scale() * 4.0 / 5); + min_scale = MIN(m_pYZWnd->Width(),m_pYZWnd->Height()) / ( 1.1 * (g_MaxWorldCoord-g_MinWorldCoord)); + if (m_pYZWnd->Scale() < min_scale) m_pYZWnd->SetScale (min_scale); + } + Sys_UpdateWindows (W_XY|W_XY_OVERLAY); +} + +void MainFrame::OnViewZ100() +{ + z.scale = 1; + Sys_UpdateWindows (W_Z|W_Z_OVERLAY); +} + +void MainFrame::OnViewZzoomin() +{ + z.scale *= 5.0/4; + if (z.scale > 4) + z.scale = 4; + Sys_UpdateWindows (W_Z|W_Z_OVERLAY); +} + +void MainFrame::OnViewZzoomout() +{ + z.scale *= 4.0f/5; + if (z.scale < 0.125) + z.scale = 0.125; + Sys_UpdateWindows (W_Z|W_Z_OVERLAY); +} + +void MainFrame::OnViewCubein() +{ + g_PrefsDlg.m_nCubicScale--; + if (g_PrefsDlg.m_nCubicScale < 1) + g_PrefsDlg.m_nCubicScale = 1; + g_PrefsDlg.SavePrefs (); + Sys_UpdateWindows(W_CAMERA); + SetGridStatus(); +} + +void MainFrame::OnViewCubeout() +{ + g_PrefsDlg.m_nCubicScale++; + if (g_PrefsDlg.m_nCubicScale > 22) + g_PrefsDlg.m_nCubicScale = 22; + g_PrefsDlg.SavePrefs (); + Sys_UpdateWindows(W_CAMERA); + SetGridStatus(); +} + +void MainFrame::OnViewShownames() +{ + g_qeglobals.d_savedinfo.show_names = !g_qeglobals.d_savedinfo.show_names; + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_shownames")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + g_qeglobals.d_savedinfo.show_names ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows (W_XY); +} + +void MainFrame::OnViewShowAngles() +{ + g_qeglobals.d_savedinfo.show_angles = !g_qeglobals.d_savedinfo.show_angles; + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showangles")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + g_qeglobals.d_savedinfo.show_angles ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows (W_XY); +} + +void MainFrame::OnViewShowblocks() +{ + g_qeglobals.show_blocks ^= 1; + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showblocks")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_qeglobals.show_blocks ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows (W_XY); +} + +void MainFrame::OnViewShowcoordinates() +{ + g_qeglobals.d_savedinfo.show_coordinates ^= 1; + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showcoordinates")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + g_qeglobals.d_savedinfo.show_coordinates ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows (W_XY|W_Z); +} + +void MainFrame::OnViewShowOutline() +{ + g_qeglobals.d_savedinfo.show_outline ^= 1; + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showoutline")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + g_qeglobals.d_savedinfo.show_outline ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows (W_XY); +} + +void MainFrame::OnViewShowAxes() +{ + g_qeglobals.d_savedinfo.show_axis ^= 1; + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showaxes")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), + g_qeglobals.d_savedinfo.show_axis ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows (W_XY); +} + +void MainFrame::OnViewShowWorkzone() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_showworkzone")); + g_bIgnoreCommands++; + if (g_qeglobals.d_show_work) + { + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_qeglobals.d_show_work = false; + } else + { + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + g_qeglobals.d_show_work = true; + } + g_bIgnoreCommands--; + Sys_UpdateWindows (W_XY); +} + +void MainFrame::OnViewHideshowHideselected() +{ + Select_Hide(); + Select_Deselect(); +} + +void MainFrame::OnViewHideshowShowhidden() +{ + Select_ShowAllHidden(); +} + +/** +sets the view mode for the entities +called upon LoadPrefs too +NOTE TTimo previous implementation had a SavePrefs call + .. I don't think it is relevant, removed (the prefs are saved upon exit) +NOTE TTimo we activate the menu item, this is only needed when we are called upon a prefs load + (otherwise we are always called following user action on the widget) +*/ +void MainFrame::OnEntitiesSetViewAs(int mode) +{ + gpointer item = NULL; + if (mode == 0) + { + switch (g_PrefsDlg.m_nEntityShowState) + { + case ENTITY_BOX: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_boundingbox"); + break; + case ENTITY_WIRE: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_wireframe"); + break; + case ENTITY_SELECTED: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_selectedwireframe"); + break; + case ENTITY_SELECTED_SKIN: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_selectedskinned"); + break; + case ENTITY_SKINNED: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_skinned"); + break; + case ENTITY_SKINNED_BOXED: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_skinnedandboxed"); + break; + } + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + g_bIgnoreCommands--; + return; + } + + switch (mode) + { + case ID_VIEW_ENTITIESAS_BOUNDINGBOX: + g_PrefsDlg.m_nEntityShowState = ENTITY_BOX; + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_boundingbox"); + break; + case ID_VIEW_ENTITIESAS_WIREFRAME: + g_PrefsDlg.m_nEntityShowState = ENTITY_WIRE; + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_wireframe"); + break; + case ID_VIEW_ENTITIESAS_SELECTEDWIREFRAME: + g_PrefsDlg.m_nEntityShowState = ENTITY_SELECTED; + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_selectedwireframe"); + break; + case ID_VIEW_ENTITIESAS_SELECTEDSKINNED: + g_PrefsDlg.m_nEntityShowState = ENTITY_SELECTED_SKIN; + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_selectedskinned"); + break; + case ID_VIEW_ENTITIESAS_SKINNED: + g_PrefsDlg.m_nEntityShowState = ENTITY_SKINNED; + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_skinned"); + break; + case ID_VIEW_ENTITIESAS_SKINNEDANDBOXED: + g_PrefsDlg.m_nEntityShowState = ENTITY_SKINNED_BOXED; + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_entitiesas_skinnedandboxed"); + break; + default: + Sys_FPrintf(SYS_ERR, "Entity mode ID_ not found in MainFrame::Entities_SetViewAs\n"); + return; + } + + if (!item) + { + Sys_FPrintf(SYS_ERR, "menu not found in MainFrame::Entities_SetViewAs\n"); + return; + } + + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + g_bIgnoreCommands--; + + Sys_UpdateWindows(W_ALL); +} + +void MainFrame::OnViewCubicclipping() +{ + GtkWidget *w; + + g_PrefsDlg.m_bCubicClipping ^= 1; + g_bIgnoreCommands++; + w = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_cubicclipping")); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), g_PrefsDlg.m_bCubicClipping ? TRUE : FALSE); + w = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_view_cubicclipping")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), g_PrefsDlg.m_bCubicClipping ? TRUE : FALSE); + g_bIgnoreCommands--; + g_PrefsDlg.SavePrefs (); + //Map_BuildBrushData (); + Sys_UpdateWindows(W_CAMERA); +} + +void MainFrame::OnViewOpengllighting() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_opengllighting")); + g_PrefsDlg.m_bGLLighting ^= 1; + g_PrefsDlg.SavePrefs (); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bGLLighting ? TRUE : FALSE); + Sys_UpdateWindows (W_XY|W_CAMERA); + g_bIgnoreCommands--; +} + +void MainFrame::OnSelectionDragedges() +{ + if (g_qeglobals.d_select_mode == sel_edge) + { + g_qeglobals.d_select_mode = sel_brush; + Sys_UpdateWindows (W_ALL); + } else + { + SetupVertexSelection (); + if (g_qeglobals.d_numpoints) + g_qeglobals.d_select_mode = sel_edge; + Sys_UpdateWindows (W_ALL); + } +} + +void MainFrame::OnSelectionDragvertecies() +{ + if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_curvepoint) + { + g_qeglobals.d_select_mode = sel_brush; + Sys_UpdateWindows (W_ALL); + } else + { + //--if (QE_SingleBrush() && selected_brushes.next->patchBrush) + if (OnlyPatchesSelected()) + { + Patch_EditPatch(); + } else //if (!AnyPatchesSelected()) // allows vertex mode when patches are selected + { + SetupVertexSelection (); + if (g_qeglobals.d_numpoints) + g_qeglobals.d_select_mode = sel_vertex; + } + Sys_UpdateWindows (W_ALL); + } +} + +void MainFrame::OnSelectionClone() +{ + Select_Clone(); +} + +// called when the escape key is used (either on the main window or on an inspector) +void MainFrame::OnSelectionDeselect() +{ + if (g_bClipMode) + OnViewClipper(); + else + if (g_bRotateMode) + OnSelectMouserotate(); + else + if (g_bScaleMode) + OnSelectMousescale(); + else + if (g_bPathMode) + { + if (ActiveXY()) + ActiveXY()->KillPathMode(); + } else + { + if (g_qeglobals.d_select_mode == sel_curvepoint && g_qeglobals.d_num_move_points > 0) + { + g_qeglobals.d_num_move_points = 0; + Sys_UpdateWindows(W_ALL); + } else + { + Select_Deselect (); + SetStatusText(2, " "); + } + } +} + +void MainFrame::OnBrushFlipx() +{ + Undo_Start("flip X"); + Undo_AddBrushList(&selected_brushes); + + Select_FlipAxis (0); + // spog - this does not work - it's a rotate not a flip + /* + for (brush_t *b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + if(b->owner->eclass->fixedsize) + { + char buf[16]; + float a = FloatForKey(b->owner, "angle"); + a = div ((int)(180 - a), 180).rem; + sprintf (buf, "%d", (int)a); + SetKeyValue(b->owner, "angle", buf); + Brush_Build(b,true,true,false,false); // don't filter + } + } + */ + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrushFlipy() +{ + Undo_Start("flip Y"); + Undo_AddBrushList(&selected_brushes); + + Select_FlipAxis (1); + // spog - this does not work - it's a rotate not a flip + /* + for (brush_t *b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + if(b->owner->eclass->fixedsize) + { + float a = FloatForKey(b->owner, "angle"); + if (a == 0 || a == 180 || a == 360) + continue; + if ( a == 90 || a == 270) + { + a += 180; + } + else if (a > 270) + a += 90; + else if (a > 180) + a -= 90; + else if (a > 90) + a += 90; + else + a -= 90; + a = (int)a % 360; + char buf[16]; + sprintf (buf, "%d", (int)a); + SetKeyValue(b->owner, "angle", buf); + Brush_Build(b,true,true,false,false); // don't filter + } + + } + */ + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrushFlipz() +{ + Undo_Start("flip Z"); + Undo_AddBrushList(&selected_brushes); + Select_FlipAxis (2); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrushRotatex() +{ + Undo_Start("rotate X"); + Undo_AddBrushList(&selected_brushes); + Select_RotateAxis (0, 90); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrushRotatey() +{ + Undo_Start("rotate Y"); + Undo_AddBrushList(&selected_brushes); + Select_RotateAxis (1, 90); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrushRotatez() +{ + Undo_Start("rotate Z"); + Undo_AddBrushList(&selected_brushes); + Select_RotateAxis (2, 90); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectionArbitraryrotation() +{ + Undo_Start("arbitrary rotation"); + Undo_AddBrushList(&selected_brushes); + + DoRotateDlg (); + + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectScale() +{ + Undo_Start("scale"); + Undo_AddBrushList(&selected_brushes); + DoScaleDlg (); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectionMakehollow() +{ + //if (ActiveXY()) + // ActiveXY()->UndoCopy(); + Undo_Start("hollow"); + Undo_AddBrushList(&selected_brushes); + CSG_MakeHollow (); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectionCsgsubtract() +{ + Undo_Start("CSG subtract"); + CSG_Subtract(); + Undo_End(); +} + +void MainFrame::OnSelectionCsgmerge() +{ + Undo_Start("CSG merge"); + Undo_AddBrushList(&selected_brushes); + CSG_Merge(); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectionNoOutline() +{ + //g_qeglobals.d_savedinfo.bNoSelectedOutlines ^= 1; + g_qeglobals.d_savedinfo.iSelectedOutlinesStyle = (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_ZBUF) ^ OUTLINE_ZBUF; + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_selection_nooutline")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_ZBUF)); + g_bIgnoreCommands--; + Sys_UpdateWindows (W_CAMERA); +} + +void MainFrame::OnSelectionOutlineStyle() +{ + if ((g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_ZBUF) && (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_BSEL)) + g_qeglobals.d_savedinfo.iSelectedOutlinesStyle &= ~OUTLINE_ZBUF; + else if (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_BSEL) + g_qeglobals.d_savedinfo.iSelectedOutlinesStyle &= ~OUTLINE_BSEL; + else if (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_ZBUF) + g_qeglobals.d_savedinfo.iSelectedOutlinesStyle |= OUTLINE_BSEL; + else + g_qeglobals.d_savedinfo.iSelectedOutlinesStyle |= OUTLINE_ZBUF; + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_selection_nooutline")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (g_qeglobals.d_savedinfo.iSelectedOutlinesStyle & OUTLINE_ZBUF)); + g_bIgnoreCommands--; + Sys_UpdateWindows (W_CAMERA); +} + +void MainFrame::OnSelectionSelectcompletetall() +{ + if (ActiveXY()) + ActiveXY()->UndoCopy(); + Select_CompleteTall (); +} + +void MainFrame::OnSelectionSelecttouching() +{ + Select_Touching(); +} + +void MainFrame::OnSelectionSelectpartialtall() +{ + Select_PartialTall(); +} + +void MainFrame::OnSelectionSelectinside() +{ + Select_Inside (); +} + +void MainFrame::OnViewClipper() +{ + GtkWidget *w = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_view_clipper")); + g_bIgnoreCommands++; + + if (ActiveXY()) + { + if (ActiveXY()->ClipMode()) + { + ActiveXY()->SetClipMode(false); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), FALSE); + } else + { + if (ActiveXY()->RotateMode()) + OnSelectMouserotate(); + ActiveXY()->SetClipMode(true); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), TRUE); + } + } + g_bIgnoreCommands--; +} + +void MainFrame::OnClipSelected() +{ + if (m_pActiveXY && m_pActiveXY->ClipMode()) + { + Undo_Start("clip selected"); + Undo_AddBrushList(&selected_brushes); + m_pActiveXY->Clip(); + Undo_EndBrushList(&selected_brushes); + Undo_End(); + } else + { + if (g_bPatchBendMode) + Patch_BendHandleENTER(); +// else if (g_bPatchBendMode) +// Patch_InsDelHandleENTER(); + } +} + +void MainFrame::OnSplitSelected() +{ + if (m_pActiveXY) + { + Undo_Start("split selected"); + Undo_AddBrushList(&selected_brushes); + m_pActiveXY->SplitClip(); + Undo_EndBrushList(&selected_brushes); + Undo_End(); + } +} + +void MainFrame::OnFlipClip() +{ + if (m_pActiveXY) + m_pActiveXY->FlipClip(); +} + +void MainFrame::OnSelectionConnect() +{ + Undo_Start("connect selected entities"); + Undo_AddBrushList(&selected_brushes); + ConnectEntities(); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectionUngroupentity() +{ + Undo_Start("ungroup selected entities"); + Undo_AddBrushList(&selected_brushes); + Select_Ungroup(); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectionMergeentity() +{ + Undo_Start("merge entity"); + Undo_AddBrushList(&selected_brushes); + Select_MergeEntity(); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectionGroupworld() +{ + Undo_Start("group world"); + Undo_AddBrushList(&selected_brushes); + Select_GroupEntity(world_entity); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectionMakeDetail() +{ + Undo_Start("make detail"); + Undo_AddBrushList(&selected_brushes); + Select_MakeDetail (); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectionMakeStructural() +{ + Undo_Start("make structural"); + Undo_AddBrushList(&selected_brushes); + Select_MakeStructural (); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBspCommand (unsigned int nID) +{ + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=503 + // make sure we don't attempt to region compile a map with the camera outside the region + if (region_active) + { + vec3_t vOrig; + VectorSet(vOrig, + (int)g_pParentWnd->GetCamWnd()->Camera()->origin[0], + (int)g_pParentWnd->GetCamWnd()->Camera()->origin[1], + (int)g_pParentWnd->GetCamWnd()->Camera()->origin[2]); + + int i; + for (i=0 ; i<3 ; i++) + { + if (vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i]) + { + Sys_FPrintf(SYS_ERR, "The camera must be in the region to start a region compile.\n"); + return; + } + } + } + + // if the map has not been saved yet we need to handle it now before we start processing the BSP commands + if (stricmp( currentmap, "unnamed.map") == 0) + { + OnFileSaveas(); + } + + if (g_PrefsDlg.m_bSnapShots && (stricmp (currentmap, "unnamed.map") != 0)) + Map_Snapshot(); + + if (g_qeglobals.bBSPFrontendPlugin) + { + char *cmd = (char*)g_slist_nth_data (g_BSPFrontendCommands, nID-CMD_BSPCOMMAND); + g_BSPFrontendTable.m_pfnDispatchBSPCommand (cmd); + } else + { + RunBsp (bsp_commands[nID-CMD_BSPCOMMAND]); + } +} + +void MainFrame::OnGrid (unsigned int nID) +{ + if (nID == ID_GRID_025) + { + g_qeglobals.d_gridsize = 0.25f; + g_qeglobals.d_bSmallGrid = true; + } else if (nID == ID_GRID_05) + { + g_qeglobals.d_gridsize = 0.5f; + g_qeglobals.d_bSmallGrid = true; + } else + { + switch (nID) + { + case ID_GRID_1: g_qeglobals.d_gridsize = 0; break; + case ID_GRID_2: g_qeglobals.d_gridsize = 1; break; + case ID_GRID_4: g_qeglobals.d_gridsize = 2; break; + case ID_GRID_8: g_qeglobals.d_gridsize = 3; break; + case ID_GRID_16: g_qeglobals.d_gridsize = 4; break; + case ID_GRID_32: g_qeglobals.d_gridsize = 5; break; + case ID_GRID_64: g_qeglobals.d_gridsize = 6; break; + case ID_GRID_128: g_qeglobals.d_gridsize = 7; break; + case ID_GRID_256: g_qeglobals.d_gridsize = 8; break; + } + g_qeglobals.d_gridsize = 1 << (int)g_qeglobals.d_gridsize; + g_qeglobals.d_bSmallGrid = false; + } + + SetGridStatus(); + + // SnapTToGrid option: need to check everywhere the grid size is changed + // this is a bit clumsy, have to do in OnGrid OnGridPrev and OnGridNext + if (g_PrefsDlg.m_bSnapTToGrid) + DoSnapTToGrid(); + + Sys_UpdateWindows (W_XY|W_Z); +} + +void MainFrame::OnSnaptogrid() +{ + g_PrefsDlg.m_bNoClamp ^= 1; + g_PrefsDlg.SavePrefs (); + + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_snaptogrid")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bNoClamp ? FALSE : TRUE); + g_bIgnoreCommands--; +} + +void MainFrame::OnTexturesShowinuse() +{ + Sys_BeginWait (); + Texture_ShowInuse (); +#ifdef _DEBUG + if (!g_bShowAllShaders) + Sys_Printf("Already showing only in-use textures.\n"); +#endif + Sys_UpdateWindows( W_TEXTURE ); + Sys_EndWait (); +} + +void MainFrame::OnTexturesShowall() +{ + Texture_ShowAll(); +} + +// do some triggering on/off, if the inspector is already up then hide it +void MainFrame::OnTexturesInspector() +{ + ToggleSurface(); +} + +void MainFrame::OnViewNearest(unsigned int nID) +{ + Texture_SetMode(nID); +} + +void MainFrame::OnTextureReplaceall() +{ + FindTextureDialog::show(); +} + +void MainFrame::OnToggleLock() +{ + g_PrefsDlg.m_bTextureLock = !g_PrefsDlg.m_bTextureLock; + + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_toggle_lock")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bTextureLock ? TRUE : FALSE); + g_bIgnoreCommands--; + g_PrefsDlg.SavePrefs (); + SetGridStatus(); +} + +void MainFrame::OnToggleRotatelock() +{ + g_PrefsDlg.m_bRotateLock ^= 1; + + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_toggle_rotatelock")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bRotateLock ? TRUE : FALSE); + g_bIgnoreCommands--; + g_PrefsDlg.SavePrefs (); + SetGridStatus(); +} + +// use a dialog for direct selection of a texture menu +// the API is a bit crappy, we need to set texture_directory to the directory name in /textures/ +void MainFrame::OnTexturesLoad() +{ + char def_path[NAME_MAX]; + + // FIXME + // check if that works with fs_game (I suspect some more design is needed) + // see how this is done in 1.2? + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=507 + strcpy (def_path, g_pGameDescription->mEnginePath.GetBuffer()); + strcat (def_path, g_pGameDescription->mBaseGame.GetBuffer()); + strcat (def_path, "/"); + + char *dir = dir_dialog (m_pWidget, "Load textures from path", def_path); + + if (dir != NULL) + { + // very uncertain task, let's hope the guy pointed to somewhere below the dir we gave him + Sys_Printf("user select: '%s'\n", dir); + // remove a potential trailing slash? + if (dir[strlen(dir)-1]=='/' || dir[strlen(dir)-1]=='\\') + dir[strlen(dir)-1] = '\0'; + char *pouic = MAX(strrchr(dir, '/'),strrchr(dir, '\\')); + if (pouic) + { + strcpy(texture_directory, pouic+1); + Sys_Printf("Loading '%s'\n", texture_directory); + Texture_ShowDirectory(); + } + else + Sys_FPrintf(SYS_WRN, "Failed to extract the directory\n"); + g_free(dir); + } + else + Sys_FPrintf(SYS_WRN, "texture load dialog cancelled\n"); +} + +void MainFrame::OnTexturesReloadshaders() +{ + Sys_BeginWait (); + QERApp_ReloadShaders(); + // current shader + // NOTE: we are kinda making it loop on itself, it will update the pShader and scroll the texture window + Texture_SetTexture (&g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef, false, NULL, false); + Sys_UpdateWindows (W_ALL); + Sys_EndWait(); +} + +void MainFrame::OnTexturesShadersShow() +{ + g_PrefsDlg.m_bShowShaders ^= 1; + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_shaders_show")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bShowShaders ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows(W_TEXTURE); +} + +void MainFrame::SetTextureScale(int id) +{ + GtkWidget *item; + + switch (id) + { + case ID_TEXTURES_TEXTUREWINDOWSCALE_10: + g_PrefsDlg.m_nTextureScale = 10; + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_texturewindowscale_10")); + break; + case ID_TEXTURES_TEXTUREWINDOWSCALE_25: + g_PrefsDlg.m_nTextureScale = 25; + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_texturewindowscale_25")); + break; + case ID_TEXTURES_TEXTUREWINDOWSCALE_50: + g_PrefsDlg.m_nTextureScale = 50; + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_texturewindowscale_50")); + break; + case ID_TEXTURES_TEXTUREWINDOWSCALE_200: + g_PrefsDlg.m_nTextureScale = 200; + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_texturewindowscale_200")); + break; + default: + g_PrefsDlg.m_nTextureScale = 100; + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_textures_texturewindowscale_100")); + break; + } + + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + g_bIgnoreCommands--; + + Texture_ResetPosition(); +} + +void MainFrame::OnTexturewindowScaleup() +{ + switch(g_PrefsDlg.m_nTextureScale) { + // 200, all the way in, don't do anything + case 100: + SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_200); + break; + case 50: + SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_100); + break; + case 25: + SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_50); + break; + case 10: + SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_25); + break; + } +} + +void MainFrame::OnTexturewindowScaledown() +{ + switch(g_PrefsDlg.m_nTextureScale) { + case 200: + SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_100); + break; + case 100: + SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_50); + break; + case 50: + SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_25); + break; + case 25: + SetTextureScale(ID_TEXTURES_TEXTUREWINDOWSCALE_10); + break; + // 10, all the way out, don't do anything + } +} + +void MainFrame::OnTexturesLoadlist() +{ + DoTextureListDlg (); +} + +void MainFrame::OnTexturesShaderlistonly() +{ + g_PrefsDlg.m_bTexturesShaderlistOnly ^= 1; + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget),"menu_textures_shaderlistonly")); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bTexturesShaderlistOnly ? TRUE : FALSE); + g_bIgnoreCommands--; + FillTextureMenu(); +} + +void MainFrame::OnTextureWad(unsigned int nID) +{ + Sys_BeginWait (); + Texture_ShowDirectory (nID); + Sys_UpdateWindows (W_ALL); + Sys_EndWait (); +} + +void MainFrame::OnMiscBenchmark() +{ + m_pCamWnd->BenchMark(); +} + +void MainFrame::OnColorSetoriginal() +{ + for (int i=0 ; i<3 ; i++) + { + g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][i] = 0.25f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][i] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR][i] = 0.75f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR][i] = 0.5f; + g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][i] = 0.25f; + } + + //djbob + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR_ALT][0] = 0.5f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR_ALT][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR_ALT][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR_ALT][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR_ALT][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR_ALT][2] = 0.0f; + //-djbob + + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][2] = 1.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][2] = 1.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][0] = 0.5f; + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][2] = 0.75f; + + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][2] = 0.0f; + + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorSetqer() +{ + for (int i=0 ; i<3 ; i++) + { + g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][i] = 0.25f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][i] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR][i] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR][i] = 0.5f; + g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][i] = 0.25f; + } + + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][2] = 1.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][2] = 1.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][0] = 0.5f; + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][2] = 0.75f; + + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][2] = 0.0f; + + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorSetblack() +{ + for (int i=0 ; i<3 ; i++) + { + g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][i] = 0.25f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][i] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR][i] = 0.2f; + g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][i] = 0.25f; + } + + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR][0] = 0.3f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR][1] = 0.5f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR][2] = 0.5f; + + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][2] = 1.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][1] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][2] = 1.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][2] = 1.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][1] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][2] = 1.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][0] = 0.7f; + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][1] = 0.7f; + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][2] = 0.0f; + + Sys_UpdateWindows (W_ALL); +} + +/* ydnar: to emulate maya/max/lightwave color schemes */ +void MainFrame::OnColorSetydnar() +{ + for (int i=0 ; i<3 ; i++) + { + g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][i] = 0.25f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][i] = 0.77f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR][i] = 0.83f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR][i] = 0.89f; + g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][i] = 0.25f; + } + + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][1] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK][2] = 1.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER][2] = 1.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][0] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES][2] = 0.0f; + + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][0] = 0.5f; + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME][2] = 0.75f; + + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][0] = 1.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][1] = 0.0f; + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES3D][2] = 0.0f; + + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnTexturebk() +{ + DoColor(COLOR_TEXTUREBACK); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsXybk() +{ + DoColor(COLOR_GRIDBACK); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsMajor() +{ + DoColor(COLOR_GRIDMAJOR); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsMinor() +{ + DoColor(COLOR_GRIDMINOR); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsMajor_Alt() +{ + DoColor(COLOR_GRIDMAJOR_ALT); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsMinor_Alt() +{ + DoColor(COLOR_GRIDMINOR_ALT); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsGridtext() +{ + DoColor(COLOR_GRIDTEXT); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsGridblock() +{ + DoColor(COLOR_GRIDBLOCK); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsCameraBack() +{ + DoColor(COLOR_CAMERABACK); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsBrush() +{ + DoColor(COLOR_BRUSHES); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsSelectedbrush() +{ + DoColor(COLOR_SELBRUSHES); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsSelectedbrush3D() +{ + DoColor(COLOR_SELBRUSHES3D); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsClipper() +{ + DoColor(COLOR_CLIPPER); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnColorsViewname() +{ + DoColor(COLOR_VIEWNAME); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnMiscGamma() +{ + float fSave = g_qeglobals.d_savedinfo.fGamma; + DoGamma(); + if (fSave != g_qeglobals.d_savedinfo.fGamma) + { + gtk_MessageBox(m_pWidget, "You must restart Radiant for Gamma settings to take effect."); + } +} +void MainFrame::OnMiscFindbrush() +{ + DoFind(); +} + +void MainFrame::OnMiscNextleakspot() +{ + Pointfile_Next(); +} + +void MainFrame::OnMiscPreviousleakspot() +{ + Pointfile_Prev(); +} + +void MainFrame::OnMiscPrintxy() +{ +// WXY_Print(); +} + +void MainFrame::OnMiscSelectentitycolor() +{ + if (edit_entity) + { + CString strColor = ValueForKey(edit_entity, "_color"); + if (strColor.GetLength() > 0) + { + float fR, fG, fB; + int n = sscanf(strColor,"%f %f %f", &fR, &fG, &fB); + if (n == 3) + { + g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][0] = fR; + g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][1] = fG; + g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][2] = fB; + } + } + + if (inspector_mode == W_ENTITY && (DoColor(COLOR_ENTITY))) + { + char buffer[100]; + sprintf(buffer, "%f %f %f", g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][0], + g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][1], + g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][2]); + + gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntValueField]), buffer); + gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntKeyField]), "_color"); + AddProp(); + //DK - SOF change to get color to entity quickly + //--::SetWindowText( hwndEnt[EntValueField], buffer ); + //--::SetWindowText( hwndEnt[EntKeyField], "color" ); + //--AddProp(); + } + Sys_UpdateWindows( W_ALL ); + } +} + +void MainFrame::OnConvertcurves() +{ +#if 0 + Select_Deselect(); + for (brush_t* pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next) + { + if (pb->curveBrush) + { + for (face_t* f = pb->brush_faces ; f ; f=f->next) + { + if (f->texdef.contents & CONTENTS_LADDER) + { + f->texdef.contents &= ~CONTENTS_LADDER; + f->texdef.contents |= CONTENTS_NEGATIVE_CURVE; + } + } + } + } + Map_BuildBrushData(); +#endif +} + +void MainFrame::OnRegionOff() +{ + Map_RegionOff (); +} + +void MainFrame::OnRegionSetxy() +{ + Map_RegionXY (); +} + +void MainFrame::OnRegionSettallbrush() +{ + Map_RegionTallBrush (); +} + +void MainFrame::OnRegionSetbrush() +{ + Map_RegionBrush (); +} + +void MainFrame::OnRegionSetselection() +{ + Map_RegionSelectedBrushes (); +} + +void MainFrame::OnBrush3sided() +{ + Undo_Start("3 sided"); + Undo_AddBrushList(&selected_brushes); + Brush_MakeSided(3); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrush4sided() +{ + Undo_Start("4 sided"); + Undo_AddBrushList(&selected_brushes); + Brush_MakeSided(4); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrush5sided() +{ + Undo_Start("5 sided"); + Undo_AddBrushList(&selected_brushes); + Brush_MakeSided(5); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrush6sided() +{ + Undo_Start("6 sided"); + Undo_AddBrushList(&selected_brushes); + Brush_MakeSided(6); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrush7sided() +{ + Undo_Start("7 sided"); + Undo_AddBrushList(&selected_brushes); + Brush_MakeSided(7); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrush8sided() +{ + Undo_Start("8 sided"); + Undo_AddBrushList(&selected_brushes); + Brush_MakeSided(8); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrush9sided() +{ + Undo_Start("9 sided"); + Undo_AddBrushList(&selected_brushes); + Brush_MakeSided(9); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrushArbitrarysided() +{ + Undo_Start("arbitrary sided"); + Undo_AddBrushList(&selected_brushes); + DoSides(); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrushMakecone() +{ + Undo_Start("make cone"); + Undo_AddBrushList(&selected_brushes); + DoSides(true); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnBrushPrimitivesSphere() +{ + Undo_Start("make sphere"); + Undo_AddBrushList(&selected_brushes); + + DoSides(false, true); + + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurvePatchtube() +{ + Undo_Start("make curve cylinder"); + Undo_AddBrushList(&selected_brushes); + Patch_BrushToMesh(false); + Sys_UpdateWindows (W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurvePatchdensetube() +{ + Undo_Start("dense cylinder"); + Undo_AddBrushList(&selected_brushes); + + Patch_BrushToMesh(false); + OnCurveInsertAddrow(); + Sys_UpdateWindows (W_ALL); + + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurvePatchverydensetube() +{ + Undo_Start("very dense cylinder"); + Undo_AddBrushList(&selected_brushes); + + Patch_BrushToMesh(false); + OnCurveInsertAddrow(); + OnCurveInsertInsertrow(); + OnCurveInsertAddrow(); + Sys_UpdateWindows (W_ALL); + + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurvePatchsquare() +{ + Undo_Start("square cylinder"); + Undo_AddBrushList(&selected_brushes); + + Patch_BrushToMesh(false, false, false, true); + Sys_UpdateWindows (W_ALL); + + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurvePatchendcap() +{ + Undo_Start("make end cap"); + Undo_AddBrushList(&selected_brushes); + Patch_BrushToMesh(false, false, true); + Sys_UpdateWindows (W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurvePatchbevel() +{ + Undo_Start("make bevel"); + Undo_AddBrushList(&selected_brushes); + Patch_BrushToMesh(false, true, false); + Sys_UpdateWindows (W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveMoreendcapsbevelsSquarebevel() +{ + Undo_Start("square bevel"); + Undo_AddBrushList(&selected_brushes); + + Patch_BrushToMesh(false, true, false, true); + Sys_UpdateWindows (W_ALL); + + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveMoreendcapsbevelsSquareendcap() +{ + Undo_Start("square endcap"); + Undo_AddBrushList(&selected_brushes); + + Patch_BrushToMesh(false, false, true, true); + Sys_UpdateWindows (W_ALL); + + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurvePatchcone() +{ + Undo_Start("make curve cone"); + Undo_AddBrushList(&selected_brushes); + Patch_BrushToMesh(true); + Sys_UpdateWindows (W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveSimplepatchmesh() +{ + Undo_Start("make simpe patch mesh"); + Undo_AddBrushList(&selected_brushes); + DoNewPatchDlg (); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveInsertInsertcolumn() +{ + Undo_Start("insert (2) columns"); + Undo_AddBrushList(&selected_brushes); + Patch_AdjustSelected(true, true, false); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveInsertAddcolumn() +{ + Undo_Start("add (2) columns"); + Undo_AddBrushList(&selected_brushes); + Patch_AdjustSelected(true, true, true); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveInsertInsertrow() +{ + Undo_Start("insert (2) rows"); + Undo_AddBrushList(&selected_brushes); + Patch_AdjustSelected(true, false, false); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveInsertAddrow() +{ + Undo_Start("add (2) rows"); + Undo_AddBrushList(&selected_brushes); + Patch_AdjustSelected(true, false, true); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveDeleteFirstcolumn() +{ + Undo_Start("delete first (2) columns"); + Undo_AddBrushList(&selected_brushes); + Patch_AdjustSelected(false, true, true); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveDeleteLastcolumn() +{ + Undo_Start("delete last (2) columns"); + Undo_AddBrushList(&selected_brushes); + Patch_AdjustSelected(false, true, false); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveDeleteFirstrow() +{ + Undo_Start("delete first (2) rows"); + Undo_AddBrushList(&selected_brushes); + Patch_AdjustSelected(false, false, true); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveDeleteLastrow() +{ + Undo_Start("delete last (2) rows"); + Undo_AddBrushList(&selected_brushes); + Patch_AdjustSelected(false, false, false); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveNegative() +{ + Patch_ToggleInverted(); + //Sys_UpdateWindows(W_ALL); +} + +void MainFrame::OnCurveRedisperseRows() +{ + Undo_Start("redisperse rows"); + Undo_AddBrushList(&selected_brushes); + Patch_DisperseRows(); + Sys_UpdateWindows (W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveRedisperseIntermediateCols() +{ + Undo_Start("redisperse im cols"); + Undo_AddBrushList(&selected_brushes); + Patch_DisperseIntermediateColumns(); + Sys_UpdateWindows (W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveRedisperseIntermediateRows() +{ + Undo_Start("redisperse im rows"); + Undo_AddBrushList(&selected_brushes); + Patch_DisperseIntermediateRows(); + Sys_UpdateWindows (W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveMatrixTranspose() +{ + Patch_Transpose(); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnCurveCap() +{ + Patch_CapCurrent(); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnCurveCyclecap() +{ + Patch_CycleCapSelected(); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnCurveOverlaySet() +{ + Patch_SetOverlays(); + Sys_UpdateWindows(W_ALL); +} + +void MainFrame::OnCurveOverlayClear() +{ + Patch_ClearOverlays(); + Sys_UpdateWindows(W_ALL); +} + +void MainFrame::OnCurveThicken() +{ + Undo_Start("curve thicken"); + Undo_AddBrushList(&selected_brushes); + DoThickenDlg (); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +/*! +this can no longer be trigger manually from the menu +happens only once at startup +*/ +void MainFrame::OnPluginsRefresh() +{ + CleanPlugInMenu(); + m_PlugInMgr.Init(); +} + +// open the Q3Rad manual +void MainFrame::OnHelp() +{ + // at least on win32, g_strGameToolsPath + "Q3Rad_Manual/index.htm" + Str help; + help = g_strAppPath; + help += "Q3Rad_Manual/index.htm"; + OpenURL(help.GetBuffer()); +} + +// FIXME: we'll go towards a unified help thing soon +void MainFrame::OnHelpLinks() +{ + Str link; + link = g_strAppPath; + link += "links.htm"; + OpenURL(link.GetBuffer()); +} + +void MainFrame::OnHelpBugreport() +{ + OpenURL("http://www.qeradiant.com/faq/fom-serve/cache/138.html"); +} + +void MainFrame::OnHelpCommandlist() +{ + DoCommandListDlg (); +} + +void MainFrame::OnHelpAbout() +{ + DoAbout(); +} + +void MainFrame::OnPopupSelection() +{ + GtkWidget *menu, *item; + char *labels[] = { "Select Complete Tall", "Select Touching", "Select Partial Tall", "Select Inside"}; + int ids[] = { ID_SELECTION_SELECTCOMPLETETALL, ID_SELECTION_SELECTTOUCHING, + ID_SELECTION_SELECTPARTIALTALL, ID_SELECTION_SELECTINSIDE}; + + menu = gtk_menu_new (); + + for (int i = 0; i < 4; i++) + { + item = gtk_menu_item_new_with_label (labels[i]); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (ids[i])); + gtk_widget_show (item); + gtk_menu_append (GTK_MENU (menu), item); + } + + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME); +} + +void MainFrame::OnViewChange() +{ + OnViewNextview(); + //HandlePopup(this, IDR_POPUP_VIEW); +} + +void MainFrame::OnTexturesPopup() +{ + gpointer item = g_object_get_data (G_OBJECT (m_pWidget), "render_quality_menu"); + gtk_menu_popup (GTK_MENU (item), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME); +} + +void MainFrame::ToggleCamera() +{ + if (m_bCamPreview) + m_bCamPreview = false; + else + m_bCamPreview = true; +} + +void MainFrame::OnViewCameraupdate() +{ + Sys_UpdateWindows(W_CAMERA); +} + +void MainFrame::OnSelectMouserotate() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_select_mouserotate")); + g_bIgnoreCommands++; + + if (ActiveXY()) + { + if (ActiveXY()->ClipMode()) + OnViewClipper(); + if (ActiveXY()->RotateMode()) + { + // SetRotateMode(false) always works + ActiveXY()->SetRotateMode(false); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), FALSE); + } else + { + // may not work if no brush selected, see return value + if (ActiveXY()->SetRotateMode(true)) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), TRUE); + else + // if MFC called, we need to set back to FALSE ourselves + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), FALSE); + } + } + g_bIgnoreCommands--; +} + +void MainFrame::OnSelectMousescale() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_select_mousescale")); + g_bIgnoreCommands++; + + if (ActiveXY()) + { + if (ActiveXY()->ClipMode()) + OnViewClipper(); + if (ActiveXY()->RotateMode()) + { + // SetRotateMode(false) always works + ActiveXY()->SetRotateMode(false); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), FALSE); + } + if (ActiveXY()->ScaleMode()) + { + ActiveXY()->SetScaleMode(false); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), FALSE); + } else + { + ActiveXY()->SetScaleMode(true); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), TRUE); + } + } + g_bIgnoreCommands--; +} + +void MainFrame::OnScalelockx() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_scalelockx")); + g_bIgnoreCommands++; + + if (g_nScaleHow & SCALE_X) + { + g_nScaleHow ^= SCALE_X; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), FALSE); + } else + { + g_nScaleHow |= SCALE_X; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), TRUE); + } + g_bIgnoreCommands--; +} + +void MainFrame::OnScalelocky() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_scalelocky")); + g_bIgnoreCommands++; + + if (g_nScaleHow & SCALE_Y) + { + g_nScaleHow ^= SCALE_Y; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), FALSE); + } else + { + g_nScaleHow |= SCALE_Y; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), TRUE); + } + g_bIgnoreCommands--; +} + +void MainFrame::OnScalelockz() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_scalelockz")); + g_bIgnoreCommands++; + + if (g_nScaleHow & SCALE_Z) + { + g_nScaleHow ^= SCALE_Z; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), FALSE); + } else + { + g_nScaleHow |= SCALE_Z; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), TRUE); + } + g_bIgnoreCommands--; +} + +void MainFrame::OnDontselectcurve() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_dontselectcurve")); + g_bIgnoreCommands++; + g_PrefsDlg.m_bSelectCurves ^= 1; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_PrefsDlg.m_bSelectCurves) ? FALSE : TRUE); + g_bIgnoreCommands--; +} + +void MainFrame::OnPatchToggleBox() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_showboundingbox")); + g_bIgnoreCommands++; + g_bPatchShowBounds ^= 1; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchShowBounds) ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows(W_ALL); +} + +void MainFrame::OnPatchWireframe() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_wireframe")); + g_bIgnoreCommands++; + g_bPatchWireFrame ^= 1; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchWireFrame) ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows(W_ALL); +} + +void MainFrame::OnPatchBend() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_bend")); + g_bIgnoreCommands++; + Patch_BendToggle(); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchBendMode) ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows(W_ALL); +} + +void MainFrame::OnPatchWeld() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_weld")); + g_bIgnoreCommands++; + g_bPatchWeld ^= 1; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchWeld) ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows(W_ALL); +} + +void MainFrame::OnPatchDrilldown() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_patch_drilldown")); + g_bIgnoreCommands++; + g_bPatchDrillDown ^= 1; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_bPatchDrillDown) ? TRUE : FALSE); + g_bIgnoreCommands--; + Sys_UpdateWindows(W_ALL); +} + +void MainFrame::OnShowEntities() +{ + gpointer item = g_object_get_data (G_OBJECT (m_pWidget), "view_entitiesas_menu"); // use pointer to existing menu object + gtk_menu_popup (GTK_MENU (item), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME); +} + +void MainFrame::OnDropGroupName() +{ + /* + char* name = DoNameDlg ("Name Selection"); + + if (name != NULL) + { + Select_Name (name); + Sys_UpdateWindows (W_ALL); + free (name); + } + */ +} + +void MainFrame::OnDropGroupNewgroup() +{ + +} + +void MainFrame::OnDropGroupRemove() +{ + /* + Select_AddToGroup("World"); + Sys_UpdateWindows (W_ALL); + */ +} + +// NOTE: it's called OnFaceFit() but we want to process everything here, faces and patches +void MainFrame::OnFaceFit() +{ + SurfaceDlgFitAll(); +} + +void MainFrame::OnDontselectmodel() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_dontselectmodel")); + g_bIgnoreCommands++; + g_PrefsDlg.m_bSelectModels ^= 1; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_PrefsDlg.m_bSelectModels) ? FALSE : TRUE); + g_bIgnoreCommands--; +} + +void MainFrame::OnViewTexture() +{ + if (FloatingGroupDialog()) // QE4 style + { + if (inspector_mode == W_TEXTURE) + { + if (GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity)) + widget_delete_hide (g_qeglobals_gui.d_entity); + else + gtk_widget_show (g_qeglobals_gui.d_entity); + } else + { + gtk_widget_show (g_qeglobals_gui.d_entity); + SetInspectorMode (W_TEXTURE); + } + } +} + +void MainFrame::OnPatchInspector() +{ + TogglePatchInspector(); +} + +void MainFrame::OnCurveNegativeTextureX() +{ + Patch_InvertTexture(false); + //Sys_UpdateWindows(W_ALL); +} + +void MainFrame::OnCurveNegativeTextureY() +{ + Patch_InvertTexture(true); + //Sys_UpdateWindows(W_ALL); +} + +void MainFrame::OnCurveInsertcolumn() +{ + if (&selected_brushes == selected_brushes.next) + return; + Undo_Start("insert colum"); + Undo_AddBrushList(&selected_brushes); + //Patch_AdjustSelectedRowCols(0, 2); + Patch_AdjustSelected(true, true, true); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveInsertrow() +{ + if (&selected_brushes == selected_brushes.next) + return; + Undo_Start("insert row"); + Undo_AddBrushList(&selected_brushes); + //Patch_AdjustSelectedRowCols(2, 0); + Patch_AdjustSelected(true, false, true); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveDeletecolumn() +{ + if (&selected_brushes == selected_brushes.next) + return; + Undo_Start("delete column"); + Undo_AddBrushList(&selected_brushes); + Patch_AdjustSelected(false, true, true); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnCurveDeleterow() +{ + if (&selected_brushes == selected_brushes.next) + return; + Undo_Start("delete row"); + Undo_AddBrushList(&selected_brushes); + Patch_AdjustSelected(false, false, true); + Sys_UpdateWindows(W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnPatchTab() +{ + if (g_bPatchBendMode) + Patch_BendHandleTAB(); +// else if (g_bPatchInsertMode) +// Patch_InsDelHandleTAB(); + else + { + // check to see if the selected brush is part of a func group + // if it is, deselect everything and reselect the next brush + // in the group + brush_t *b2, *b = selected_brushes.next; + entity_t * e; + if (b != &selected_brushes) + { + if (strcmpi(b->owner->eclass->name, "worldspawn") != 0) + { + e = b->owner; + Select_Deselect(); + for (b2 = e->brushes.onext ; b2 != &e->brushes ; b2 = b2->onext) + { + if (b == b2) + { + b2 = b2->onext; + break; + } + } + if (b2 == &e->brushes) + b2 = b2->onext; + + Select_Brush(b2, false); + Sys_UpdateWindows(W_ALL); + } + } + } +} + +void MainFrame::OnCameraForward(bool keydown) +{ + if (g_PrefsDlg.m_bCamDiscrete && (m_pCamWnd && !m_pCamWnd->m_bFreeMove) ) + { + if(keydown) + { + VectorMA (m_pCamWnd->Camera()->origin, SPEED_MOVE, m_pCamWnd->Camera()->forward, m_pCamWnd->Camera()->origin); + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + } + } + else { + if (keydown) + m_pCamWnd->Camera()->movementflags |= MOVE_FORWARD; + else + m_pCamWnd->Camera()->movementflags &= ~MOVE_FORWARD; + } +} + +void MainFrame::OnCameraBack(bool keydown) +{ + if (g_PrefsDlg.m_bCamDiscrete && (m_pCamWnd && !m_pCamWnd->m_bFreeMove) ) + { + if(keydown) + { + VectorMA (m_pCamWnd->Camera()->origin, -SPEED_MOVE, m_pCamWnd->Camera()->forward, m_pCamWnd->Camera()->origin); + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + } + } + else { + if (keydown) + m_pCamWnd->Camera()->movementflags |= MOVE_BACK; + else + m_pCamWnd->Camera()->movementflags &= ~MOVE_BACK; + } +} + +void MainFrame::OnCameraLeft(bool keydown) +{ + if (m_pCamWnd) + { + if (m_pCamWnd->m_bFreeMove) + { + OnCameraStrafeleft(keydown); + return; + } + } + + if (g_PrefsDlg.m_bCamDiscrete) + { + if(keydown) + { + m_pCamWnd->Camera()->angles[1] += SPEED_TURN; + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + } + } + else { + if (keydown) + m_pCamWnd->Camera()->movementflags |= MOVE_ROTLEFT; + else + m_pCamWnd->Camera()->movementflags &= ~MOVE_ROTLEFT; + } +} + +void MainFrame::OnCameraRight(bool keydown) +{ + if (m_pCamWnd) + { + if (m_pCamWnd->m_bFreeMove) + { + OnCameraStraferight(keydown); + return; + } + } + + if (g_PrefsDlg.m_bCamDiscrete) + { + if(keydown) + { + m_pCamWnd->Camera()->angles[1] -= SPEED_TURN; + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + } + } + else { + if (keydown) + m_pCamWnd->Camera()->movementflags |= MOVE_ROTRIGHT; + else + m_pCamWnd->Camera()->movementflags &= ~MOVE_ROTRIGHT; + } +} + +void MainFrame::OnCameraUp() +{ + m_pCamWnd->Camera()->origin[2] += SPEED_MOVE; + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY | W_Z) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); +} + +void MainFrame::OnCameraDown() +{ + m_pCamWnd->Camera()->origin[2] -= SPEED_MOVE; + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY | W_Z) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); +} + +void MainFrame::OnCameraAngleup() +{ + m_pCamWnd->Camera()->angles[0] += SPEED_TURN; + if (m_pCamWnd->Camera()->angles[0] > 85) + m_pCamWnd->Camera()->angles[0] = 85; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); +} + +void MainFrame::OnCameraAngledown() +{ + m_pCamWnd->Camera()->angles[0] -= SPEED_TURN; + if (m_pCamWnd->Camera()->angles[0] < -85) + m_pCamWnd->Camera()->angles[0] = -85; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); +} + +void MainFrame::OnCameraStrafeleft(bool keydown) +{ + // FIXME: as soon as gtk supports proper keyup/down support, remove this bit + if (m_pCamWnd) + { + if (!m_pCamWnd->m_bFreeMove) + { + if(keydown) + { + VectorMA (m_pCamWnd->Camera()->origin, -SPEED_MOVE, m_pCamWnd->Camera()->right, m_pCamWnd->Camera()->origin); + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + } + return; + } + } + + if (keydown) + m_pCamWnd->Camera()->movementflags |= MOVE_STRAFELEFT; + else + m_pCamWnd->Camera()->movementflags &= ~MOVE_STRAFELEFT; +} + +void MainFrame::OnCameraStraferight(bool keydown) +{ + // FIXME: as soon as gtk supports proper keyup/down support, remove this bit + if (m_pCamWnd) + { + if (!m_pCamWnd->m_bFreeMove) + { + if(keydown) + { + VectorMA (m_pCamWnd->Camera()->origin, SPEED_MOVE, m_pCamWnd->Camera()->right, m_pCamWnd->Camera()->origin); + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + } + return; + } + } + + if (keydown) + m_pCamWnd->Camera()->movementflags |= MOVE_STRAFERIGHT; + else + m_pCamWnd->Camera()->movementflags &= ~MOVE_STRAFERIGHT; +} + +void MainFrame::OnGridToggle() +{ + g_qeglobals.d_showgrid = !g_qeglobals.d_showgrid; + Sys_UpdateWindows (W_XY|W_Z); +} + +void MainFrame::OnViewCrosshair() +{ + g_bCrossHairs ^= 1; + Sys_UpdateWindows (W_XY); +} + +void MainFrame::OnSelectionTextureRotateclock() +{ + Select_RotateTexture(abs(g_PrefsDlg.m_nRotation)); +} + +void MainFrame::OnSelectionTextureRotatecounter() +{ + Select_RotateTexture(-abs(g_PrefsDlg.m_nRotation)); +} + +void MainFrame::OnSelectionTextureScaleup() +{ + Select_ScaleTexture(0, g_qeglobals.d_savedinfo.m_SIIncrement.scale[1]); +} + +void MainFrame::OnSelectionTextureScaledown() +{ + Select_ScaleTexture(0, -g_qeglobals.d_savedinfo.m_SIIncrement.scale[1]); +} + +void MainFrame::OnSelectionTextureScaleLeft() +{ + Select_ScaleTexture(-g_qeglobals.d_savedinfo.m_SIIncrement.scale[0],0); +} + +void MainFrame::OnSelectionTextureScaleRight() +{ + Select_ScaleTexture(g_qeglobals.d_savedinfo.m_SIIncrement.scale[0],0); +} + +void MainFrame::OnSelectionTextureShiftleft() +{ + Select_ShiftTexture((int)-g_qeglobals.d_savedinfo.m_SIIncrement.shift[0], 0); +} + +void MainFrame::OnSelectionTextureShiftright() +{ + Select_ShiftTexture((int)g_qeglobals.d_savedinfo.m_SIIncrement.shift[0], 0); +} + +void MainFrame::OnSelectionTextureShiftup() +{ + Select_ShiftTexture(0, (int)g_qeglobals.d_savedinfo.m_SIIncrement.shift[1]); +} + +void MainFrame::OnSelectionTextureShiftdown() +{ + Select_ShiftTexture(0, (int)-g_qeglobals.d_savedinfo.m_SIIncrement.shift[1]); +} + +void MainFrame::OnGridPrev() +{ + GtkWidget *item; + if (g_qeglobals.d_gridsize == 1) + { + g_qeglobals.d_gridsize = 0.5; + g_qeglobals.d_bSmallGrid = true; + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_05")); + } else if (g_qeglobals.d_gridsize == 0.5) + { + g_qeglobals.d_gridsize = 0.25; + g_qeglobals.d_bSmallGrid = true; + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_025")); + } else if (g_qeglobals.d_gridsize > 1) + { + g_qeglobals.d_gridsize = (int)g_qeglobals.d_gridsize >> 1; + g_qeglobals.d_bSmallGrid = false; + + switch ((int)g_qeglobals.d_gridsize) + { + case 1: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_1")); break; + case 2: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_2")); break; + case 4: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_4")); break; + case 8: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_8")); break; + case 16: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_16")); break; + case 32: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_32")); break; + case 64: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_64")); break; + case 128: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_128")); break; + case 256: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_256")); break; + } + + } else + return; + + // SnapTToGrid option: need to check everywhere the grid size is changed + // this is a bit clumsy, have to do in OnGrid OnGridPrev and OnGridNext + if (g_PrefsDlg.m_bSnapTToGrid) + DoSnapTToGrid(); + + SetGridStatus(); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + g_bIgnoreCommands--; + + Sys_UpdateWindows(W_XY | W_Z); +} + +void MainFrame::OnGridNext() +{ + GtkWidget *item; + if (g_qeglobals.d_gridsize == 0.25) + { + g_qeglobals.d_gridsize = 0.5; + g_qeglobals.d_bSmallGrid = true; + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_05")); + } else if (g_qeglobals.d_gridsize == 0.5) + { + g_qeglobals.d_gridsize = 1; + g_qeglobals.d_bSmallGrid = false; + item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_1")); + } else if (g_qeglobals.d_gridsize < 256) + { + g_qeglobals.d_gridsize = (int)g_qeglobals.d_gridsize << 1; + g_qeglobals.d_bSmallGrid = false; + + switch ((int)g_qeglobals.d_gridsize) + { + case 1: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_1")); break; + case 2: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_2")); break; + case 4: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_4")); break; + case 8: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_8")); break; + case 16: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_16")); break; + case 32: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_32")); break; + case 64: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_64")); break; + case 128: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_128")); break; + case 256: item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_grid_256")); break; + } + + } else + return; + + // SnapTToGrid option: need to check everywhere the grid size is changed + // this is a bit clumsy, have to do in OnGrid OnGridPrev and OnGridNext + if (g_PrefsDlg.m_bSnapTToGrid) + DoSnapTToGrid(); + + SetGridStatus(); + g_bIgnoreCommands++; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + g_bIgnoreCommands--; + + Sys_UpdateWindows(W_XY | W_Z); +} + +void MainFrame::OnSelectionMovedown() +{ + if (&selected_brushes == selected_brushes.next) + return; + Undo_Start("move down"); + Undo_AddBrushList(&selected_brushes); + + vec3_t vAmt; + vAmt[0] = vAmt[1] = 0.0; + vAmt[2] = -g_qeglobals.d_gridsize; + Select_Move (vAmt); + Sys_UpdateWindows(W_CAMERA | W_XY | W_Z); + + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectionMoveup() +{ + if (&selected_brushes == selected_brushes.next) + return; + Undo_Start("move up"); + Undo_AddBrushList(&selected_brushes); + + vec3_t vAmt; + vAmt[0] = vAmt[1] = 0.0; + vAmt[2] = g_qeglobals.d_gridsize; + Select_Move (vAmt); + Sys_UpdateWindows(W_CAMERA | W_XY | W_Z); + + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectionPrint() +{ + for (brush_t* b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + Brush_Print(b); +} + +void MainFrame::OnSelectionTogglesizepaint() +{ + g_PrefsDlg.m_bSizePaint = !g_PrefsDlg.m_bSizePaint; + Sys_UpdateWindows(W_XY); +} + +void MainFrame::OnPatchNaturalize() +{ + Patch_NaturalizeSelected(); + Sys_UpdateWindows (W_ALL); +} + +void MainFrame::OnSnapToGrid() +{ + if (&selected_brushes == selected_brushes.next) + return; + Undo_Start("snap selection to grid"); + Undo_AddBrushList(&selected_brushes); + //Select_SnapToGrid(); + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + Patch_SnapToGrid(pb->pPatch); + else + Brush_SnapToGrid(pb); + } + Sys_UpdateWindows (W_ALL); + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +void MainFrame::OnSelectAll() +{ + Select_AllOfType(); +} + +void MainFrame::OnSelectionInvert() +{ + Select_Invert(); + Sys_UpdateWindows(W_XY | W_Z | W_CAMERA); +} + + +void PerformFiltering () +{ + brush_t *brush; + + // spog - deletes old filters list and creates new one when + // g_qeglobals.d_savedinfo.exclude is updated + g_qeglobals.d_savedinfo.filters = FilterListDelete(g_qeglobals.d_savedinfo.filters); + g_qeglobals.d_savedinfo.filters = FilterUpdate(g_qeglobals.d_savedinfo.filters); + + for ( brush = active_brushes.next; brush != &active_brushes; brush = brush->next ) + brush->bFiltered = FilterBrush( brush ); + + for ( brush = selected_brushes.next; brush != &selected_brushes; brush = brush->next ) + brush->bFiltered = FilterBrush( brush ); +} + +void MainFrame::OnFilterAreaportals() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_areaportals")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_AREAPORTALS) & EXCLUDE_AREAPORTALS) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterCaulk() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_caulk")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_CAULK) & EXCLUDE_CAULK) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterClips() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_clips")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_CLIP) & EXCLUDE_CLIP) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterBotClips() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_botclips")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_BOTCLIP) & EXCLUDE_BOTCLIP) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterStructural() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_structural")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_STRUCTURAL) & EXCLUDE_STRUCTURAL) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterDetails() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_details")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_DETAILS) & EXCLUDE_DETAILS) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterEntities() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_entities")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_ENT) & EXCLUDE_ENT) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterHintsskips() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_hintsskips")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_HINTSSKIPS) & EXCLUDE_HINTSSKIPS) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterLights() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_lights")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_LIGHTS) & EXCLUDE_LIGHTS) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterLiquids() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_liquids")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_LIQUIDS) & EXCLUDE_LIQUIDS) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterModels() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_models")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_MODELS) & EXCLUDE_MODELS) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterPatches() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_patches")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_CURVES) & EXCLUDE_CURVES) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterPaths() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_paths")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_PATHS) & EXCLUDE_PATHS) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterClusterportals() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_clusterportals")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_CLUSTERPORTALS) & EXCLUDE_CLUSTERPORTALS) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterLightgrid() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_lightgrid")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_LIGHTGRID) & EXCLUDE_LIGHTGRID) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterTranslucent() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_translucent")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_TRANSLUCENT) & EXCLUDE_TRANSLUCENT) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterTriggers() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_triggers")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_TRIGGERS) & EXCLUDE_TRIGGERS) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + +void MainFrame::OnFilterWorld() +{ + GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_filter_world")); + g_bIgnoreCommands++; + if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_WORLD) & EXCLUDE_WORLD) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + else + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE); + g_bIgnoreCommands--; + PerformFiltering(); + Sys_UpdateWindows (W_XY|W_CAMERA); +} + + + + + + + + +// ============================================================================= +// leo: Unused functions, not called anywhere from the code (need to check) + +void MainFrame::OnViewConsole() +{ + if (FloatingGroupDialog()) // QE4 style + { + if (inspector_mode == W_CONSOLE && CurrentStyle() != MainFrame::eFloating) // are we in console mode already? + { + if (GTK_WIDGET_VISIBLE (g_qeglobals_gui.d_entity)) + widget_delete_hide (g_qeglobals_gui.d_entity); + else + gtk_widget_show (g_qeglobals_gui.d_entity); + } else + { + gtk_widget_show (g_qeglobals_gui.d_entity); + SetInspectorMode(W_CONSOLE); + } + } +} + +void MainFrame::OnCurveFreeze() +{ + Patch_Freeze(); +} + +void MainFrame::OnCurveUnFreeze() +{ + Patch_UnFreeze(false); +} + +void MainFrame::OnCurveUnFreezeAll() +{ + Patch_UnFreeze(true); +} + +void MainFrame::OnSelectReselect() +{ + Select_Reselect(); +} + +void MainFrame::OnSelectionTextureFit() +{ + // TODO: Add your command handler code here +} + +void MainFrame::OnPatchEnter() +{ + +} + +void MainFrame::OnDropGroupAddtoWorld() +{ + /* + Select_AddToGroup("World"); + Sys_UpdateWindows (W_ALL); + */ +} diff --git a/radiant/map.cpp b/radiant/map.cpp index 051c0a51..59290f2a 100644 --- a/radiant/map.cpp +++ b/radiant/map.cpp @@ -1,1322 +1,1322 @@ -/* -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 -*/ - -#include "stdafx.h" -#include -#if defined (__linux__) || defined (__APPLE__) -#include -#endif -#include "preferences.h" -#include "mainframe.h" -#include "gtkmisc.h" -#include "filters.h" - -extern MainFrame* g_pParentWnd; - -int modified; // for quit confirmation (0 = clean, 1 = unsaved, - // 2 = autosaved, but not regular saved) - -char currentmap[1024]; - -brush_t active_brushes; // brushes currently being displayed -brush_t selected_brushes; // highlighted - -face_t *selected_face; -brush_t *selected_face_brush; - -brush_t filtered_brushes; // brushes that have been filtered or regioned - -entity_t entities; // head/tail of doubly linked list - -entity_t *world_entity = NULL; // "classname" "worldspawn" ! - -void Map_Init() -{ - Map_Free(); -} - - -bool g_bCancel_Map_LoadFile; // Hydra: moved this here - -// TTimo -// need that in a variable, will have to tweak depending on the game -int g_MaxWorldCoord = 64*1024; -int g_MinWorldCoord = -64*1024; - -// the max size we allow on brushes, this is dependant on world coords too -// makes more sense to say smaller I think? -int g_MaxBrushSize = (g_MaxWorldCoord-1)*2; - -void AddRegionBrushes (void); -void RemoveRegionBrushes (void); - -/* -============================================================= - - Cross map selection saving - - this could fuck up if you have only part of a complex entity selected... -============================================================= -*/ - -brush_t between_brushes; -entity_t between_entities; - -bool g_bRestoreBetween = false; - -void Map_SaveBetween (void) -{ - if (g_pParentWnd->ActiveXY()) - { - g_bRestoreBetween = true; - g_pParentWnd->ActiveXY()->Copy(); - } - return; -} - -void Map_RestoreBetween (void) -{ - if (g_pParentWnd->ActiveXY() && g_bRestoreBetween) - g_pParentWnd->ActiveXY()->Paste(); -} - -//============================================================================ - -bool CheckForTinyBrush(brush_t* b, int n, float fSize) -{ - bool bTiny = false; - for (int i=0 ; i<3 ; i++) - { - if (b->maxs[i] - b->mins[i] < fSize) - bTiny = true; - } - if (bTiny) - Sys_Printf("Possible problem brush (too small) #%i ", n); - return bTiny; -} - -void Map_BuildBrushData(void) -{ - brush_t *b, *next; - - if (active_brushes.next == NULL) - return; - - Sys_BeginWait (); // this could take a while - - int n = 0; - for (b=active_brushes.next ; b != NULL && b != &active_brushes ; b=next) - { - next = b->next; - Brush_Build( b, true, false, false ); - if (!b->brush_faces || (g_PrefsDlg.m_bCleanTiny && CheckForTinyBrush(b, n++, g_PrefsDlg.m_fTinySize))) - { - Brush_Free (b); - Sys_Printf ("Removed degenerate brush\n"); - } - } - Sys_EndWait(); -} - -entity_t *Map_FindClass (char *cname) -{ - entity_t *ent; - - for (ent = entities.next ; ent != &entities ; ent=ent->next) - { - if (!strcmp(cname, ValueForKey (ent, "classname"))) - return ent; - } - return NULL; -} - -/* -================ -Map_Free -free all map elements, reinitialize the structures that depend on them -================ -*/ -void Map_Free (void) -{ - g_bRestoreBetween = false; - if (selected_brushes.next && - (selected_brushes.next != &selected_brushes)) - { - if (gtk_MessageBox (g_pParentWnd->m_pWidget, "Copy selection?", " ", MB_YESNO) == IDYES) - Map_SaveBetween (); - } - - QERApp_ActiveShaders_SetInUse( false ); - Pointfile_Clear (); - g_qeglobals.d_num_entities = 0; - - if (!active_brushes.next) - { - // first map - active_brushes.prev = active_brushes.next = &active_brushes; - selected_brushes.prev = selected_brushes.next = &selected_brushes; - filtered_brushes.prev = filtered_brushes.next = &filtered_brushes; - entities.prev = entities.next = &entities; - } - else - { - // free selected faces array - g_ptrSelectedFaces.RemoveAll(); - g_ptrSelectedFaceBrushes.RemoveAll(); - while (active_brushes.next != &active_brushes) - Brush_Free (active_brushes.next); - while (selected_brushes.next != &selected_brushes) - Brush_Free (selected_brushes.next); - while (filtered_brushes.next != &filtered_brushes) - Brush_Free (filtered_brushes.next); - while (entities.next != &entities) - Entity_Free (entities.next); - } - - if (world_entity) - Entity_Free(world_entity); - world_entity = NULL; -} - -entity_t *AngledEntity() -{ - entity_t *ent = Map_FindClass ("info_player_start"); - if (!ent) - { - ent = Map_FindClass ("info_player_deathmatch"); - } - if (!ent) - { - ent = Map_FindClass ("info_player_deathmatch"); - } - if (!ent) - { - ent = Map_FindClass ("team_CTF_redplayer"); - } - if (!ent) - { - ent = Map_FindClass ("team_CTF_blueplayer"); - } - if (!ent) - { - ent = Map_FindClass ("team_CTF_redspawn"); - } - if (!ent) - { - ent = Map_FindClass ("team_CTF_bluespawn"); - } - return ent; -} - -// -// move the view to a start position -// -void Map_StartPosition() -{ - entity_t *ent = AngledEntity(); - - g_pParentWnd->GetCamWnd()->Camera()->angles[PITCH] = 0; - if (ent) - { - GetVectorForKey (ent, "origin", g_pParentWnd->GetCamWnd()->Camera()->origin); - GetVectorForKey (ent, "origin", g_pParentWnd->GetXYWnd()->GetOrigin()); - g_pParentWnd->GetCamWnd()->Camera()->angles[YAW] = FloatForKey (ent, "angle"); - } - else - { - g_pParentWnd->GetCamWnd()->Camera()->angles[YAW] = 0; - VectorCopy (vec3_origin, g_pParentWnd->GetCamWnd()->Camera()->origin); - VectorCopy (vec3_origin, g_pParentWnd->GetXYWnd()->GetOrigin()); - } -} - -void Map_FreeEntities(CPtrArray *ents) -{ - int i, j, num_ents, num_brushes; - entity_t* e; - CPtrArray* brushes; - - num_ents = ents->GetSize(); - for(i=0; iGetAt(i); - brushes = (CPtrArray*)e->pData; - num_brushes = brushes->GetSize(); - for(j=0; jGetAt(j)); - brushes->RemoveAll(); - delete (CPtrArray*)e->pData; - e->pData = NULL; - Entity_Free(e); - } - ents->RemoveAll(); -} - -/*!\todo Possibly make the import Undo-friendly by calling Undo_End for new brushes and ents */ -void Map_ImportEntities(CPtrArray *ents, bool bAddSelected = false) -{ - int num_ents, num_brushes; - CPtrArray *brushes; - vec3_t mins, maxs; - entity_t *e; - brush_t *b; - face_t *f; - int i,j; - - GPtrArray *new_ents = g_ptr_array_new(); - - g_qeglobals.bPrimitBrushes = false; - - brush_t *pBrushList = (bAddSelected) ? &selected_brushes : &active_brushes; - - bool bDoneBPCheck = false; - g_qeglobals.bNeedConvert = false; - // HACK: find out if this map file was a BP one - // check the first brush in the file that is NOT a patch - // this will not be necessary when we allow both formats in the same file - num_ents = ents->GetSize(); - for(i=0; !bDoneBPCheck && iGetAt(i); - brushes = (CPtrArray*)e->pData; - num_brushes = brushes->GetSize(); - for(j=0; !bDoneBPCheck && jGetAt(j); - if(b->patchBrush) continue; - bDoneBPCheck = true; - int BP_param = -1; - if(b->bBrushDef && !g_qeglobals.m_bBrushPrimitMode) - BP_param = 0; - else if(!b->bBrushDef && g_qeglobals.m_bBrushPrimitMode) - BP_param = 1; - - if(BP_param != -1) - { - switch(BP_MessageBox(BP_param)) - { - case 0: - Map_FreeEntities(ents); - return; - case 1: - g_qeglobals.bNeedConvert = true; - break; - case 2: - g_qeglobals.bNeedConvert = false; - break; - } - } - } - } - - // process the entities into the world geometry - num_ents = ents->GetSize(); - for(i=0; iGetAt(i); - brushes = (CPtrArray*)e->pData; - - num_brushes = brushes->GetSize(); - // link brushes into entity - for(j=0; jGetAt(j)); - g_qeglobals.d_parsed_brushes++; - } - brushes->RemoveAll(); - delete brushes; - e->pData = NULL; - - // set entity origin - GetVectorForKey (e, "origin", e->origin); - // set entity eclass - /*!\todo Make SetKeyValue check for "classname" change and assign appropriate eclass */ - e->eclass = Eclass_ForName (ValueForKey (e, "classname"), - (e->brushes.onext != &e->brushes)); - - // go through all parsed brushes and build stuff - for(b = e->brushes.onext; b!=&e->brushes; b=b->onext) - { - for(f = b->brush_faces; f != NULL; f = f->next) - { - f->pShader = QERApp_Shader_ForName(f->texdef.GetName()); - f->d_texture = f->pShader->getTexture(); - } - - // when brushes are in final state, build the planes and windings - // NOTE: also converts BP brushes if g_qeglobals.bNeedConvert is true - Brush_Build(b); - } - -//#define TERRAIN_HACK -#undef TERRAIN_HACK - -#ifdef TERRAIN_HACK - if ((strcmp(ValueForKey(e, "terrain"),"1") == 0 && strcmp(e->eclass->name,"func_group") == 0)) - { - - // two aux pointers to the shaders used in the terrain entity - // we don't keep refcount on them since they are only temporary - // this avoids doing expensive lookups by name for all faces - IShader *pTerrainShader, *pCaulk; - - pTerrainShader = NULL; - pCaulk = QERApp_Shader_ForName(SHADER_CAULK); - - for(b = e->brushes.onext; b!=&e->brushes; b=b->onext) - { - if (pTerrainShader == NULL) - for(f = b->brush_faces; f != NULL; f = f->next) - if (strcmp(f->texdef.GetName(), SHADER_CAULK)!=0) - pTerrainShader = f->pShader; - - if (pTerrainShader) - { - for(f = b->brush_faces; f != NULL; f = f->next) - { - if (strcmp(f->texdef.GetName(), SHADER_CAULK)!=0) // not caulk - Face_SetShader(f, pTerrainShader->getName()); - else - Face_SetShader(f, pCaulk->getName()); - } - } - else - Sys_Printf("WARNING: no terrain shader found for brush\n"); - } - } -#endif - -#define PATCH_HACK -#ifdef PATCH_HACK - for(b = e->brushes.onext; b!=&e->brushes; b=b->onext) - { - // patch hack, to be removed when dependency on brush_faces is removed - if (b->patchBrush) - { - Patch_CalcBounds(b->pPatch, mins, maxs); - for (int i=0; i<3; i++) - { - if ((int)mins[i] == (int)maxs[i]) - { - mins[i] -= 4; - maxs[i] += 4; - } - } - Brush_Resize(b, mins, maxs); - Brush_Build(b); - } - } -#endif - // add brush for fixedsize entity - if (e->eclass->fixedsize) - { - vec3_t mins, maxs; - VectorAdd (e->eclass->mins, e->origin, mins); - VectorAdd (e->eclass->maxs, e->origin, maxs); - b = Brush_Create (mins, maxs, &e->eclass->texdef); - Entity_LinkBrush(e, b); - Brush_Build(b); - } - - for(b = e->brushes.onext; b!=&e->brushes; b=b->onext) - Brush_AddToList(b, pBrushList); - - if (strcmp(e->eclass->name, "worldspawn") == 0) - { - if (world_entity) - { - while(e->brushes.onext != &e->brushes) - { - b = e->brushes.onext; - Entity_UnlinkBrush(b); - Entity_LinkBrush(world_entity, b); - } - Entity_Free(e); - } - else - { - world_entity = e; - } - } - else if (strcmp(e->eclass->name, "group_info") == 0) - { - // it's a group thing! - Group_Add(e); - Entity_Free(e); - } - else - { - // fix target/targetname collisions - if ((g_PrefsDlg.m_bDoTargetFix) && (strcmp(ValueForKey(e, "target"), "") != 0)) - { - GPtrArray *t_ents = g_ptr_array_new(); - entity_t *e_target; - const char *target = ValueForKey(e, "target"); - qboolean bCollision=FALSE; - - // check the current map entities for an actual collision - for (e_target = entities.next; e_target != &entities; e_target = e_target->next) - { - if(!strcmp(target, ValueForKey(e_target, "target"))) - { - bCollision = TRUE; - // make sure the collision is not between two imported entities - for(j=0; j<(int)new_ents->len; j++) - { - if(e_target == g_ptr_array_index(new_ents, j)) - bCollision = FALSE; - } - } - } - - // find the matching targeted entity(s) - if(bCollision) - { - for(j=num_ents-1; j>0; j--) - { - e_target = (entity_t*)ents->GetAt(j); - if(e_target != NULL && e_target != e) - { - const char *targetname = ValueForKey(e_target, "targetname"); - if( (targetname != NULL) && (strcmp(target, targetname) == 0) ) - g_ptr_array_add(t_ents, (gpointer)e_target); - } - } - if(t_ents->len > 0) - { - // link the first to get a unique target/targetname - Entity_Connect(e, (entity_t*)g_ptr_array_index(t_ents,0)); - // set the targetname of the rest of them manually - for(j = 1; j < (int)t_ents->len; j++) - SetKeyValue( (entity_t*)g_ptr_array_index(t_ents, j), "targetname", ValueForKey(e, "target") ); - } - g_ptr_array_free(t_ents, FALSE); - } - } - - // add the entity to the end of the entity list - Entity_AddToList(e, &entities); - g_qeglobals.d_num_entities++; - - // keep a list of ents added to avoid testing collisions against them - g_ptr_array_add(new_ents, (gpointer)e); - } - } - g_ptr_array_free(new_ents, FALSE); - - ents->RemoveAll(); - - g_qeglobals.bNeedConvert = false; -} - -void Map_Import(IDataStream *in, const char *type, bool bAddSelected) -{ - CPtrArray ents; - - g_pParentWnd->GetSynapseClient().ImportMap(in, &ents, type); - Map_ImportEntities(&ents, bAddSelected); -} - -/* -================ -Map_LoadFile -================ -*/ -void Map_LoadFile (const char *filename) -{ - clock_t start, finish; - double elapsed_time; - start = clock(); - - Sys_BeginWait (); - Select_Deselect(); - /*! - \todo FIXME TTimo why is this commented out? - stability issues maybe? or duplicate feature? - forcing to show the console during map load was a good thing IMO - */ - //SetInspectorMode(W_CONSOLE); - Sys_Printf ("Loading map from %s\n", filename ); - - Map_Free (); - //++timo FIXME: maybe even easier to have Group_Init called from Map_Free? - Group_Init(); - g_qeglobals.d_num_entities = 0; - g_qeglobals.d_parsed_brushes = 0; - - - // cancel the map loading process - // used when conversion between standard map format and BP format is required and the user cancels the process - g_bCancel_Map_LoadFile = false; - - strcpy (currentmap, filename); - - g_bScreenUpdates = false; // leo: avoid redraws while loading the map (see fenris:1952) - - // prepare to let the map module do the parsing - FileStream file; - const char* type = strrchr(filename,'.'); - if(type!=NULL) type++; - // NOTE TTimo opening has binary doesn't make a lot of sense - // but opening as text confuses the scriptlib parser - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=261 - // this may be a problem if we "rb" and use the XML parser, might have an incompatibility - if (file.Open(filename, "rb")) - Map_Import(&file, type); - else - Sys_FPrintf(SYS_ERR, "ERROR: failed to open %s for read\n", filename); - file.Close(); - - g_bScreenUpdates = true; - - if (g_bCancel_Map_LoadFile) - { - Sys_Printf("Map_LoadFile canceled\n"); - Map_New(); - Sys_EndWait(); - return; - } - - if (!world_entity) - { - Sys_Printf ("No worldspawn in map.\n"); - Map_New (); - Sys_EndWait(); - return; - } - finish = clock(); - elapsed_time = (double)(finish - start) / CLOCKS_PER_SEC; - - Sys_Printf ("--- LoadMapFile ---\n"); - Sys_Printf ("%s\n", filename ); - - Sys_Printf ("%5i brushes\n", g_qeglobals.d_parsed_brushes ); - Sys_Printf ("%5i entities\n", g_qeglobals.d_num_entities); - Sys_Printf ("%5.2f second(s) load time\n", elapsed_time ); - - Sys_EndWait(); - - Map_RestoreBetween (); - - // - // move the view to a start position - // - Map_StartPosition(); - - Map_RegionOff (); - - modified = false; - Sys_SetTitle (filename); - - Texture_ShowInuse (); - QERApp_SortActiveShaders(); - - Sys_UpdateWindows (W_ALL); -} - -/*! -=========== -Supporting functions for Map_SaveFile, builds a CPtrArray with the filtered / non filtered brushes -=========== -*/ -void CleanFilter(entity_t *ent) -{ - if (ent->pData) - { - delete static_cast(ent->pData); - ent->pData = NULL; - } -} - -/*! -filters out the region brushes if necessary -returns true if this entity as a whole is out of the region -(if all brushes are filtered out, then the entity will be completely dropped .. except if it's worldspawn of course) -*/ -bool FilterChildren(entity_t *ent, bool bRegionOnly = false, bool bSelectedOnly = false) -{ - if(ent->brushes.onext == &ent->brushes) - return false; - // entity without a brush, ignore it... this can be caused by Undo - - // filter fixedsize ents by their eclass bounding box - // don't add their brushes - if (ent->eclass->fixedsize) - { - if(bSelectedOnly && !IsBrushSelected(ent->brushes.onext)) - return false; - - if(bRegionOnly && region_active) - { - for (int i=0 ; i<3 ; i++) - { - if ((ent->origin[i] + ent->eclass->mins[i]) > region_maxs[i]) - return false; - if ((ent->origin[i] + ent->eclass->maxs[i]) < region_mins[i]) - return false; - } - } - } - else - { - for (brush_t *b = ent->brushes.onext ; b != &ent->brushes ; b=b->onext) - { - // set flag to use brushprimit_texdef - if(g_qeglobals.m_bBrushPrimitMode) - b->bBrushDef = true; - else - b->bBrushDef = false; - - // add brush, unless it's excluded by region - if ( !(bRegionOnly && Map_IsBrushFiltered(b)) && - !(bSelectedOnly && !IsBrushSelected(b)) ) - ((CPtrArray*)ent->pData)->Add(b); - } - - if (((CPtrArray*)ent->pData)->GetSize() <= 0) - return false; - } - return true; -} - -entity_t *region_startpoint = NULL; -void Map_ExportEntities(CPtrArray* ents, bool bRegionOnly = false, bool bSelectedOnly = false) -{ - int i; - entity_t *e; - - /*! - \todo the entity_t needs to be reworked and asbtracted some more - - keeping the entity_t as the struct providing access to a list of map objects, a list of epairs and various other info? - but separating some more the data that belongs to the entity_t and the 'sons' data - on a side note, I don't think that doing that with linked list would be a good thing - - for now, we use the blind void* in entity_t casted to a CPtrArray of brush_t* to hand out a list of the brushes for map write - the next step is very likely to be a change of the brush_t* to a more abstract object? - */ - - FilterChildren(world_entity, bRegionOnly, bSelectedOnly); - ents->Add(world_entity); - - for (e=entities.next ; e!=&entities ; e=e->next) - { - // not sure this still happens, probably safe to leave it in - if ((!strcmp(ValueForKey (e, "classname"), "worldspawn")) && (e!=world_entity)) - { - Sys_FPrintf(SYS_ERR, "Dropping parasite worldspawn entity\n"); - continue; - } - - // entities which brushes are completely filtered out by regioning are not printed to the map - if (FilterChildren(e, bRegionOnly, bSelectedOnly)) - ents->Add(e); - } - - if (bRegionOnly && region_active) - { - for(i=0; i<6; i++) - ((CPtrArray*)world_entity->pData)->Add(region_sides[i]); - - ents->Add(region_startpoint); - } -} - -void Map_Export(IDataStream *out, const char *type, bool bRegionOnly, bool bSelectedOnly) -{ - entity_t *e; - - CPtrArray ents; - - if (bRegionOnly && region_active) - AddRegionBrushes(); - - // create the filters - world_entity->pData = new CPtrArray(); - for(e = entities.next; e != &entities; e = e->next) - e->pData = new CPtrArray(); - - Map_ExportEntities(&ents, bRegionOnly, bSelectedOnly); - - g_pParentWnd->GetSynapseClient().ExportMap(&ents, out, type); - - // cleanup the filters - CleanFilter(world_entity); - for (e=entities.next ; e!=&entities ; e=e->next) - CleanFilter(e); - - if (bRegionOnly && region_active) - RemoveRegionBrushes(); -} - -const char* filename_get_extension(const char* filename) -{ - const char* type = strrchr(filename,'.'); - if(type != NULL) - return ++type; - return ""; -} - -/* -=========== -Map_SaveFile -\todo FIXME remove the use_region, this is broken .. work with a global flag to set region mode or not -=========== -*/ -void Map_SaveFile (const char *filename, qboolean use_region ) -{ - clock_t start, finish; - double elapsed_time; - start = clock(); - Sys_Printf("Saving map to %s\n",filename); - - Pointfile_Clear (); - - if (!use_region) - { - char backup[1024]; - - // rename current to .bak - strcpy (backup, filename); - StripExtension (backup); - strcat (backup, ".bak"); - unlink (backup); - rename (filename, backup); - } - - Sys_Printf ("Map_SaveFile: %s\n", filename); - - // build the out data stream - FileStream file; - if (!file.Open(filename,"w")) - { - Sys_FPrintf(SYS_ERR, "ERROR: couldn't open %s for write\n", filename); - return; - } - - // extract filetype - Map_Export(&file, filename_get_extension(filename), use_region); - - file.Close(); - - finish = clock(); - elapsed_time = (double)(finish - start) / CLOCKS_PER_SEC; - - Sys_Printf ("Saved in %-.2f second(s).\n",elapsed_time); - modified = false; - - if ( !strstr( filename, "autosave" ) ) - Sys_SetTitle (filename); - - if (!use_region) - { - time_t timer; - - time (&timer); - - Sys_Beep (); - - Sys_Status ("Saved.", 0); - } -} - -/* -=========== -Map_New - -=========== -*/ -void Map_New (void) -{ - Sys_Printf ("Map_New\n"); - Map_Free (); - - strcpy (currentmap, "unnamed.map"); - Sys_SetTitle (currentmap); - - world_entity = (entity_s*)qmalloc(sizeof(*world_entity)); - world_entity->brushes.onext = - world_entity->brushes.oprev = &world_entity->brushes; - SetKeyValue (world_entity, "classname", "worldspawn"); - world_entity->eclass = Eclass_ForName ("worldspawn", true); - - g_pParentWnd->GetCamWnd()->Camera()->angles[YAW] = 0; - g_pParentWnd->GetCamWnd()->Camera()->angles[PITCH] = 0; - VectorCopy (vec3_origin, g_pParentWnd->GetCamWnd()->Camera()->origin); - g_pParentWnd->GetCamWnd()->Camera()->origin[2] = 48; - VectorCopy (vec3_origin, g_pParentWnd->GetXYWnd()->GetOrigin()); - - Map_RestoreBetween (); - - Group_Init(); - - Sys_UpdateWindows (W_ALL); - modified = false; -} - -/* -=========================================================== - - REGION - -=========================================================== -*/ -qboolean region_active; -vec3_t region_mins = {g_MinWorldCoord, g_MinWorldCoord, g_MinWorldCoord}; -vec3_t region_maxs = {g_MaxWorldCoord, g_MaxWorldCoord, g_MaxWorldCoord}; - -brush_t *region_sides[6]; - -/* -=========== -AddRegionBrushes -a regioned map will have temp walls put up at the region boundary -\todo TODO TTimo old implementation of region brushes - we still add them straight in the worldspawn and take them out after the map is saved - with the new implementation we should be able to append them in a temporary manner to the data we pass to the map module -=========== -*/ -void AddRegionBrushes (void) -{ - vec3_t mins, maxs; - int i; - texdef_t td; - - if (!region_active) - { -#ifdef _DEBUG - Sys_FPrintf( SYS_WRN, "Unexpected AddRegionBrushes call.\n"); -#endif - return; - } - - memset (&td, 0, sizeof(td)); - td.SetName(SHADER_NOT_FOUND); - - // set mins - VectorSet(mins, region_mins[0]-32, region_mins[1]-32, region_mins[2]-32); - - // vary maxs - for(i=0; i<3; i++) - { - VectorSet(maxs, region_maxs[0]+32, region_maxs[1]+32, region_maxs[2]+32); - maxs[i] = region_mins[i]; - region_sides[i] = Brush_Create (mins, maxs, &td); - } - - // set maxs - VectorSet(maxs, region_maxs[0]+32, region_maxs[1]+32, region_maxs[2]+32); - - // vary mins - for(i=0; i<3; i++) - { - VectorSet(mins, region_mins[0]-32, region_mins[1]-32, region_mins[2]-32); - mins[i] = region_maxs[i]; - region_sides[i+3] = Brush_Create (mins, maxs, &td); - } - - - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=503 - // this is a safe check, but it should not really happen anymore - vec3_t vOrig; - VectorSet(vOrig, - (int)g_pParentWnd->GetCamWnd()->Camera()->origin[0], - (int)g_pParentWnd->GetCamWnd()->Camera()->origin[1], - (int)g_pParentWnd->GetCamWnd()->Camera()->origin[2]); - - for (i=0 ; i<3 ; i++) - { - if (vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i]) - { - Sys_FPrintf(SYS_ERR, "Camera is NOT in the region, it's likely that the region won't compile correctly\n"); - } - } - - // write the info_playerstart - region_startpoint = Entity_Alloc(); - SetKeyValue(region_startpoint, "classname", "info_player_start"); - region_startpoint->eclass = Eclass_ForName ("info_player_start", false); - char sTmp[1024]; - sprintf(sTmp, "%d %d %d", (int)vOrig[0], (int)vOrig[1], (int)vOrig[2]); - SetKeyValue(region_startpoint, "origin", sTmp); - sprintf(sTmp, "%d", (int)g_pParentWnd->GetCamWnd()->Camera()->angles[YAW]); - SetKeyValue(region_startpoint, "angle", sTmp); - // empty array of children - region_startpoint->pData = new CPtrArray; -} - -void RemoveRegionBrushes (void) -{ - int i; - - if (!region_active) - return; - for (i=0 ; i<6 ; i++) - Brush_Free (region_sides[i]); - - CleanFilter(region_startpoint); - Entity_Free(region_startpoint); -} - -qboolean Map_IsBrushFiltered (brush_t *b) -{ - int i; - - for (i=0 ; i<3 ; i++) - { - if (b->mins[i] > region_maxs[i]) - return true; - if (b->maxs[i] < region_mins[i]) - return true; - } - return false; -} - -/* -=========== -Map_RegionOff - -Other filtering options may still be on -=========== -*/ -void Map_RegionOff (void) -{ - brush_t *b, *next; - int i; - - region_active = false; - for (i=0 ; i<3 ; i++) - { - region_maxs[i] = g_MaxWorldCoord-64; - region_mins[i] = g_MinWorldCoord+64; - } - - for (b=filtered_brushes.next ; b != &filtered_brushes ; b=next) - { - next = b->next; - if (Map_IsBrushFiltered (b)) - continue; // still filtered - Brush_RemoveFromList (b); - if (active_brushes.next == NULL || active_brushes.prev == NULL) - { - active_brushes.next = &active_brushes; - active_brushes.prev = &active_brushes; - } - Brush_AddToList (b, &active_brushes); - b->bFiltered = FilterBrush(b); - } - Sys_UpdateWindows (W_ALL); -} - -void Map_ApplyRegion (void) -{ - brush_t *b, *next; - - region_active = true; - for (b=active_brushes.next ; b != &active_brushes ; b=next) - { - next = b->next; - if (!Map_IsBrushFiltered (b)) - continue; // still filtered - Brush_RemoveFromList (b); - Brush_AddToList (b, &filtered_brushes); - } - - Sys_UpdateWindows (W_ALL); -} - - -/* -======================== -Map_RegionSelectedBrushes -======================== -*/ -void Map_RegionSelectedBrushes (void) -{ - Map_RegionOff (); - - if (selected_brushes.next == &selected_brushes) // nothing selected - { - Sys_Printf("Tried to region with no selection...\n"); - return; - } - region_active = true; - Select_GetBounds (region_mins, region_maxs); - -#ifdef _DEBUG - if (filtered_brushes.next != &filtered_brushes) - Sys_Printf("WARNING: filtered_brushes list may not be empty in Map_RegionSelectedBrushes\n"); -#endif - - if (active_brushes.next == &active_brushes) - { - // just have an empty filtered_brushes list - // this happens if you set region after selecting all the brushes in your map (some weird people do that, ask MrE!) - filtered_brushes.next = filtered_brushes.prev = &filtered_brushes; - } - else - { - // move the entire active_brushes list to filtered_brushes - filtered_brushes.next = active_brushes.next; - filtered_brushes.prev = active_brushes.prev; - filtered_brushes.next->prev = &filtered_brushes; - filtered_brushes.prev->next = &filtered_brushes; - } - - // move the entire selected_brushes list to active_brushes - active_brushes.next = selected_brushes.next; - active_brushes.prev = selected_brushes.prev; - active_brushes.next->prev = &active_brushes; - active_brushes.prev->next = &active_brushes; - - // deselect patches - for (brush_t *b = active_brushes.next; b != &active_brushes; b = b->next) - if (b->patchBrush) - b->pPatch->bSelected = false; - - // clear selected_brushes - selected_brushes.next = selected_brushes.prev = &selected_brushes; - - Sys_UpdateWindows (W_ALL); -} - - -/* -=========== -Map_RegionXY -=========== -*/ -void Map_RegionXY (void) -{ - Map_RegionOff (); - - region_mins[0] = g_pParentWnd->GetXYWnd()->GetOrigin()[0] - 0.5 * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(); - region_maxs[0] = g_pParentWnd->GetXYWnd()->GetOrigin()[0] + 0.5 * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(); - region_mins[1] = g_pParentWnd->GetXYWnd()->GetOrigin()[1] - 0.5 * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale(); - region_maxs[1] = g_pParentWnd->GetXYWnd()->GetOrigin()[1] + 0.5 * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale(); - region_mins[2] = g_MinWorldCoord+64; - region_maxs[2] = g_MaxWorldCoord-64; - Map_ApplyRegion (); -} - -/* -=========== -Map_RegionTallBrush -=========== -*/ -void Map_RegionTallBrush (void) -{ - brush_t *b; - - if (!QE_SingleBrush ()) - return; - - b = selected_brushes.next; - - Map_RegionOff (); - - VectorCopy (b->mins, region_mins); - VectorCopy (b->maxs, region_maxs); - region_mins[2] = g_MinWorldCoord+64; - region_maxs[2] = g_MaxWorldCoord-64; - - Undo_Start("delete"); - Undo_AddBrushList(&selected_brushes); - Undo_AddEntity(b->owner); - Select_Delete (); - Undo_EndBrushList(&selected_brushes); - Undo_End(); - - Map_ApplyRegion (); -} - -/* -=========== -Map_RegionBrush -=========== -*/ -void Map_RegionBrush (void) -{ - brush_t *b; - - if (!QE_SingleBrush ()) - return; - - b = selected_brushes.next; - - Map_RegionOff (); - - VectorCopy (b->mins, region_mins); - VectorCopy (b->maxs, region_maxs); - - Undo_Start("delete"); - Undo_AddBrushList(&selected_brushes); - Undo_AddEntity(b->owner); - Select_Delete (); - Undo_EndBrushList(&selected_brushes); - Undo_End(); - - Map_ApplyRegion (); -} - -GList *find_string(GList *glist, const char *buf) -{ - while (glist) - { - if (strcmp((char *)glist->data, buf) == 0) - break; // this name is in our list already - glist = glist->next; - } - return glist; -} - -void Map_ImportBuffer(char *buf) -{ - Select_Deselect(); - - Undo_Start("import buffer"); - - MemStream stream; - - stream.Write(buf, strlen(buf)); - Map_Import(&stream, "xmap"); - stream.Close(); - - Sys_UpdateWindows (W_ALL); - Sys_MarkMapModified(); - - Undo_End(); -} - - -// -//================ -//Map_ImportFile -//================ -// -void Map_ImportFile (const char *filename) -{ - FileStream file; - Sys_BeginWait (); - - Sys_Printf("Importing map from %s\n",filename); - - const char* type = strrchr(filename,'.'); - if(type!=NULL) type++; - /*!\todo Resolve "r" problem in scriptlib" */ - if(file.Open(filename, "rb")) - Map_Import(&file, type, true); - else - Sys_FPrintf(SYS_ERR, "ERROR: couldn't open %s for read\n", filename); - - file.Close(); - - Sys_UpdateWindows (W_ALL); - modified = true; - Sys_EndWait(); -} - -// -//=========== -//Map_SaveSelected -//=========== -// -// Saves selected world brushes and whole entities with partial/full selections -// -void Map_SaveSelected(const char* filename) -{ - FileStream file; - - Sys_Printf("Saving selection to %s\n",filename); - - const char* type = strrchr(filename,'.'); - if(type!=NULL) type++; - if(file.Open(filename, "w")) - Map_Export (&file, type, false, true); - else - Sys_FPrintf(SYS_ERR, "ERROR: failed to open %s for write\n", filename); - - file.Close(); - -} - -// -//=========== -//Map_SaveSelected -//=========== -// -// Saves selected world brushes and whole entities with partial/full selections -// -void Map_SaveSelected (MemStream* pMemFile, MemStream* pPatchFile) -{ - Map_Export (pMemFile, "xmap", false, true); - - /* - // write world entity first - Entity_WriteSelected(world_entity, pMemFile); - - // then write all other ents - count = 1; - for (e=entities.next ; e != &entities ; e=next) - { - MemFile_fprintf(pMemFile, "// entity %i\n", count); - count++; - Entity_WriteSelected(e, pMemFile); - next = e->next; - } - - //if (pPatchFile) - // Patch_WriteFile(pPatchFile); - */ -} - - -void MemFile_fprintf(MemStream* pMemFile, const char* pText, ...) -{ - char Buffer[4096]; - va_list args; - va_start (args,pText); - vsprintf(Buffer, pText, args); - pMemFile->Write(Buffer, strlen(Buffer)); -} - -/*! -============== -Region_SpawnPoint -push the region spawn point -\todo FIXME TTimo this was in the #1 MAP module implementation (in the core) -not sure it has any use anymore, should prolly drop it -============== -*/ -void Region_SpawnPoint(FILE *f) -{ - // write the info_player_start, we use the camera position - fprintf (f, "{\n"); - fprintf (f, "\"classname\" \"info_player_start\"\n"); - fprintf (f, "\"origin\" \"%i %i %i\"\n", - (int)g_pParentWnd->GetCamWnd()->Camera()->origin[0], - (int)g_pParentWnd->GetCamWnd()->Camera()->origin[1], - (int)g_pParentWnd->GetCamWnd()->Camera()->origin[2]); - fprintf (f, "\"angle\" \"%i\"\n", (int)g_pParentWnd->GetCamWnd()->Camera()->angles[YAW]); - fprintf (f, "}\n"); -} +/* +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 +*/ + +#include "stdafx.h" +#include +#if defined (__linux__) || defined (__APPLE__) +#include +#endif +#include "preferences.h" +#include "mainframe.h" +#include "gtkmisc.h" +#include "filters.h" + +extern MainFrame* g_pParentWnd; + +int modified; // for quit confirmation (0 = clean, 1 = unsaved, + // 2 = autosaved, but not regular saved) + +char currentmap[1024]; + +brush_t active_brushes; // brushes currently being displayed +brush_t selected_brushes; // highlighted + +face_t *selected_face; +brush_t *selected_face_brush; + +brush_t filtered_brushes; // brushes that have been filtered or regioned + +entity_t entities; // head/tail of doubly linked list + +entity_t *world_entity = NULL; // "classname" "worldspawn" ! + +void Map_Init() +{ + Map_Free(); +} + + +bool g_bCancel_Map_LoadFile; // Hydra: moved this here + +// TTimo +// need that in a variable, will have to tweak depending on the game +int g_MaxWorldCoord = 64*1024; +int g_MinWorldCoord = -64*1024; + +// the max size we allow on brushes, this is dependant on world coords too +// makes more sense to say smaller I think? +int g_MaxBrushSize = (g_MaxWorldCoord-1)*2; + +void AddRegionBrushes (void); +void RemoveRegionBrushes (void); + +/* +============================================================= + + Cross map selection saving + + this could fuck up if you have only part of a complex entity selected... +============================================================= +*/ + +brush_t between_brushes; +entity_t between_entities; + +bool g_bRestoreBetween = false; + +void Map_SaveBetween (void) +{ + if (g_pParentWnd->ActiveXY()) + { + g_bRestoreBetween = true; + g_pParentWnd->ActiveXY()->Copy(); + } + return; +} + +void Map_RestoreBetween (void) +{ + if (g_pParentWnd->ActiveXY() && g_bRestoreBetween) + g_pParentWnd->ActiveXY()->Paste(); +} + +//============================================================================ + +bool CheckForTinyBrush(brush_t* b, int n, float fSize) +{ + bool bTiny = false; + for (int i=0 ; i<3 ; i++) + { + if (b->maxs[i] - b->mins[i] < fSize) + bTiny = true; + } + if (bTiny) + Sys_Printf("Possible problem brush (too small) #%i ", n); + return bTiny; +} + +void Map_BuildBrushData(void) +{ + brush_t *b, *next; + + if (active_brushes.next == NULL) + return; + + Sys_BeginWait (); // this could take a while + + int n = 0; + for (b=active_brushes.next ; b != NULL && b != &active_brushes ; b=next) + { + next = b->next; + Brush_Build( b, true, false, false ); + if (!b->brush_faces || (g_PrefsDlg.m_bCleanTiny && CheckForTinyBrush(b, n++, g_PrefsDlg.m_fTinySize))) + { + Brush_Free (b); + Sys_Printf ("Removed degenerate brush\n"); + } + } + Sys_EndWait(); +} + +entity_t *Map_FindClass (char *cname) +{ + entity_t *ent; + + for (ent = entities.next ; ent != &entities ; ent=ent->next) + { + if (!strcmp(cname, ValueForKey (ent, "classname"))) + return ent; + } + return NULL; +} + +/* +================ +Map_Free +free all map elements, reinitialize the structures that depend on them +================ +*/ +void Map_Free (void) +{ + g_bRestoreBetween = false; + if (selected_brushes.next && + (selected_brushes.next != &selected_brushes)) + { + if (gtk_MessageBox (g_pParentWnd->m_pWidget, "Copy selection?", " ", MB_YESNO) == IDYES) + Map_SaveBetween (); + } + + QERApp_ActiveShaders_SetInUse( false ); + Pointfile_Clear (); + g_qeglobals.d_num_entities = 0; + + if (!active_brushes.next) + { + // first map + active_brushes.prev = active_brushes.next = &active_brushes; + selected_brushes.prev = selected_brushes.next = &selected_brushes; + filtered_brushes.prev = filtered_brushes.next = &filtered_brushes; + entities.prev = entities.next = &entities; + } + else + { + // free selected faces array + g_ptrSelectedFaces.RemoveAll(); + g_ptrSelectedFaceBrushes.RemoveAll(); + while (active_brushes.next != &active_brushes) + Brush_Free (active_brushes.next); + while (selected_brushes.next != &selected_brushes) + Brush_Free (selected_brushes.next); + while (filtered_brushes.next != &filtered_brushes) + Brush_Free (filtered_brushes.next); + while (entities.next != &entities) + Entity_Free (entities.next); + } + + if (world_entity) + Entity_Free(world_entity); + world_entity = NULL; +} + +entity_t *AngledEntity() +{ + entity_t *ent = Map_FindClass ("info_player_start"); + if (!ent) + { + ent = Map_FindClass ("info_player_deathmatch"); + } + if (!ent) + { + ent = Map_FindClass ("info_player_deathmatch"); + } + if (!ent) + { + ent = Map_FindClass ("team_CTF_redplayer"); + } + if (!ent) + { + ent = Map_FindClass ("team_CTF_blueplayer"); + } + if (!ent) + { + ent = Map_FindClass ("team_CTF_redspawn"); + } + if (!ent) + { + ent = Map_FindClass ("team_CTF_bluespawn"); + } + return ent; +} + +// +// move the view to a start position +// +void Map_StartPosition() +{ + entity_t *ent = AngledEntity(); + + g_pParentWnd->GetCamWnd()->Camera()->angles[PITCH] = 0; + if (ent) + { + GetVectorForKey (ent, "origin", g_pParentWnd->GetCamWnd()->Camera()->origin); + GetVectorForKey (ent, "origin", g_pParentWnd->GetXYWnd()->GetOrigin()); + g_pParentWnd->GetCamWnd()->Camera()->angles[YAW] = FloatForKey (ent, "angle"); + } + else + { + g_pParentWnd->GetCamWnd()->Camera()->angles[YAW] = 0; + VectorCopy (vec3_origin, g_pParentWnd->GetCamWnd()->Camera()->origin); + VectorCopy (vec3_origin, g_pParentWnd->GetXYWnd()->GetOrigin()); + } +} + +void Map_FreeEntities(CPtrArray *ents) +{ + int i, j, num_ents, num_brushes; + entity_t* e; + CPtrArray* brushes; + + num_ents = ents->GetSize(); + for(i=0; iGetAt(i); + brushes = (CPtrArray*)e->pData; + num_brushes = brushes->GetSize(); + for(j=0; jGetAt(j)); + brushes->RemoveAll(); + delete (CPtrArray*)e->pData; + e->pData = NULL; + Entity_Free(e); + } + ents->RemoveAll(); +} + +/*!\todo Possibly make the import Undo-friendly by calling Undo_End for new brushes and ents */ +void Map_ImportEntities(CPtrArray *ents, bool bAddSelected = false) +{ + int num_ents, num_brushes; + CPtrArray *brushes; + vec3_t mins, maxs; + entity_t *e; + brush_t *b; + face_t *f; + int i,j; + + GPtrArray *new_ents = g_ptr_array_new(); + + g_qeglobals.bPrimitBrushes = false; + + brush_t *pBrushList = (bAddSelected) ? &selected_brushes : &active_brushes; + + bool bDoneBPCheck = false; + g_qeglobals.bNeedConvert = false; + // HACK: find out if this map file was a BP one + // check the first brush in the file that is NOT a patch + // this will not be necessary when we allow both formats in the same file + num_ents = ents->GetSize(); + for(i=0; !bDoneBPCheck && iGetAt(i); + brushes = (CPtrArray*)e->pData; + num_brushes = brushes->GetSize(); + for(j=0; !bDoneBPCheck && jGetAt(j); + if(b->patchBrush) continue; + bDoneBPCheck = true; + int BP_param = -1; + if(b->bBrushDef && !g_qeglobals.m_bBrushPrimitMode) + BP_param = 0; + else if(!b->bBrushDef && g_qeglobals.m_bBrushPrimitMode) + BP_param = 1; + + if(BP_param != -1) + { + switch(BP_MessageBox(BP_param)) + { + case 0: + Map_FreeEntities(ents); + return; + case 1: + g_qeglobals.bNeedConvert = true; + break; + case 2: + g_qeglobals.bNeedConvert = false; + break; + } + } + } + } + + // process the entities into the world geometry + num_ents = ents->GetSize(); + for(i=0; iGetAt(i); + brushes = (CPtrArray*)e->pData; + + num_brushes = brushes->GetSize(); + // link brushes into entity + for(j=0; jGetAt(j)); + g_qeglobals.d_parsed_brushes++; + } + brushes->RemoveAll(); + delete brushes; + e->pData = NULL; + + // set entity origin + GetVectorForKey (e, "origin", e->origin); + // set entity eclass + /*!\todo Make SetKeyValue check for "classname" change and assign appropriate eclass */ + e->eclass = Eclass_ForName (ValueForKey (e, "classname"), + (e->brushes.onext != &e->brushes)); + + // go through all parsed brushes and build stuff + for(b = e->brushes.onext; b!=&e->brushes; b=b->onext) + { + for(f = b->brush_faces; f != NULL; f = f->next) + { + f->pShader = QERApp_Shader_ForName(f->texdef.GetName()); + f->d_texture = f->pShader->getTexture(); + } + + // when brushes are in final state, build the planes and windings + // NOTE: also converts BP brushes if g_qeglobals.bNeedConvert is true + Brush_Build(b); + } + +//#define TERRAIN_HACK +#undef TERRAIN_HACK + +#ifdef TERRAIN_HACK + if ((strcmp(ValueForKey(e, "terrain"),"1") == 0 && strcmp(e->eclass->name,"func_group") == 0)) + { + + // two aux pointers to the shaders used in the terrain entity + // we don't keep refcount on them since they are only temporary + // this avoids doing expensive lookups by name for all faces + IShader *pTerrainShader, *pCaulk; + + pTerrainShader = NULL; + pCaulk = QERApp_Shader_ForName(SHADER_CAULK); + + for(b = e->brushes.onext; b!=&e->brushes; b=b->onext) + { + if (pTerrainShader == NULL) + for(f = b->brush_faces; f != NULL; f = f->next) + if (strcmp(f->texdef.GetName(), SHADER_CAULK)!=0) + pTerrainShader = f->pShader; + + if (pTerrainShader) + { + for(f = b->brush_faces; f != NULL; f = f->next) + { + if (strcmp(f->texdef.GetName(), SHADER_CAULK)!=0) // not caulk + Face_SetShader(f, pTerrainShader->getName()); + else + Face_SetShader(f, pCaulk->getName()); + } + } + else + Sys_Printf("WARNING: no terrain shader found for brush\n"); + } + } +#endif + +#define PATCH_HACK +#ifdef PATCH_HACK + for(b = e->brushes.onext; b!=&e->brushes; b=b->onext) + { + // patch hack, to be removed when dependency on brush_faces is removed + if (b->patchBrush) + { + Patch_CalcBounds(b->pPatch, mins, maxs); + for (int i=0; i<3; i++) + { + if ((int)mins[i] == (int)maxs[i]) + { + mins[i] -= 4; + maxs[i] += 4; + } + } + Brush_Resize(b, mins, maxs); + Brush_Build(b); + } + } +#endif + // add brush for fixedsize entity + if (e->eclass->fixedsize) + { + vec3_t mins, maxs; + VectorAdd (e->eclass->mins, e->origin, mins); + VectorAdd (e->eclass->maxs, e->origin, maxs); + b = Brush_Create (mins, maxs, &e->eclass->texdef); + Entity_LinkBrush(e, b); + Brush_Build(b); + } + + for(b = e->brushes.onext; b!=&e->brushes; b=b->onext) + Brush_AddToList(b, pBrushList); + + if (strcmp(e->eclass->name, "worldspawn") == 0) + { + if (world_entity) + { + while(e->brushes.onext != &e->brushes) + { + b = e->brushes.onext; + Entity_UnlinkBrush(b); + Entity_LinkBrush(world_entity, b); + } + Entity_Free(e); + } + else + { + world_entity = e; + } + } + else if (strcmp(e->eclass->name, "group_info") == 0) + { + // it's a group thing! + Group_Add(e); + Entity_Free(e); + } + else + { + // fix target/targetname collisions + if ((g_PrefsDlg.m_bDoTargetFix) && (strcmp(ValueForKey(e, "target"), "") != 0)) + { + GPtrArray *t_ents = g_ptr_array_new(); + entity_t *e_target; + const char *target = ValueForKey(e, "target"); + qboolean bCollision=FALSE; + + // check the current map entities for an actual collision + for (e_target = entities.next; e_target != &entities; e_target = e_target->next) + { + if(!strcmp(target, ValueForKey(e_target, "target"))) + { + bCollision = TRUE; + // make sure the collision is not between two imported entities + for(j=0; j<(int)new_ents->len; j++) + { + if(e_target == g_ptr_array_index(new_ents, j)) + bCollision = FALSE; + } + } + } + + // find the matching targeted entity(s) + if(bCollision) + { + for(j=num_ents-1; j>0; j--) + { + e_target = (entity_t*)ents->GetAt(j); + if(e_target != NULL && e_target != e) + { + const char *targetname = ValueForKey(e_target, "targetname"); + if( (targetname != NULL) && (strcmp(target, targetname) == 0) ) + g_ptr_array_add(t_ents, (gpointer)e_target); + } + } + if(t_ents->len > 0) + { + // link the first to get a unique target/targetname + Entity_Connect(e, (entity_t*)g_ptr_array_index(t_ents,0)); + // set the targetname of the rest of them manually + for(j = 1; j < (int)t_ents->len; j++) + SetKeyValue( (entity_t*)g_ptr_array_index(t_ents, j), "targetname", ValueForKey(e, "target") ); + } + g_ptr_array_free(t_ents, FALSE); + } + } + + // add the entity to the end of the entity list + Entity_AddToList(e, &entities); + g_qeglobals.d_num_entities++; + + // keep a list of ents added to avoid testing collisions against them + g_ptr_array_add(new_ents, (gpointer)e); + } + } + g_ptr_array_free(new_ents, FALSE); + + ents->RemoveAll(); + + g_qeglobals.bNeedConvert = false; +} + +void Map_Import(IDataStream *in, const char *type, bool bAddSelected) +{ + CPtrArray ents; + + g_pParentWnd->GetSynapseClient().ImportMap(in, &ents, type); + Map_ImportEntities(&ents, bAddSelected); +} + +/* +================ +Map_LoadFile +================ +*/ +void Map_LoadFile (const char *filename) +{ + clock_t start, finish; + double elapsed_time; + start = clock(); + + Sys_BeginWait (); + Select_Deselect(); + /*! + \todo FIXME TTimo why is this commented out? + stability issues maybe? or duplicate feature? + forcing to show the console during map load was a good thing IMO + */ + //SetInspectorMode(W_CONSOLE); + Sys_Printf ("Loading map from %s\n", filename ); + + Map_Free (); + //++timo FIXME: maybe even easier to have Group_Init called from Map_Free? + Group_Init(); + g_qeglobals.d_num_entities = 0; + g_qeglobals.d_parsed_brushes = 0; + + + // cancel the map loading process + // used when conversion between standard map format and BP format is required and the user cancels the process + g_bCancel_Map_LoadFile = false; + + strcpy (currentmap, filename); + + g_bScreenUpdates = false; // leo: avoid redraws while loading the map (see fenris:1952) + + // prepare to let the map module do the parsing + FileStream file; + const char* type = strrchr(filename,'.'); + if(type!=NULL) type++; + // NOTE TTimo opening has binary doesn't make a lot of sense + // but opening as text confuses the scriptlib parser + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=261 + // this may be a problem if we "rb" and use the XML parser, might have an incompatibility + if (file.Open(filename, "rb")) + Map_Import(&file, type); + else + Sys_FPrintf(SYS_ERR, "ERROR: failed to open %s for read\n", filename); + file.Close(); + + g_bScreenUpdates = true; + + if (g_bCancel_Map_LoadFile) + { + Sys_Printf("Map_LoadFile canceled\n"); + Map_New(); + Sys_EndWait(); + return; + } + + if (!world_entity) + { + Sys_Printf ("No worldspawn in map.\n"); + Map_New (); + Sys_EndWait(); + return; + } + finish = clock(); + elapsed_time = (double)(finish - start) / CLOCKS_PER_SEC; + + Sys_Printf ("--- LoadMapFile ---\n"); + Sys_Printf ("%s\n", filename ); + + Sys_Printf ("%5i brushes\n", g_qeglobals.d_parsed_brushes ); + Sys_Printf ("%5i entities\n", g_qeglobals.d_num_entities); + Sys_Printf ("%5.2f second(s) load time\n", elapsed_time ); + + Sys_EndWait(); + + Map_RestoreBetween (); + + // + // move the view to a start position + // + Map_StartPosition(); + + Map_RegionOff (); + + modified = false; + Sys_SetTitle (filename); + + Texture_ShowInuse (); + QERApp_SortActiveShaders(); + + Sys_UpdateWindows (W_ALL); +} + +/*! +=========== +Supporting functions for Map_SaveFile, builds a CPtrArray with the filtered / non filtered brushes +=========== +*/ +void CleanFilter(entity_t *ent) +{ + if (ent->pData) + { + delete static_cast(ent->pData); + ent->pData = NULL; + } +} + +/*! +filters out the region brushes if necessary +returns true if this entity as a whole is out of the region +(if all brushes are filtered out, then the entity will be completely dropped .. except if it's worldspawn of course) +*/ +bool FilterChildren(entity_t *ent, bool bRegionOnly = false, bool bSelectedOnly = false) +{ + if(ent->brushes.onext == &ent->brushes) + return false; + // entity without a brush, ignore it... this can be caused by Undo + + // filter fixedsize ents by their eclass bounding box + // don't add their brushes + if (ent->eclass->fixedsize) + { + if(bSelectedOnly && !IsBrushSelected(ent->brushes.onext)) + return false; + + if(bRegionOnly && region_active) + { + for (int i=0 ; i<3 ; i++) + { + if ((ent->origin[i] + ent->eclass->mins[i]) > region_maxs[i]) + return false; + if ((ent->origin[i] + ent->eclass->maxs[i]) < region_mins[i]) + return false; + } + } + } + else + { + for (brush_t *b = ent->brushes.onext ; b != &ent->brushes ; b=b->onext) + { + // set flag to use brushprimit_texdef + if(g_qeglobals.m_bBrushPrimitMode) + b->bBrushDef = true; + else + b->bBrushDef = false; + + // add brush, unless it's excluded by region + if ( !(bRegionOnly && Map_IsBrushFiltered(b)) && + !(bSelectedOnly && !IsBrushSelected(b)) ) + ((CPtrArray*)ent->pData)->Add(b); + } + + if (((CPtrArray*)ent->pData)->GetSize() <= 0) + return false; + } + return true; +} + +entity_t *region_startpoint = NULL; +void Map_ExportEntities(CPtrArray* ents, bool bRegionOnly = false, bool bSelectedOnly = false) +{ + int i; + entity_t *e; + + /*! + \todo the entity_t needs to be reworked and asbtracted some more + + keeping the entity_t as the struct providing access to a list of map objects, a list of epairs and various other info? + but separating some more the data that belongs to the entity_t and the 'sons' data + on a side note, I don't think that doing that with linked list would be a good thing + + for now, we use the blind void* in entity_t casted to a CPtrArray of brush_t* to hand out a list of the brushes for map write + the next step is very likely to be a change of the brush_t* to a more abstract object? + */ + + FilterChildren(world_entity, bRegionOnly, bSelectedOnly); + ents->Add(world_entity); + + for (e=entities.next ; e!=&entities ; e=e->next) + { + // not sure this still happens, probably safe to leave it in + if ((!strcmp(ValueForKey (e, "classname"), "worldspawn")) && (e!=world_entity)) + { + Sys_FPrintf(SYS_ERR, "Dropping parasite worldspawn entity\n"); + continue; + } + + // entities which brushes are completely filtered out by regioning are not printed to the map + if (FilterChildren(e, bRegionOnly, bSelectedOnly)) + ents->Add(e); + } + + if (bRegionOnly && region_active) + { + for(i=0; i<6; i++) + ((CPtrArray*)world_entity->pData)->Add(region_sides[i]); + + ents->Add(region_startpoint); + } +} + +void Map_Export(IDataStream *out, const char *type, bool bRegionOnly, bool bSelectedOnly) +{ + entity_t *e; + + CPtrArray ents; + + if (bRegionOnly && region_active) + AddRegionBrushes(); + + // create the filters + world_entity->pData = new CPtrArray(); + for(e = entities.next; e != &entities; e = e->next) + e->pData = new CPtrArray(); + + Map_ExportEntities(&ents, bRegionOnly, bSelectedOnly); + + g_pParentWnd->GetSynapseClient().ExportMap(&ents, out, type); + + // cleanup the filters + CleanFilter(world_entity); + for (e=entities.next ; e!=&entities ; e=e->next) + CleanFilter(e); + + if (bRegionOnly && region_active) + RemoveRegionBrushes(); +} + +const char* filename_get_extension(const char* filename) +{ + const char* type = strrchr(filename,'.'); + if(type != NULL) + return ++type; + return ""; +} + +/* +=========== +Map_SaveFile +\todo FIXME remove the use_region, this is broken .. work with a global flag to set region mode or not +=========== +*/ +void Map_SaveFile (const char *filename, qboolean use_region ) +{ + clock_t start, finish; + double elapsed_time; + start = clock(); + Sys_Printf("Saving map to %s\n",filename); + + Pointfile_Clear (); + + if (!use_region) + { + char backup[1024]; + + // rename current to .bak + strcpy (backup, filename); + StripExtension (backup); + strcat (backup, ".bak"); + unlink (backup); + rename (filename, backup); + } + + Sys_Printf ("Map_SaveFile: %s\n", filename); + + // build the out data stream + FileStream file; + if (!file.Open(filename,"w")) + { + Sys_FPrintf(SYS_ERR, "ERROR: couldn't open %s for write\n", filename); + return; + } + + // extract filetype + Map_Export(&file, filename_get_extension(filename), use_region); + + file.Close(); + + finish = clock(); + elapsed_time = (double)(finish - start) / CLOCKS_PER_SEC; + + Sys_Printf ("Saved in %-.2f second(s).\n",elapsed_time); + modified = false; + + if ( !strstr( filename, "autosave" ) ) + Sys_SetTitle (filename); + + if (!use_region) + { + time_t timer; + + time (&timer); + + Sys_Beep (); + + Sys_Status ("Saved.", 0); + } +} + +/* +=========== +Map_New + +=========== +*/ +void Map_New (void) +{ + Sys_Printf ("Map_New\n"); + Map_Free (); + + strcpy (currentmap, "unnamed.map"); + Sys_SetTitle (currentmap); + + world_entity = (entity_s*)qmalloc(sizeof(*world_entity)); + world_entity->brushes.onext = + world_entity->brushes.oprev = &world_entity->brushes; + SetKeyValue (world_entity, "classname", "worldspawn"); + world_entity->eclass = Eclass_ForName ("worldspawn", true); + + g_pParentWnd->GetCamWnd()->Camera()->angles[YAW] = 0; + g_pParentWnd->GetCamWnd()->Camera()->angles[PITCH] = 0; + VectorCopy (vec3_origin, g_pParentWnd->GetCamWnd()->Camera()->origin); + g_pParentWnd->GetCamWnd()->Camera()->origin[2] = 48; + VectorCopy (vec3_origin, g_pParentWnd->GetXYWnd()->GetOrigin()); + + Map_RestoreBetween (); + + Group_Init(); + + Sys_UpdateWindows (W_ALL); + modified = false; +} + +/* +=========================================================== + + REGION + +=========================================================== +*/ +qboolean region_active; +vec3_t region_mins = {g_MinWorldCoord, g_MinWorldCoord, g_MinWorldCoord}; +vec3_t region_maxs = {g_MaxWorldCoord, g_MaxWorldCoord, g_MaxWorldCoord}; + +brush_t *region_sides[6]; + +/* +=========== +AddRegionBrushes +a regioned map will have temp walls put up at the region boundary +\todo TODO TTimo old implementation of region brushes + we still add them straight in the worldspawn and take them out after the map is saved + with the new implementation we should be able to append them in a temporary manner to the data we pass to the map module +=========== +*/ +void AddRegionBrushes (void) +{ + vec3_t mins, maxs; + int i; + texdef_t td; + + if (!region_active) + { +#ifdef _DEBUG + Sys_FPrintf( SYS_WRN, "Unexpected AddRegionBrushes call.\n"); +#endif + return; + } + + memset (&td, 0, sizeof(td)); + td.SetName(SHADER_NOT_FOUND); + + // set mins + VectorSet(mins, region_mins[0]-32, region_mins[1]-32, region_mins[2]-32); + + // vary maxs + for(i=0; i<3; i++) + { + VectorSet(maxs, region_maxs[0]+32, region_maxs[1]+32, region_maxs[2]+32); + maxs[i] = region_mins[i]; + region_sides[i] = Brush_Create (mins, maxs, &td); + } + + // set maxs + VectorSet(maxs, region_maxs[0]+32, region_maxs[1]+32, region_maxs[2]+32); + + // vary mins + for(i=0; i<3; i++) + { + VectorSet(mins, region_mins[0]-32, region_mins[1]-32, region_mins[2]-32); + mins[i] = region_maxs[i]; + region_sides[i+3] = Brush_Create (mins, maxs, &td); + } + + + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=503 + // this is a safe check, but it should not really happen anymore + vec3_t vOrig; + VectorSet(vOrig, + (int)g_pParentWnd->GetCamWnd()->Camera()->origin[0], + (int)g_pParentWnd->GetCamWnd()->Camera()->origin[1], + (int)g_pParentWnd->GetCamWnd()->Camera()->origin[2]); + + for (i=0 ; i<3 ; i++) + { + if (vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i]) + { + Sys_FPrintf(SYS_ERR, "Camera is NOT in the region, it's likely that the region won't compile correctly\n"); + } + } + + // write the info_playerstart + region_startpoint = Entity_Alloc(); + SetKeyValue(region_startpoint, "classname", "info_player_start"); + region_startpoint->eclass = Eclass_ForName ("info_player_start", false); + char sTmp[1024]; + sprintf(sTmp, "%d %d %d", (int)vOrig[0], (int)vOrig[1], (int)vOrig[2]); + SetKeyValue(region_startpoint, "origin", sTmp); + sprintf(sTmp, "%d", (int)g_pParentWnd->GetCamWnd()->Camera()->angles[YAW]); + SetKeyValue(region_startpoint, "angle", sTmp); + // empty array of children + region_startpoint->pData = new CPtrArray; +} + +void RemoveRegionBrushes (void) +{ + int i; + + if (!region_active) + return; + for (i=0 ; i<6 ; i++) + Brush_Free (region_sides[i]); + + CleanFilter(region_startpoint); + Entity_Free(region_startpoint); +} + +qboolean Map_IsBrushFiltered (brush_t *b) +{ + int i; + + for (i=0 ; i<3 ; i++) + { + if (b->mins[i] > region_maxs[i]) + return true; + if (b->maxs[i] < region_mins[i]) + return true; + } + return false; +} + +/* +=========== +Map_RegionOff + +Other filtering options may still be on +=========== +*/ +void Map_RegionOff (void) +{ + brush_t *b, *next; + int i; + + region_active = false; + for (i=0 ; i<3 ; i++) + { + region_maxs[i] = g_MaxWorldCoord-64; + region_mins[i] = g_MinWorldCoord+64; + } + + for (b=filtered_brushes.next ; b != &filtered_brushes ; b=next) + { + next = b->next; + if (Map_IsBrushFiltered (b)) + continue; // still filtered + Brush_RemoveFromList (b); + if (active_brushes.next == NULL || active_brushes.prev == NULL) + { + active_brushes.next = &active_brushes; + active_brushes.prev = &active_brushes; + } + Brush_AddToList (b, &active_brushes); + b->bFiltered = FilterBrush(b); + } + Sys_UpdateWindows (W_ALL); +} + +void Map_ApplyRegion (void) +{ + brush_t *b, *next; + + region_active = true; + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + if (!Map_IsBrushFiltered (b)) + continue; // still filtered + Brush_RemoveFromList (b); + Brush_AddToList (b, &filtered_brushes); + } + + Sys_UpdateWindows (W_ALL); +} + + +/* +======================== +Map_RegionSelectedBrushes +======================== +*/ +void Map_RegionSelectedBrushes (void) +{ + Map_RegionOff (); + + if (selected_brushes.next == &selected_brushes) // nothing selected + { + Sys_Printf("Tried to region with no selection...\n"); + return; + } + region_active = true; + Select_GetBounds (region_mins, region_maxs); + +#ifdef _DEBUG + if (filtered_brushes.next != &filtered_brushes) + Sys_Printf("WARNING: filtered_brushes list may not be empty in Map_RegionSelectedBrushes\n"); +#endif + + if (active_brushes.next == &active_brushes) + { + // just have an empty filtered_brushes list + // this happens if you set region after selecting all the brushes in your map (some weird people do that, ask MrE!) + filtered_brushes.next = filtered_brushes.prev = &filtered_brushes; + } + else + { + // move the entire active_brushes list to filtered_brushes + filtered_brushes.next = active_brushes.next; + filtered_brushes.prev = active_brushes.prev; + filtered_brushes.next->prev = &filtered_brushes; + filtered_brushes.prev->next = &filtered_brushes; + } + + // move the entire selected_brushes list to active_brushes + active_brushes.next = selected_brushes.next; + active_brushes.prev = selected_brushes.prev; + active_brushes.next->prev = &active_brushes; + active_brushes.prev->next = &active_brushes; + + // deselect patches + for (brush_t *b = active_brushes.next; b != &active_brushes; b = b->next) + if (b->patchBrush) + b->pPatch->bSelected = false; + + // clear selected_brushes + selected_brushes.next = selected_brushes.prev = &selected_brushes; + + Sys_UpdateWindows (W_ALL); +} + + +/* +=========== +Map_RegionXY +=========== +*/ +void Map_RegionXY (void) +{ + Map_RegionOff (); + + region_mins[0] = g_pParentWnd->GetXYWnd()->GetOrigin()[0] - 0.5 * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(); + region_maxs[0] = g_pParentWnd->GetXYWnd()->GetOrigin()[0] + 0.5 * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(); + region_mins[1] = g_pParentWnd->GetXYWnd()->GetOrigin()[1] - 0.5 * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale(); + region_maxs[1] = g_pParentWnd->GetXYWnd()->GetOrigin()[1] + 0.5 * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale(); + region_mins[2] = g_MinWorldCoord+64; + region_maxs[2] = g_MaxWorldCoord-64; + Map_ApplyRegion (); +} + +/* +=========== +Map_RegionTallBrush +=========== +*/ +void Map_RegionTallBrush (void) +{ + brush_t *b; + + if (!QE_SingleBrush ()) + return; + + b = selected_brushes.next; + + Map_RegionOff (); + + VectorCopy (b->mins, region_mins); + VectorCopy (b->maxs, region_maxs); + region_mins[2] = g_MinWorldCoord+64; + region_maxs[2] = g_MaxWorldCoord-64; + + Undo_Start("delete"); + Undo_AddBrushList(&selected_brushes); + Undo_AddEntity(b->owner); + Select_Delete (); + Undo_EndBrushList(&selected_brushes); + Undo_End(); + + Map_ApplyRegion (); +} + +/* +=========== +Map_RegionBrush +=========== +*/ +void Map_RegionBrush (void) +{ + brush_t *b; + + if (!QE_SingleBrush ()) + return; + + b = selected_brushes.next; + + Map_RegionOff (); + + VectorCopy (b->mins, region_mins); + VectorCopy (b->maxs, region_maxs); + + Undo_Start("delete"); + Undo_AddBrushList(&selected_brushes); + Undo_AddEntity(b->owner); + Select_Delete (); + Undo_EndBrushList(&selected_brushes); + Undo_End(); + + Map_ApplyRegion (); +} + +GList *find_string(GList *glist, const char *buf) +{ + while (glist) + { + if (strcmp((char *)glist->data, buf) == 0) + break; // this name is in our list already + glist = glist->next; + } + return glist; +} + +void Map_ImportBuffer(char *buf) +{ + Select_Deselect(); + + Undo_Start("import buffer"); + + MemStream stream; + + stream.Write(buf, strlen(buf)); + Map_Import(&stream, "xmap"); + stream.Close(); + + Sys_UpdateWindows (W_ALL); + Sys_MarkMapModified(); + + Undo_End(); +} + + +// +//================ +//Map_ImportFile +//================ +// +void Map_ImportFile (const char *filename) +{ + FileStream file; + Sys_BeginWait (); + + Sys_Printf("Importing map from %s\n",filename); + + const char* type = strrchr(filename,'.'); + if(type!=NULL) type++; + /*!\todo Resolve "r" problem in scriptlib" */ + if(file.Open(filename, "rb")) + Map_Import(&file, type, true); + else + Sys_FPrintf(SYS_ERR, "ERROR: couldn't open %s for read\n", filename); + + file.Close(); + + Sys_UpdateWindows (W_ALL); + modified = true; + Sys_EndWait(); +} + +// +//=========== +//Map_SaveSelected +//=========== +// +// Saves selected world brushes and whole entities with partial/full selections +// +void Map_SaveSelected(const char* filename) +{ + FileStream file; + + Sys_Printf("Saving selection to %s\n",filename); + + const char* type = strrchr(filename,'.'); + if(type!=NULL) type++; + if(file.Open(filename, "w")) + Map_Export (&file, type, false, true); + else + Sys_FPrintf(SYS_ERR, "ERROR: failed to open %s for write\n", filename); + + file.Close(); + +} + +// +//=========== +//Map_SaveSelected +//=========== +// +// Saves selected world brushes and whole entities with partial/full selections +// +void Map_SaveSelected (MemStream* pMemFile, MemStream* pPatchFile) +{ + Map_Export (pMemFile, "xmap", false, true); + + /* + // write world entity first + Entity_WriteSelected(world_entity, pMemFile); + + // then write all other ents + count = 1; + for (e=entities.next ; e != &entities ; e=next) + { + MemFile_fprintf(pMemFile, "// entity %i\n", count); + count++; + Entity_WriteSelected(e, pMemFile); + next = e->next; + } + + //if (pPatchFile) + // Patch_WriteFile(pPatchFile); + */ +} + + +void MemFile_fprintf(MemStream* pMemFile, const char* pText, ...) +{ + char Buffer[4096]; + va_list args; + va_start (args,pText); + vsprintf(Buffer, pText, args); + pMemFile->Write(Buffer, strlen(Buffer)); +} + +/*! +============== +Region_SpawnPoint +push the region spawn point +\todo FIXME TTimo this was in the #1 MAP module implementation (in the core) +not sure it has any use anymore, should prolly drop it +============== +*/ +void Region_SpawnPoint(FILE *f) +{ + // write the info_player_start, we use the camera position + fprintf (f, "{\n"); + fprintf (f, "\"classname\" \"info_player_start\"\n"); + fprintf (f, "\"origin\" \"%i %i %i\"\n", + (int)g_pParentWnd->GetCamWnd()->Camera()->origin[0], + (int)g_pParentWnd->GetCamWnd()->Camera()->origin[1], + (int)g_pParentWnd->GetCamWnd()->Camera()->origin[2]); + fprintf (f, "\"angle\" \"%i\"\n", (int)g_pParentWnd->GetCamWnd()->Camera()->angles[YAW]); + fprintf (f, "}\n"); +} diff --git a/radiant/missing.cpp b/radiant/missing.cpp index cf1c5b2d..cf7c820f 100644 --- a/radiant/missing.cpp +++ b/radiant/missing.cpp @@ -1,203 +1,203 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -// -// Missing functions -// -// Leonardo Zide (leo@lokigames.com) -// - -#if defined (__linux__) || defined (__APPLE__) - -#include -#include -#include -#include -#include "missing.h" - -bool CopyFile(const char *lpExistingFileName, const char *lpNewFileName) -{ - FILE *src, *dst; - void* buf; - int l, ret = 0; - char realsrc[PATH_MAX], realdest[PATH_MAX]; - - realpath (lpExistingFileName, realsrc); - realpath (lpNewFileName, realdest); - - src = fopen (realsrc, "rb"); - if (!src) - return 0; - dst = fopen (realdest, "wb"); - if (!dst) - { - fclose (src); - return 0; - } - - fseek (src, 0, SEEK_END); - l = ftell (src); - rewind (src); - buf = g_malloc (l); - - if (buf != NULL) - if (fread (buf, l, 1, src) == 1) - if (fwrite (buf, l, 1, dst) == 1) - ret = 1; - - g_free (buf); - fclose (src); - fclose (dst); - - return ret; -} - -int GetFullPathName(const char *lpFileName, int nBufferLength, char *lpBuffer, char **lpFilePart) -{ - if (lpFileName[0] == '/') - { - strcpy (lpBuffer, lpFileName); - *lpFilePart = strrchr (lpBuffer, '/'); - return strlen (lpBuffer); - } - - if (getcwd (lpBuffer, nBufferLength) == NULL) - return 0; - - strcat (lpBuffer, "/"); - *lpFilePart = lpBuffer + strlen (lpBuffer); - strcat (lpBuffer, lpFileName); - - char *scr = lpBuffer, *dst = lpBuffer; - for (int i = 0; (i < nBufferLength) && (*scr != 0); i++) - { - if (*scr == '/' && *(scr+1) == '.' && *(scr+2) == '.') - { - scr += 4; - while (dst != lpBuffer && *dst != '/') - { - dst--; - i--; - } - } - - *dst = *scr; - - scr++; dst++; - } - *dst = 0; - - return strlen (lpBuffer); -} -/* -static void g_string_sprintfa_int (GString *string, const gchar *fmt, va_list args) -{ - gchar *buffer; - - buffer = g_strdup_vprintf (fmt, args); - g_string_append (string, buffer); - g_free (buffer); -} - -const CString& CString::operator=(const char* lpsz) -{ - g_string_assign (m_str, lpsz); - return *this; -} - -const CString& CString::operator+=(const char* lpsz) -{ - g_string_append (m_str, lpsz); - return *this; -} - -CString::operator char*() const -{ - return m_str->str; -} - -void CString::Format(const char* fmt, ...) -{ - va_list args; - - g_string_truncate (m_str, 0); - - va_start (args, fmt); - g_string_sprintfa_int (m_str, fmt, args); - va_end (args); -} - -CString CString::Right(int nCount) const -{ - if (nCount < 0) - nCount = 0; - else if (nCount > m_str->len) - nCount = m_str->len; - - CString dest (&m_str->str[m_str->len-nCount]); - return dest; -} - -CString CString::Left(int nCount) const -{ - if (nCount < 0) - nCount = 0; - else if (nCount > m_str->len) - nCount = m_str->len; - - CString dest; - dest.m_str = g_string_sized_new (nCount); - memcpy (dest.m_str->str, m_str->str, nCount); - dest.m_str->str[nCount] = 0; - return dest; -} - -void CString::SetAt(int nIndex, char ch) -{ - if (nIndex >= 0 && nIndex < m_str->len) - m_str->str[nIndex] = ch; -} - -char CString::GetAt(int nIndex) const -{ - if (nIndex >= 0 && nIndex < m_str->len) - return m_str->str[nIndex]; - return 0; -} - -char CString::operator[](int nIndex) const -{ - if (nIndex >= 0 && nIndex < m_str->len) - return m_str->str[nIndex]; - return 0; -} -*/ - -#endif +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// +// Missing functions +// +// Leonardo Zide (leo@lokigames.com) +// + +#if defined (__linux__) || defined (__APPLE__) + +#include +#include +#include +#include +#include "missing.h" + +bool CopyFile(const char *lpExistingFileName, const char *lpNewFileName) +{ + FILE *src, *dst; + void* buf; + int l, ret = 0; + char realsrc[PATH_MAX], realdest[PATH_MAX]; + + realpath (lpExistingFileName, realsrc); + realpath (lpNewFileName, realdest); + + src = fopen (realsrc, "rb"); + if (!src) + return 0; + dst = fopen (realdest, "wb"); + if (!dst) + { + fclose (src); + return 0; + } + + fseek (src, 0, SEEK_END); + l = ftell (src); + rewind (src); + buf = g_malloc (l); + + if (buf != NULL) + if (fread (buf, l, 1, src) == 1) + if (fwrite (buf, l, 1, dst) == 1) + ret = 1; + + g_free (buf); + fclose (src); + fclose (dst); + + return ret; +} + +int GetFullPathName(const char *lpFileName, int nBufferLength, char *lpBuffer, char **lpFilePart) +{ + if (lpFileName[0] == '/') + { + strcpy (lpBuffer, lpFileName); + *lpFilePart = strrchr (lpBuffer, '/'); + return strlen (lpBuffer); + } + + if (getcwd (lpBuffer, nBufferLength) == NULL) + return 0; + + strcat (lpBuffer, "/"); + *lpFilePart = lpBuffer + strlen (lpBuffer); + strcat (lpBuffer, lpFileName); + + char *scr = lpBuffer, *dst = lpBuffer; + for (int i = 0; (i < nBufferLength) && (*scr != 0); i++) + { + if (*scr == '/' && *(scr+1) == '.' && *(scr+2) == '.') + { + scr += 4; + while (dst != lpBuffer && *dst != '/') + { + dst--; + i--; + } + } + + *dst = *scr; + + scr++; dst++; + } + *dst = 0; + + return strlen (lpBuffer); +} +/* +static void g_string_sprintfa_int (GString *string, const gchar *fmt, va_list args) +{ + gchar *buffer; + + buffer = g_strdup_vprintf (fmt, args); + g_string_append (string, buffer); + g_free (buffer); +} + +const CString& CString::operator=(const char* lpsz) +{ + g_string_assign (m_str, lpsz); + return *this; +} + +const CString& CString::operator+=(const char* lpsz) +{ + g_string_append (m_str, lpsz); + return *this; +} + +CString::operator char*() const +{ + return m_str->str; +} + +void CString::Format(const char* fmt, ...) +{ + va_list args; + + g_string_truncate (m_str, 0); + + va_start (args, fmt); + g_string_sprintfa_int (m_str, fmt, args); + va_end (args); +} + +CString CString::Right(int nCount) const +{ + if (nCount < 0) + nCount = 0; + else if (nCount > m_str->len) + nCount = m_str->len; + + CString dest (&m_str->str[m_str->len-nCount]); + return dest; +} + +CString CString::Left(int nCount) const +{ + if (nCount < 0) + nCount = 0; + else if (nCount > m_str->len) + nCount = m_str->len; + + CString dest; + dest.m_str = g_string_sized_new (nCount); + memcpy (dest.m_str->str, m_str->str, nCount); + dest.m_str->str[nCount] = 0; + return dest; +} + +void CString::SetAt(int nIndex, char ch) +{ + if (nIndex >= 0 && nIndex < m_str->len) + m_str->str[nIndex] = ch; +} + +char CString::GetAt(int nIndex) const +{ + if (nIndex >= 0 && nIndex < m_str->len) + return m_str->str[nIndex]; + return 0; +} + +char CString::operator[](int nIndex) const +{ + if (nIndex >= 0 && nIndex < m_str->len) + return m_str->str[nIndex]; + return 0; +} +*/ + +#endif diff --git a/radiant/parse.cpp b/radiant/parse.cpp index be6d1586..3760bf00 100644 --- a/radiant/parse.cpp +++ b/radiant/parse.cpp @@ -1,220 +1,220 @@ -/* -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 -*/ - -#include "stdafx.h" - -char token[MAXTOKEN]; -qboolean unget; -char* script_p; -int scriptline; - -// Hydra: added support for GetTokenExtra() -char *currentdelimiters; -qboolean script_keepdelimiter; - -void StartTokenParsing (char *data) -{ - scriptline = 1; - script_p = data; - unget = false; - - // Hydra: added support for GetTokenExtra() - currentdelimiters = NULL; - script_keepdelimiter = true; -} - - -qboolean GetToken (qboolean crossline) -{ - char *token_p; - - if (unget) // is a token already waiting? - { - unget = false; - return true; - } - - // - // skip space - // -skipspace: - while (*script_p <= 32) - { - if (!*script_p) - { - if (!crossline) - Sys_Printf("Warning: Line %i is incomplete [01]\n",scriptline); - return false; - } - - if (*script_p++ == '\n') - { - if (!crossline) - Sys_Printf("Warning: Line %i is incomplete [02]\n",scriptline); - scriptline++; - } - } - - if (script_p[0] == '/' && script_p[1] == '/') // comment field - { - if (!crossline) - Sys_Printf("Warning: Line %i is incomplete [03]\n",scriptline); - while (*script_p++ != '\n') - if (!*script_p) - { - if (!crossline) - Sys_Printf("Warning: Line %i is incomplete [04]\n",scriptline); - return false; - } - scriptline++; // Hydra: fixed bad line numbers problem - goto skipspace; - } - - // - // copy token - // - token_p = token; - - if (*script_p == '"') - { - script_p++; - while ( *script_p != '"' ) - { - if (!*script_p) - Error ("EOF inside quoted token"); - *token_p++ = *script_p++; - if (token_p == &token[MAXTOKEN]) - Error ("Token too large on line %i",scriptline); - } - script_p++; - } - else - while ( *script_p > 32 ) - { - // Hydra: added support for GetTokenExtra(), care was taken to maintain speed - if((currentdelimiters) && (!script_keepdelimiter) && (strchr(currentdelimiters,*(script_p)))) - break; - - *token_p++ = *script_p++; - if (token_p == &token[MAXTOKEN]) - Error ("Token too large on line %i",scriptline); - - // Hydra: added support for GetTokenExtra() - if((currentdelimiters) && (strchr(currentdelimiters,*(script_p-1)))) - break; - - } - - *token_p = 0; - - return true; -} - -void UngetToken (void) -{ - unget = true; -} - -/* -============== -GetTokenExtra - -This function expands the use of GetToken() so it can be used to parse -more complex file formats. - -Hydra - Notes: -You can use this function to split a string like this - -string1:("string2") - -into two strings, like this: -string1 -string2 - -whilst still checking for the brackets and colons, like this: - -GetTokenExtra(false,":",false);// contains "string1" -GetTokenExtra(false,":",true); // contains ":" -GetTokenExtra(false,"(",true); // contains "(" -GetToken(false); // contains "string2" -GetTokenExtra(false,")",true); // contains ")" - -here's what you get, given the same string, with this code: - -GetToken(false); // contains "string1:("string2")" - -Parsing will end if any character in the script matches any one of the -characters in the "delimiters" string. - -it's also possible to do things like this: - -source strings: -1,2 -1:2 -1-2 -1*2 - -code: -GetTokenExtra(false,",:-*",false); // token contains "1" -GetTokenExtra(false,",:-*",false); // token contains the delimiter that was used -GetToken(false); // contains "2" -============== -*/ -qboolean GetTokenExtra (qboolean crossline,char *delimiters, qboolean keepdelimiter) -{ - qboolean result; - char *olddelimiters = currentdelimiters; // store it - - currentdelimiters = delimiters; // change the delimiters - script_keepdelimiter = keepdelimiter; // change the global flag - - result = GetToken(crossline); - currentdelimiters = olddelimiters; // restore it - return(result); -} - -/* -============== -TokenAvailable - -Returns true if there is another token on the line -============== -*/ -qboolean TokenAvailable (void) -{ - char *search_p; - - search_p = script_p; - - while ( *search_p <= 32) - { - if (*search_p == '\n') - return false; - if (*search_p == 0) - return false; - search_p++; - } - - if (*search_p == ';') - return false; - - return true; -} +/* +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 +*/ + +#include "stdafx.h" + +char token[MAXTOKEN]; +qboolean unget; +char* script_p; +int scriptline; + +// Hydra: added support for GetTokenExtra() +char *currentdelimiters; +qboolean script_keepdelimiter; + +void StartTokenParsing (char *data) +{ + scriptline = 1; + script_p = data; + unget = false; + + // Hydra: added support for GetTokenExtra() + currentdelimiters = NULL; + script_keepdelimiter = true; +} + + +qboolean GetToken (qboolean crossline) +{ + char *token_p; + + if (unget) // is a token already waiting? + { + unget = false; + return true; + } + + // + // skip space + // +skipspace: + while (*script_p <= 32) + { + if (!*script_p) + { + if (!crossline) + Sys_Printf("Warning: Line %i is incomplete [01]\n",scriptline); + return false; + } + + if (*script_p++ == '\n') + { + if (!crossline) + Sys_Printf("Warning: Line %i is incomplete [02]\n",scriptline); + scriptline++; + } + } + + if (script_p[0] == '/' && script_p[1] == '/') // comment field + { + if (!crossline) + Sys_Printf("Warning: Line %i is incomplete [03]\n",scriptline); + while (*script_p++ != '\n') + if (!*script_p) + { + if (!crossline) + Sys_Printf("Warning: Line %i is incomplete [04]\n",scriptline); + return false; + } + scriptline++; // Hydra: fixed bad line numbers problem + goto skipspace; + } + + // + // copy token + // + token_p = token; + + if (*script_p == '"') + { + script_p++; + while ( *script_p != '"' ) + { + if (!*script_p) + Error ("EOF inside quoted token"); + *token_p++ = *script_p++; + if (token_p == &token[MAXTOKEN]) + Error ("Token too large on line %i",scriptline); + } + script_p++; + } + else + while ( *script_p > 32 ) + { + // Hydra: added support for GetTokenExtra(), care was taken to maintain speed + if((currentdelimiters) && (!script_keepdelimiter) && (strchr(currentdelimiters,*(script_p)))) + break; + + *token_p++ = *script_p++; + if (token_p == &token[MAXTOKEN]) + Error ("Token too large on line %i",scriptline); + + // Hydra: added support for GetTokenExtra() + if((currentdelimiters) && (strchr(currentdelimiters,*(script_p-1)))) + break; + + } + + *token_p = 0; + + return true; +} + +void UngetToken (void) +{ + unget = true; +} + +/* +============== +GetTokenExtra + +This function expands the use of GetToken() so it can be used to parse +more complex file formats. + +Hydra - Notes: +You can use this function to split a string like this + +string1:("string2") + +into two strings, like this: +string1 +string2 + +whilst still checking for the brackets and colons, like this: + +GetTokenExtra(false,":",false);// contains "string1" +GetTokenExtra(false,":",true); // contains ":" +GetTokenExtra(false,"(",true); // contains "(" +GetToken(false); // contains "string2" +GetTokenExtra(false,")",true); // contains ")" + +here's what you get, given the same string, with this code: + +GetToken(false); // contains "string1:("string2")" + +Parsing will end if any character in the script matches any one of the +characters in the "delimiters" string. + +it's also possible to do things like this: + +source strings: +1,2 +1:2 +1-2 +1*2 + +code: +GetTokenExtra(false,",:-*",false); // token contains "1" +GetTokenExtra(false,",:-*",false); // token contains the delimiter that was used +GetToken(false); // contains "2" +============== +*/ +qboolean GetTokenExtra (qboolean crossline,char *delimiters, qboolean keepdelimiter) +{ + qboolean result; + char *olddelimiters = currentdelimiters; // store it + + currentdelimiters = delimiters; // change the delimiters + script_keepdelimiter = keepdelimiter; // change the global flag + + result = GetToken(crossline); + currentdelimiters = olddelimiters; // restore it + return(result); +} + +/* +============== +TokenAvailable + +Returns true if there is another token on the line +============== +*/ +qboolean TokenAvailable (void) +{ + char *search_p; + + search_p = script_p; + + while ( *search_p <= 32) + { + if (*search_p == '\n') + return false; + if (*search_p == 0) + return false; + search_p++; + } + + if (*search_p == ';') + return false; + + return true; +} diff --git a/radiant/patchdialog.cpp b/radiant/patchdialog.cpp index 8a6ff7cd..e3d6c794 100644 --- a/radiant/patchdialog.cpp +++ b/radiant/patchdialog.cpp @@ -1,745 +1,745 @@ -/* -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 -*/ - -// -// Patch Dialog -// -// Leonardo Zide (leo@lokigames.com) -// - -#include -#include "stdafx.h" -#include "patchdialog.h" - -PatchDialog g_PatchDialog; -// is the patch inspector currently displayed/active? -bool l_bIsActive = false; -// the increment we are using for the patch inspector (this is saved in the prefs) -texdef_t *l_pPIIncrement = &g_qeglobals.d_savedinfo.m_PIIncrement; - -// ============================================================================= -// static functions - -static void OnDone (GtkWidget *widget, gpointer data) -{ - g_PatchDialog.m_Patch = NULL; - g_PatchDialog.HideDlg (); -} - -// memorize the current state (that is don't try to undo our do before changing something else) -static void OnApply (GtkWidget *widget, gpointer data) -{ - g_PatchDialog.UpdateData(TRUE); - if (g_PatchDialog.m_Patch != NULL) - { - int r = g_PatchDialog.m_nRow; - int c = g_PatchDialog.m_nCol; - if (r >= 0 && r < g_PatchDialog.m_Patch->height && c >= 0 && c < g_PatchDialog.m_Patch->width) - { - if (g_PatchDialog.m_Patch->pShader) - g_PatchDialog.m_Patch->pShader->DecRef(); - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=467 - if (g_PatchDialog.m_strName.Find(' ') >= 0) - { - Sys_FPrintf(SYS_WRN, "WARNING: spaces in shader names are not allowed, dropping '%s'\n", g_PatchDialog.m_strName.GetBuffer()); - g_PatchDialog.m_strName = SHADER_NOT_FOUND; - } - g_PatchDialog.m_Patch->pShader = QERApp_Shader_ForName(g_PatchDialog.m_strName); - g_PatchDialog.m_Patch->d_texture = g_PatchDialog.m_Patch->pShader->getTexture(); - g_PatchDialog.m_Patch->ctrl[c][r].xyz[0] = g_PatchDialog.m_fX; - g_PatchDialog.m_Patch->ctrl[c][r].xyz[1] = g_PatchDialog.m_fY; - g_PatchDialog.m_Patch->ctrl[c][r].xyz[2] = g_PatchDialog.m_fZ; - g_PatchDialog.m_Patch->ctrl[c][r].st[0] = g_PatchDialog.m_fS; - g_PatchDialog.m_Patch->ctrl[c][r].st[1] = g_PatchDialog.m_fT; - g_PatchDialog.m_Patch->bDirty = true; - Sys_UpdateWindows(W_ALL); - } - } -} - -static void OnSelchangeComboColRow (GtkWidget *widget, gpointer data) -{ - if (!g_PatchDialog.m_bListenChanged) - return; -#ifdef DBG_PI - Sys_Printf("OnSelchangeComboColRow\n"); -#endif - // retrieve the current m_nRow and m_nCol, other params are not relevant - // (NOTE: UpdateData has a mechanism to avoid inifinite looping) - g_PatchDialog.UpdateData(TRUE); - // read the changed values ourselves - g_PatchDialog.UpdateRowColInfo(); - // now reflect our changes - g_PatchDialog.UpdateData(FALSE); -} - -static void OnBtnPatchdetails (GtkWidget *widget, gpointer data) -{ - Patch_NaturalizeSelected(true); - Sys_UpdateWindows(W_ALL); -} - -static void OnBtnPatchfit (GtkWidget *widget, gpointer data) -{ - Patch_ResetTexturing(1.0, 1.0); - Sys_UpdateWindows(W_ALL); -} - -static void OnBtnPatchnatural (GtkWidget *widget, gpointer data) -{ - Patch_NaturalizeSelected(); - Sys_UpdateWindows(W_ALL); -} - -static void OnBtnPatchreset (GtkWidget *widget, gpointer data) -{ - float fx, fy; - if (DoTextureLayout (&fx, &fy) == IDOK) - { - Patch_ResetTexturing(fx, fy); - } - Sys_UpdateWindows(W_ALL); -} - -static void OnSpinChanged (GtkAdjustment *adj, gpointer data) -{ - texdef_t td; - - td.rotate = 0; - td.scale[0] = td.scale[1] = 0; - td.shift[0] = td.shift[1] = 0; - td.contents = 0; - td.flags = 0; - td.value = 0; - - if (adj->value == 0) - return; - - if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "hshift_adj")) - { - l_pPIIncrement->shift[0] = atof (gtk_entry_get_text (GTK_ENTRY (data))); - - if (adj->value > 0) - td.shift[0] = l_pPIIncrement->shift[0]; - else - td.shift[0] = -l_pPIIncrement->shift[0]; - } - else if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "vshift_adj")) - { - l_pPIIncrement->shift[1] = atof (gtk_entry_get_text (GTK_ENTRY (data))); - - if (adj->value > 0) - td.shift[1] = l_pPIIncrement->shift[1]; - else - td.shift[1] = -l_pPIIncrement->shift[1]; - } - else if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "hscale_adj")) - { - l_pPIIncrement->scale[0] = atof (gtk_entry_get_text (GTK_ENTRY (data))); - if (l_pPIIncrement->scale[0] == 0.0f) - return; - // make sure scale factor is always >1 for increases and <1 for decreases - if (adj->value > 0) - { - if (l_pPIIncrement->scale[0] < 1) - td.scale[0] = l_pPIIncrement->scale[0]; - else - td.scale[0] = 1.0f / l_pPIIncrement->scale[0]; - } - else - { - if (l_pPIIncrement->scale[0] < 1) - td.scale[0] = 1.0f / l_pPIIncrement->scale[0]; - else - td.scale[0] = l_pPIIncrement->scale[0]; - } - } - else if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "vscale_adj")) - { - l_pPIIncrement->scale[1] = atof (gtk_entry_get_text (GTK_ENTRY (data))); - if (l_pPIIncrement->scale[1] == 0.0f) - return; - // make sure scale factor is always >1 for increases and <1 for decreases - if (adj->value > 0) - { - if (l_pPIIncrement->scale[1] < 1) - td.scale[1] = l_pPIIncrement->scale[1]; - else - td.scale[1] = 1.0f / l_pPIIncrement->scale[1]; - } - else - { - if (l_pPIIncrement->scale[1] < 1) - td.scale[1] = 1.0f / l_pPIIncrement->scale[1]; - else - td.scale[1] = l_pPIIncrement->scale[1]; - } - } - else if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "rotate_adj")) - { - l_pPIIncrement->rotate = atof (gtk_entry_get_text (GTK_ENTRY (data))); - - if (adj->value > 0) - td.rotate = l_pPIIncrement->rotate; - else - td.rotate = -l_pPIIncrement->rotate; - } - - adj->value = 0; - -#ifdef DBG_PI - Sys_Printf("Patch_SetTextureInfo: %g %g %g %g %g\n", td.shift[0], td.shift[1],td.scale[0],td.scale[1],td.rotate ); -#endif - // will scale shift rotate the patch accordingly - Patch_SetTextureInfo (&td); - // update the point-by-point view - OnSelchangeComboColRow(NULL,NULL); - Sys_UpdateWindows (W_CAMERA); -} - -static gint OnDialogKey (GtkWidget* widget, GdkEventKey* event, gpointer data) -{ -#ifdef DBG_PI - Sys_Printf("OnDialogKey\n"); -#endif - if (event->keyval == GDK_Return) - { - OnApply (NULL, NULL); - return TRUE; - } - else if (event->keyval == GDK_Escape) - { - OnDone (NULL, NULL); - return TRUE; - } - return FALSE; -} - -// ============================================================================= -// Global Functions - -void DoPatchInspector() -{ - // do we need to create the dialog? - if (g_PatchDialog.GetWidget() == NULL) - { - g_PatchDialog.Create(); - g_PatchDialog.UpdateData (FALSE); - } - g_PatchDialog.GetPatchInfo(); - if (!l_bIsActive) - g_PatchDialog.ShowDlg (); -} - -void UpdatePatchInspector() -{ - if (l_bIsActive) - g_PatchDialog.GetPatchInfo(); -} - -void TogglePatchInspector() -{ - if (l_bIsActive) - OnDone(NULL,NULL); - else - DoPatchInspector(); -} - -// ============================================================================= -// PatchDialog class - -PatchDialog::PatchDialog () -{ - m_strName = ""; - m_fS = 0.0f; - m_fT = 0.0f; - m_fX = 0.0f; - m_fY = 0.0f; - m_fZ = 0.0f; - m_nCol = 0; - m_nRow = 0; - m_Patch = NULL; - m_bListenChanged = true; -} - -void PatchDialog::InitDefaultIncrement(texdef_t *tex) -{ - tex->SetName(SHADER_NOT_FOUND); - tex->scale[0] = 0.5f; - tex->scale[1] = 0.5f; - tex->rotate = 45; - tex->shift[0] = 8.0f; - tex->shift[1] = 8.0f; -} - -// we plug into HideDlg and ShowDlg to maintain the l_bIsActive flag -void PatchDialog::HideDlg() -{ - l_bIsActive = false; - Dialog::HideDlg(); -} - -void PatchDialog::ShowDlg() -{ - l_bIsActive = true; - Dialog::ShowDlg(); -} - -void PatchDialog::BuildDialog () -{ - GtkWidget *dlg, *vbox, *vbox2, *hbox, *hbox2, *frame, *table, *label; - GtkWidget *button, *entry, *spin, *combo; - GtkObject *adj; - char buf[32]; - - dlg = m_pWidget; - - load_window_pos (dlg, g_PrefsDlg.mWindowInfo.posPatchWnd); - - gtk_window_set_title (GTK_WINDOW (dlg), "Patch Properties"); - gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", GTK_SIGNAL_FUNC (OnDone), NULL); - // catch 'Esc' and 'Enter' - gtk_signal_connect (GTK_OBJECT (dlg), "key_press_event", GTK_SIGNAL_FUNC (OnDialogKey), NULL); - gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pParentWnd->m_pWidget)); - - - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_container_add (GTK_CONTAINER (dlg), vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0); - - frame = gtk_frame_new ("Details"); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0); - - vbox2 = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox2); - gtk_container_add (GTK_CONTAINER (frame), vbox2); - gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); - - table = gtk_table_new (2, 2, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("Row:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - label = gtk_label_new ("Column:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - combo = gtk_combo_new (); - gtk_widget_show (combo); - gtk_table_attach (GTK_TABLE (table), combo, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (combo, 60, -1); - gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE); - gtk_signal_connect (GTK_OBJECT (GTK_COMBO (combo)->entry), "changed", - GTK_SIGNAL_FUNC (OnSelchangeComboColRow), this); - AddDialogData (combo, &m_nRow, DLG_COMBO_INT); - m_pRowCombo = combo; - - combo = gtk_combo_new (); - gtk_widget_show (combo); - gtk_table_attach (GTK_TABLE (table), combo, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (combo, 60, -1); - gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE); - gtk_signal_connect (GTK_OBJECT (GTK_COMBO (combo)->entry), "changed", - GTK_SIGNAL_FUNC (OnSelchangeComboColRow), this); - AddDialogData (combo, &m_nCol, DLG_COMBO_INT); - m_pColCombo = combo; - - table = gtk_table_new (5, 2, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("X:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - label = gtk_label_new ("Y:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - label = gtk_label_new ("Z:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - label = gtk_label_new ("S:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - label = gtk_label_new ("T:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 4, 5, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - AddDialogData (entry, &m_fX, DLG_ENTRY_FLOAT); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - AddDialogData (entry, &m_fY, DLG_ENTRY_FLOAT); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - AddDialogData (entry, &m_fZ, DLG_ENTRY_FLOAT); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 3, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - AddDialogData (entry, &m_fS, DLG_ENTRY_FLOAT); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 4, 5, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - AddDialogData (entry, &m_fT, DLG_ENTRY_FLOAT); - - frame = gtk_frame_new ("Texturing"); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0); - - vbox2 = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox2); - gtk_container_add (GTK_CONTAINER (frame), vbox2); - gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); - - label = gtk_label_new ("Name:"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (vbox2), label, TRUE, TRUE, 0); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - entry = gtk_entry_new (); -// gtk_entry_set_editable (GTK_ENTRY (entry), false); - gtk_widget_show (entry); - gtk_box_pack_start (GTK_BOX (vbox2), entry, TRUE, TRUE, 0); - AddDialogData (entry, &m_strName, DLG_ENTRY_TEXT); - - table = gtk_table_new (5, 3, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("Horizontal Shift Step"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - label = gtk_label_new ("Vertical Shift Step"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - label = gtk_label_new ("Horizontal Stretch Step"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 2, 3, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - label = gtk_label_new ("Vertical Stretch Step"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 2, 3, 3, 4, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - label = gtk_label_new ("Rotate Step"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 2, 3, 4, 5, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - g_object_set_data (G_OBJECT (m_pWidget), "hshift_entry", entry); - // we fill in this data, if no patch is selected the widgets are unmodified when the inspector is raised - // so we need to have at least one initialisation somewhere - sprintf (buf, "%g", l_pPIIncrement->shift[0]); - gtk_entry_set_text (GTK_ENTRY (entry), buf); - - adj = gtk_adjustment_new (0, -8192, 8192, 1, 1, 1); - gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry); - g_object_set_data (G_OBJECT (m_pWidget), "hshift_adj", adj); - - spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); - gtk_widget_show (spin); - gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (spin, 10, -2); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - sprintf (buf, "%g", l_pPIIncrement->shift[1]); - gtk_entry_set_text (GTK_ENTRY (entry), buf); - - adj = gtk_adjustment_new (0, -8192, 8192, 1, 1, 1); - gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry); - g_object_set_data (G_OBJECT (m_pWidget), "vshift_adj", adj); - - spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); - gtk_widget_show (spin); - gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 1, 2, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (spin, 10, -2); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - sprintf (buf, "%g", l_pPIIncrement->scale[0]); - gtk_entry_set_text (GTK_ENTRY (entry), buf); - - adj = gtk_adjustment_new (0, -1000, 1000, 1, 1, 1); - gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry); - g_object_set_data (G_OBJECT (m_pWidget), "hscale_adj", adj); - - spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); - gtk_widget_show (spin); - gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 2, 3, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (spin, 10, -2); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 3, 4, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - sprintf (buf, "%g", l_pPIIncrement->scale[1]); - gtk_entry_set_text (GTK_ENTRY (entry), buf); - - adj = gtk_adjustment_new (0, -1000, 1000, 1, 1, 1); - gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry); - g_object_set_data (G_OBJECT (m_pWidget), "vscale_adj", adj); - - spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); - gtk_widget_show (spin); - gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 3, 4, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (spin, 10, -2); - - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 4, 5, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - sprintf (buf, "%g", l_pPIIncrement->rotate); - gtk_entry_set_text (GTK_ENTRY (entry), buf); - - adj = gtk_adjustment_new (0, -1000, 1000, 1, 1, 1); // NOTE: Arnout - this really should be 360 but can't change it anymore as it could break existing maps - gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry); - g_object_set_data (G_OBJECT (m_pWidget), "rotate_adj", adj); - - spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); - gtk_widget_show (spin); - gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 4, 5, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (spin, 10, -2); - - hbox2 = gtk_hbox_new (TRUE, 5); - gtk_widget_show (hbox2); - gtk_box_pack_start (GTK_BOX (vbox2), hbox2, TRUE, FALSE, 0); - - button = gtk_button_new_with_label ("CAP"); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (hbox2), button, TRUE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnPatchdetails), NULL); - gtk_widget_set_usize (button, 60, -1); - - button = gtk_button_new_with_label ("Set..."); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (hbox2), button, TRUE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnPatchreset), NULL); - gtk_widget_set_usize (button, 60, -1); - - button = gtk_button_new_with_label ("Natural"); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (hbox2), button, TRUE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnPatchnatural), NULL); - gtk_widget_set_usize (button, 60, -1); - - button = gtk_button_new_with_label ("Fit"); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (hbox2), button, TRUE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnPatchfit), NULL); - gtk_widget_set_usize (button, 60, -1); - - hbox = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, FALSE, 0); - - button = gtk_button_new_with_label ("Done"); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnDone), NULL); - gtk_widget_set_usize (button, 60, -1); - - button = gtk_button_new_with_label ("Apply"); - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnApply), NULL); - gtk_widget_set_usize (button, 60, -1); -} - -// sync the dialog our internal data structures -void PatchDialog::UpdateData (bool retrieve) -{ - if (m_pWidget == NULL) - return; - - m_bListenChanged = false; - Dialog::UpdateData (retrieve); - m_bListenChanged = true; -} - -// read the map and feed in the stuff to the dialog box -void PatchDialog::GetPatchInfo() -{ - m_Patch = SinglePatchSelected(); - if (m_Patch != NULL) - { - m_strName = m_Patch->pShader->getName(); - - GList *combo_list = NULL; - int i; - - // fill in the numbers for Row / Col selection - m_bListenChanged = false; - - for (i = 0; i < m_Patch->height; i++) - combo_list = g_list_append (combo_list, g_strdup_printf ("%i", i)); // NOTE: leaving the g_strdup cause we free with g_free later on - gtk_combo_set_popdown_strings (GTK_COMBO (m_pRowCombo), combo_list); - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (m_pRowCombo)->entry), "0"); - - while (combo_list) - { - g_free (combo_list->data); - combo_list = g_list_remove (combo_list, combo_list->data); - } - - for (i = 0; i < m_Patch->width; i++) - combo_list = g_list_append (combo_list, g_strdup_printf ("%i", i)); - gtk_combo_set_popdown_strings (GTK_COMBO (m_pColCombo), combo_list); - gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (m_pColCombo)->entry), "0"); - - while (combo_list) - { - g_free (combo_list->data); - combo_list = g_list_remove (combo_list, combo_list->data); - } - - m_bListenChanged = true; - - } - else - Sys_Printf("WARNING: no patch\n"); - // fill in our internal structs - m_nRow = 0; m_nCol = 0; - UpdateRowColInfo(); - // now update the dialog box - UpdateData(false); -} - -// read the current patch on map and initialize m_fX m_fY accordingly -// NOTE: don't call UpdateData in there, it's not meant for -void PatchDialog::UpdateRowColInfo() -{ - m_fX = m_fY = m_fZ = m_fS = m_fT = 0.0; - - if (m_Patch != NULL) - { - // we rely on whatever active row/column has been set before we get called - int r = m_nRow; - int c = m_nCol; - if (r >= 0 && r < m_Patch->height && c >= 0 && c < m_Patch->width) - { - m_fX = m_Patch->ctrl[c][r].xyz[0]; - m_fY = m_Patch->ctrl[c][r].xyz[1]; - m_fZ = m_Patch->ctrl[c][r].xyz[2]; - m_fS = m_Patch->ctrl[c][r].st[0]; - m_fT = m_Patch->ctrl[c][r].st[1]; - } - } -} - +/* +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 +*/ + +// +// Patch Dialog +// +// Leonardo Zide (leo@lokigames.com) +// + +#include +#include "stdafx.h" +#include "patchdialog.h" + +PatchDialog g_PatchDialog; +// is the patch inspector currently displayed/active? +bool l_bIsActive = false; +// the increment we are using for the patch inspector (this is saved in the prefs) +texdef_t *l_pPIIncrement = &g_qeglobals.d_savedinfo.m_PIIncrement; + +// ============================================================================= +// static functions + +static void OnDone (GtkWidget *widget, gpointer data) +{ + g_PatchDialog.m_Patch = NULL; + g_PatchDialog.HideDlg (); +} + +// memorize the current state (that is don't try to undo our do before changing something else) +static void OnApply (GtkWidget *widget, gpointer data) +{ + g_PatchDialog.UpdateData(TRUE); + if (g_PatchDialog.m_Patch != NULL) + { + int r = g_PatchDialog.m_nRow; + int c = g_PatchDialog.m_nCol; + if (r >= 0 && r < g_PatchDialog.m_Patch->height && c >= 0 && c < g_PatchDialog.m_Patch->width) + { + if (g_PatchDialog.m_Patch->pShader) + g_PatchDialog.m_Patch->pShader->DecRef(); + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=467 + if (g_PatchDialog.m_strName.Find(' ') >= 0) + { + Sys_FPrintf(SYS_WRN, "WARNING: spaces in shader names are not allowed, dropping '%s'\n", g_PatchDialog.m_strName.GetBuffer()); + g_PatchDialog.m_strName = SHADER_NOT_FOUND; + } + g_PatchDialog.m_Patch->pShader = QERApp_Shader_ForName(g_PatchDialog.m_strName); + g_PatchDialog.m_Patch->d_texture = g_PatchDialog.m_Patch->pShader->getTexture(); + g_PatchDialog.m_Patch->ctrl[c][r].xyz[0] = g_PatchDialog.m_fX; + g_PatchDialog.m_Patch->ctrl[c][r].xyz[1] = g_PatchDialog.m_fY; + g_PatchDialog.m_Patch->ctrl[c][r].xyz[2] = g_PatchDialog.m_fZ; + g_PatchDialog.m_Patch->ctrl[c][r].st[0] = g_PatchDialog.m_fS; + g_PatchDialog.m_Patch->ctrl[c][r].st[1] = g_PatchDialog.m_fT; + g_PatchDialog.m_Patch->bDirty = true; + Sys_UpdateWindows(W_ALL); + } + } +} + +static void OnSelchangeComboColRow (GtkWidget *widget, gpointer data) +{ + if (!g_PatchDialog.m_bListenChanged) + return; +#ifdef DBG_PI + Sys_Printf("OnSelchangeComboColRow\n"); +#endif + // retrieve the current m_nRow and m_nCol, other params are not relevant + // (NOTE: UpdateData has a mechanism to avoid inifinite looping) + g_PatchDialog.UpdateData(TRUE); + // read the changed values ourselves + g_PatchDialog.UpdateRowColInfo(); + // now reflect our changes + g_PatchDialog.UpdateData(FALSE); +} + +static void OnBtnPatchdetails (GtkWidget *widget, gpointer data) +{ + Patch_NaturalizeSelected(true); + Sys_UpdateWindows(W_ALL); +} + +static void OnBtnPatchfit (GtkWidget *widget, gpointer data) +{ + Patch_ResetTexturing(1.0, 1.0); + Sys_UpdateWindows(W_ALL); +} + +static void OnBtnPatchnatural (GtkWidget *widget, gpointer data) +{ + Patch_NaturalizeSelected(); + Sys_UpdateWindows(W_ALL); +} + +static void OnBtnPatchreset (GtkWidget *widget, gpointer data) +{ + float fx, fy; + if (DoTextureLayout (&fx, &fy) == IDOK) + { + Patch_ResetTexturing(fx, fy); + } + Sys_UpdateWindows(W_ALL); +} + +static void OnSpinChanged (GtkAdjustment *adj, gpointer data) +{ + texdef_t td; + + td.rotate = 0; + td.scale[0] = td.scale[1] = 0; + td.shift[0] = td.shift[1] = 0; + td.contents = 0; + td.flags = 0; + td.value = 0; + + if (adj->value == 0) + return; + + if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "hshift_adj")) + { + l_pPIIncrement->shift[0] = atof (gtk_entry_get_text (GTK_ENTRY (data))); + + if (adj->value > 0) + td.shift[0] = l_pPIIncrement->shift[0]; + else + td.shift[0] = -l_pPIIncrement->shift[0]; + } + else if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "vshift_adj")) + { + l_pPIIncrement->shift[1] = atof (gtk_entry_get_text (GTK_ENTRY (data))); + + if (adj->value > 0) + td.shift[1] = l_pPIIncrement->shift[1]; + else + td.shift[1] = -l_pPIIncrement->shift[1]; + } + else if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "hscale_adj")) + { + l_pPIIncrement->scale[0] = atof (gtk_entry_get_text (GTK_ENTRY (data))); + if (l_pPIIncrement->scale[0] == 0.0f) + return; + // make sure scale factor is always >1 for increases and <1 for decreases + if (adj->value > 0) + { + if (l_pPIIncrement->scale[0] < 1) + td.scale[0] = l_pPIIncrement->scale[0]; + else + td.scale[0] = 1.0f / l_pPIIncrement->scale[0]; + } + else + { + if (l_pPIIncrement->scale[0] < 1) + td.scale[0] = 1.0f / l_pPIIncrement->scale[0]; + else + td.scale[0] = l_pPIIncrement->scale[0]; + } + } + else if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "vscale_adj")) + { + l_pPIIncrement->scale[1] = atof (gtk_entry_get_text (GTK_ENTRY (data))); + if (l_pPIIncrement->scale[1] == 0.0f) + return; + // make sure scale factor is always >1 for increases and <1 for decreases + if (adj->value > 0) + { + if (l_pPIIncrement->scale[1] < 1) + td.scale[1] = l_pPIIncrement->scale[1]; + else + td.scale[1] = 1.0f / l_pPIIncrement->scale[1]; + } + else + { + if (l_pPIIncrement->scale[1] < 1) + td.scale[1] = 1.0f / l_pPIIncrement->scale[1]; + else + td.scale[1] = l_pPIIncrement->scale[1]; + } + } + else if (adj == g_object_get_data (G_OBJECT (g_PatchDialog.GetWidget ()), "rotate_adj")) + { + l_pPIIncrement->rotate = atof (gtk_entry_get_text (GTK_ENTRY (data))); + + if (adj->value > 0) + td.rotate = l_pPIIncrement->rotate; + else + td.rotate = -l_pPIIncrement->rotate; + } + + adj->value = 0; + +#ifdef DBG_PI + Sys_Printf("Patch_SetTextureInfo: %g %g %g %g %g\n", td.shift[0], td.shift[1],td.scale[0],td.scale[1],td.rotate ); +#endif + // will scale shift rotate the patch accordingly + Patch_SetTextureInfo (&td); + // update the point-by-point view + OnSelchangeComboColRow(NULL,NULL); + Sys_UpdateWindows (W_CAMERA); +} + +static gint OnDialogKey (GtkWidget* widget, GdkEventKey* event, gpointer data) +{ +#ifdef DBG_PI + Sys_Printf("OnDialogKey\n"); +#endif + if (event->keyval == GDK_Return) + { + OnApply (NULL, NULL); + return TRUE; + } + else if (event->keyval == GDK_Escape) + { + OnDone (NULL, NULL); + return TRUE; + } + return FALSE; +} + +// ============================================================================= +// Global Functions + +void DoPatchInspector() +{ + // do we need to create the dialog? + if (g_PatchDialog.GetWidget() == NULL) + { + g_PatchDialog.Create(); + g_PatchDialog.UpdateData (FALSE); + } + g_PatchDialog.GetPatchInfo(); + if (!l_bIsActive) + g_PatchDialog.ShowDlg (); +} + +void UpdatePatchInspector() +{ + if (l_bIsActive) + g_PatchDialog.GetPatchInfo(); +} + +void TogglePatchInspector() +{ + if (l_bIsActive) + OnDone(NULL,NULL); + else + DoPatchInspector(); +} + +// ============================================================================= +// PatchDialog class + +PatchDialog::PatchDialog () +{ + m_strName = ""; + m_fS = 0.0f; + m_fT = 0.0f; + m_fX = 0.0f; + m_fY = 0.0f; + m_fZ = 0.0f; + m_nCol = 0; + m_nRow = 0; + m_Patch = NULL; + m_bListenChanged = true; +} + +void PatchDialog::InitDefaultIncrement(texdef_t *tex) +{ + tex->SetName(SHADER_NOT_FOUND); + tex->scale[0] = 0.5f; + tex->scale[1] = 0.5f; + tex->rotate = 45; + tex->shift[0] = 8.0f; + tex->shift[1] = 8.0f; +} + +// we plug into HideDlg and ShowDlg to maintain the l_bIsActive flag +void PatchDialog::HideDlg() +{ + l_bIsActive = false; + Dialog::HideDlg(); +} + +void PatchDialog::ShowDlg() +{ + l_bIsActive = true; + Dialog::ShowDlg(); +} + +void PatchDialog::BuildDialog () +{ + GtkWidget *dlg, *vbox, *vbox2, *hbox, *hbox2, *frame, *table, *label; + GtkWidget *button, *entry, *spin, *combo; + GtkObject *adj; + char buf[32]; + + dlg = m_pWidget; + + load_window_pos (dlg, g_PrefsDlg.mWindowInfo.posPatchWnd); + + gtk_window_set_title (GTK_WINDOW (dlg), "Patch Properties"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", GTK_SIGNAL_FUNC (OnDone), NULL); + // catch 'Esc' and 'Enter' + gtk_signal_connect (GTK_OBJECT (dlg), "key_press_event", GTK_SIGNAL_FUNC (OnDialogKey), NULL); + gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pParentWnd->m_pWidget)); + + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0); + + frame = gtk_frame_new ("Details"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (frame), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Row:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("Column:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + combo = gtk_combo_new (); + gtk_widget_show (combo); + gtk_table_attach (GTK_TABLE (table), combo, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (combo, 60, -1); + gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE); + gtk_signal_connect (GTK_OBJECT (GTK_COMBO (combo)->entry), "changed", + GTK_SIGNAL_FUNC (OnSelchangeComboColRow), this); + AddDialogData (combo, &m_nRow, DLG_COMBO_INT); + m_pRowCombo = combo; + + combo = gtk_combo_new (); + gtk_widget_show (combo); + gtk_table_attach (GTK_TABLE (table), combo, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (combo, 60, -1); + gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE); + gtk_signal_connect (GTK_OBJECT (GTK_COMBO (combo)->entry), "changed", + GTK_SIGNAL_FUNC (OnSelchangeComboColRow), this); + AddDialogData (combo, &m_nCol, DLG_COMBO_INT); + m_pColCombo = combo; + + table = gtk_table_new (5, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("X:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("Y:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("Z:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("S:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("T:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + AddDialogData (entry, &m_fX, DLG_ENTRY_FLOAT); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + AddDialogData (entry, &m_fY, DLG_ENTRY_FLOAT); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + AddDialogData (entry, &m_fZ, DLG_ENTRY_FLOAT); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + AddDialogData (entry, &m_fS, DLG_ENTRY_FLOAT); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + AddDialogData (entry, &m_fT, DLG_ENTRY_FLOAT); + + frame = gtk_frame_new ("Texturing"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (frame), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + label = gtk_label_new ("Name:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox2), label, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + entry = gtk_entry_new (); +// gtk_entry_set_editable (GTK_ENTRY (entry), false); + gtk_widget_show (entry); + gtk_box_pack_start (GTK_BOX (vbox2), entry, TRUE, TRUE, 0); + AddDialogData (entry, &m_strName, DLG_ENTRY_TEXT); + + table = gtk_table_new (5, 3, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Horizontal Shift Step"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Vertical Shift Step"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Horizontal Stretch Step"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Vertical Stretch Step"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + label = gtk_label_new ("Rotate Step"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (m_pWidget), "hshift_entry", entry); + // we fill in this data, if no patch is selected the widgets are unmodified when the inspector is raised + // so we need to have at least one initialisation somewhere + sprintf (buf, "%g", l_pPIIncrement->shift[0]); + gtk_entry_set_text (GTK_ENTRY (entry), buf); + + adj = gtk_adjustment_new (0, -8192, 8192, 1, 1, 1); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry); + g_object_set_data (G_OBJECT (m_pWidget), "hshift_adj", adj); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 10, -2); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + sprintf (buf, "%g", l_pPIIncrement->shift[1]); + gtk_entry_set_text (GTK_ENTRY (entry), buf); + + adj = gtk_adjustment_new (0, -8192, 8192, 1, 1, 1); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry); + g_object_set_data (G_OBJECT (m_pWidget), "vshift_adj", adj); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 10, -2); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + sprintf (buf, "%g", l_pPIIncrement->scale[0]); + gtk_entry_set_text (GTK_ENTRY (entry), buf); + + adj = gtk_adjustment_new (0, -1000, 1000, 1, 1, 1); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry); + g_object_set_data (G_OBJECT (m_pWidget), "hscale_adj", adj); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 2, 3, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 10, -2); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + sprintf (buf, "%g", l_pPIIncrement->scale[1]); + gtk_entry_set_text (GTK_ENTRY (entry), buf); + + adj = gtk_adjustment_new (0, -1000, 1000, 1, 1, 1); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry); + g_object_set_data (G_OBJECT (m_pWidget), "vscale_adj", adj); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 3, 4, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 10, -2); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + sprintf (buf, "%g", l_pPIIncrement->rotate); + gtk_entry_set_text (GTK_ENTRY (entry), buf); + + adj = gtk_adjustment_new (0, -1000, 1000, 1, 1, 1); // NOTE: Arnout - this really should be 360 but can't change it anymore as it could break existing maps + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnSpinChanged), entry); + g_object_set_data (G_OBJECT (m_pWidget), "rotate_adj", adj); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 4, 5, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 10, -2); + + hbox2 = gtk_hbox_new (TRUE, 5); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox2), hbox2, TRUE, FALSE, 0); + + button = gtk_button_new_with_label ("CAP"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox2), button, TRUE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnPatchdetails), NULL); + gtk_widget_set_usize (button, 60, -1); + + button = gtk_button_new_with_label ("Set..."); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox2), button, TRUE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnPatchreset), NULL); + gtk_widget_set_usize (button, 60, -1); + + button = gtk_button_new_with_label ("Natural"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox2), button, TRUE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnPatchnatural), NULL); + gtk_widget_set_usize (button, 60, -1); + + button = gtk_button_new_with_label ("Fit"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox2), button, TRUE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnPatchfit), NULL); + gtk_widget_set_usize (button, 60, -1); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, FALSE, 0); + + button = gtk_button_new_with_label ("Done"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnDone), NULL); + gtk_widget_set_usize (button, 60, -1); + + button = gtk_button_new_with_label ("Apply"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnApply), NULL); + gtk_widget_set_usize (button, 60, -1); +} + +// sync the dialog our internal data structures +void PatchDialog::UpdateData (bool retrieve) +{ + if (m_pWidget == NULL) + return; + + m_bListenChanged = false; + Dialog::UpdateData (retrieve); + m_bListenChanged = true; +} + +// read the map and feed in the stuff to the dialog box +void PatchDialog::GetPatchInfo() +{ + m_Patch = SinglePatchSelected(); + if (m_Patch != NULL) + { + m_strName = m_Patch->pShader->getName(); + + GList *combo_list = NULL; + int i; + + // fill in the numbers for Row / Col selection + m_bListenChanged = false; + + for (i = 0; i < m_Patch->height; i++) + combo_list = g_list_append (combo_list, g_strdup_printf ("%i", i)); // NOTE: leaving the g_strdup cause we free with g_free later on + gtk_combo_set_popdown_strings (GTK_COMBO (m_pRowCombo), combo_list); + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (m_pRowCombo)->entry), "0"); + + while (combo_list) + { + g_free (combo_list->data); + combo_list = g_list_remove (combo_list, combo_list->data); + } + + for (i = 0; i < m_Patch->width; i++) + combo_list = g_list_append (combo_list, g_strdup_printf ("%i", i)); + gtk_combo_set_popdown_strings (GTK_COMBO (m_pColCombo), combo_list); + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (m_pColCombo)->entry), "0"); + + while (combo_list) + { + g_free (combo_list->data); + combo_list = g_list_remove (combo_list, combo_list->data); + } + + m_bListenChanged = true; + + } + else + Sys_Printf("WARNING: no patch\n"); + // fill in our internal structs + m_nRow = 0; m_nCol = 0; + UpdateRowColInfo(); + // now update the dialog box + UpdateData(false); +} + +// read the current patch on map and initialize m_fX m_fY accordingly +// NOTE: don't call UpdateData in there, it's not meant for +void PatchDialog::UpdateRowColInfo() +{ + m_fX = m_fY = m_fZ = m_fS = m_fT = 0.0; + + if (m_Patch != NULL) + { + // we rely on whatever active row/column has been set before we get called + int r = m_nRow; + int c = m_nCol; + if (r >= 0 && r < m_Patch->height && c >= 0 && c < m_Patch->width) + { + m_fX = m_Patch->ctrl[c][r].xyz[0]; + m_fY = m_Patch->ctrl[c][r].xyz[1]; + m_fZ = m_Patch->ctrl[c][r].xyz[2]; + m_fS = m_Patch->ctrl[c][r].st[0]; + m_fT = m_Patch->ctrl[c][r].st[1]; + } + } +} + diff --git a/radiant/pluginentities.cpp b/radiant/pluginentities.cpp index 563fa85a..153a61fb 100644 --- a/radiant/pluginentities.cpp +++ b/radiant/pluginentities.cpp @@ -1,74 +1,74 @@ -/* -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 -*/ - -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// implementation of IPluginEntities specific interface -// - -#ifdef USEPLUGINENTITIES - -#include "stdafx.h" -#if defined (__linux__) || defined (__APPLE__) -#include -#endif -//#include "qe3.h" - -int QERApp_EClassScanDir (char *path, void* hPlug) -{ - char temp[NAME_MAX]; - char filebase[NAME_MAX]; - char filename[NAME_MAX]; - char *s; - eclass_t *e; - DIR *dir; - struct dirent *dirlist; - - QE_ConvertDOSToUnixName( temp, path ); - strcpy (filebase, path); - s = filebase + strlen(filebase)-1; - while (*s != '\\' && *s != '/' && s!=filebase) - s--; - *s = 0; - - dir = opendir (path); - if (dir != NULL) - { - while ((dirlist = readdir (dir)) != NULL) - { - sprintf (filename, "%s/%s", filebase, dirlist->d_name); - Eclass_ScanFile (filename); - - if (eclass_found) - { - e = eclass_e; - e->modelpath = strdup(dirlist->d_name); - e->nShowFlags |= ECLASS_PLUGINENTITY; - e->hPlug = hPlug; - } - } - closedir (dir); - } - return 0; -} - -#endif // USEPLUGINENTITIES +/* +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 +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// implementation of IPluginEntities specific interface +// + +#ifdef USEPLUGINENTITIES + +#include "stdafx.h" +#if defined (__linux__) || defined (__APPLE__) +#include +#endif +//#include "qe3.h" + +int QERApp_EClassScanDir (char *path, void* hPlug) +{ + char temp[NAME_MAX]; + char filebase[NAME_MAX]; + char filename[NAME_MAX]; + char *s; + eclass_t *e; + DIR *dir; + struct dirent *dirlist; + + QE_ConvertDOSToUnixName( temp, path ); + strcpy (filebase, path); + s = filebase + strlen(filebase)-1; + while (*s != '\\' && *s != '/' && s!=filebase) + s--; + *s = 0; + + dir = opendir (path); + if (dir != NULL) + { + while ((dirlist = readdir (dir)) != NULL) + { + sprintf (filename, "%s/%s", filebase, dirlist->d_name); + Eclass_ScanFile (filename); + + if (eclass_found) + { + e = eclass_e; + e->modelpath = strdup(dirlist->d_name); + e->nShowFlags |= ECLASS_PLUGINENTITY; + e->hPlug = hPlug; + } + } + closedir (dir); + } + return 0; +} + +#endif // USEPLUGINENTITIES diff --git a/radiant/pluginmanager.cpp b/radiant/pluginmanager.cpp index 7840b0b5..609e8065 100644 --- a/radiant/pluginmanager.cpp +++ b/radiant/pluginmanager.cpp @@ -1,2522 +1,2522 @@ -/* -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 -*/ - -// PlugInManager.cpp: implementation of the CPlugInManager class. -// -////////////////////////////////////////////////////////////////////// - -#include "stdafx.h" -#if defined (__linux__) || defined (__APPLE__) - #include - #include -#endif -#ifdef __APPLE__ - #ifdef __cplusplus - extern "C" { - #endif - #include - #ifdef __cplusplus - } - #endif -#endif -#ifdef _WIN32 - #include "objbase.h" -#endif -#include "pluginmanager.h" -#include "plugin.h" -#include "missing.h" - -#include "version.h" - -CRadiantImageManager g_ImageManager; -CRadiantPluginManager g_PluginsManager; - -_QERPlugSurfaceTable g_SurfaceTable; -_QERFileSystemTable g_FileSystemTable; -_QERShadersTable g_ShadersTable; -_QERPlugMapTable g_MapTable; -_QERPlugMapTable g_MapTable2; -_QEREntityTable g_EntityTable; -_EClassTable g_EClassDefTable; - -/*! - extending entity class formats - this approach only allows a single additional format, but it is enough for now -*/ -bool g_bHaveEClassExt = false; -_EClassTable g_EClassExtTable; - - -filetype_t g_pattern_all("all files", "*.*"); -filetype_t g_pattern_projqe4v2("qe4 v2 project files", "*.qe4"); -filetype_t g_pattern_projxml("xml project files", "*.proj"); -filetype_t g_pattern_mapq3("quake3 maps", "*.map"); -filetype_t g_pattern_mapxml("xml quake3 maps", "*.xmap"); -filetype_t g_pattern_modelmd3("md3 models", "*.md3"); -filetype_t g_pattern_modelmdc("mdc models", "*.mdc"); -filetype_t g_pattern_modelmd2("md2 models", "*.md2"); -filetype_t g_pattern_modelmdl("mdl models", "*.mdl"); -//filetype_t g_pattern_modelea3("EA3 models", "*.ea3"); -filetype_t g_pattern_soundwav("PCM sound files", "*.wav"); -filetype_t g_pattern_regq3("quake3 region", "*.reg"); - -#include - -class RadiantFileTypeRegistry : public IFileTypeRegistry -{ -public: - virtual ~RadiantFileTypeRegistry() {} - virtual void addType(const char* key, filetype_t type) - { - m_typelists[key].push_back(type); - } - virtual void getTypeList(const char* key, IFileTypeList* typelist) - { - filetype_list_t& list_ref = m_typelists[key]; - for(unsigned int i=0; iaddType(list_ref[i].getType()); - } -private: - struct filetype_copy_t - { - inline filetype_copy_t(const filetype_t other) - : m_name(other.name), m_pattern(other.pattern) - {} - inline filetype_t getType() const - { - return filetype_t(m_name.c_str(), m_pattern.c_str()); - } - private: - string_t m_name; - string_t m_pattern; - }; - typedef vector filetype_list_t; - map m_typelists; -}; - -static RadiantFileTypeRegistry g_patterns; - -IFileTypeRegistry* GetFileTypeRegistry() -{ - return &g_patterns; -} - -void InitFileTypes() -{ - //GetFileTypeRegistry()->addType("project", g_pattern_projqe4v2); - GetFileTypeRegistry()->addType("project", g_pattern_projxml); - - GetFileTypeRegistry()->addType(MAP_MAJOR, g_pattern_mapq3); - GetFileTypeRegistry()->addType(MAP_MAJOR, g_pattern_mapxml); - - GetFileTypeRegistry()->addType("region", g_pattern_regq3); -/* - GetFileTypeRegistry()->addType(MODEL_MAJOR, g_pattern_modelmd3); - GetFileTypeRegistry()->addType(MODEL_MAJOR, g_pattern_modelmd2); - GetFileTypeRegistry()->addType(MODEL_MAJOR, g_pattern_modelmdl); - GetFileTypeRegistry()->addType(MODEL_MAJOR, g_pattern_modelmdc); - //GetFileTypeRegistry()->addType(MODEL_MAJOR, g_pattern_modelea3); - */ - - GetFileTypeRegistry()->addType("sound", g_pattern_soundwav); -} - - -class CRadiantModelModuleManager : public CSynapseAPIManager -{ - typedef list APIDescriptorList; - - APIDescriptorList mAPIs; -public: - CRadiantModelModuleManager() - { - SetMatchAPI(MODEL_MAJOR, "*"); - } - virtual ~CRadiantModelModuleManager() - { - APIDescriptorList::iterator i; - for(i=mAPIs.begin(); i!=mAPIs.end(); i++) - { - delete (_QERPlugModelTable*)(*i)->mpTable; - delete *i; - *i = NULL; - } - mAPIs.clear(); - } - - // CSynapseAPIManager interface ------------------- - APIDescriptor_t* BuildRequireAPI(APIDescriptor_t* pAPI) - { - APIDescriptor_t* pRequireAPI = CSynapseAPIManager::PrepareRequireAPI(pAPI); - pRequireAPI->mpTable = new _QERPlugModelTable; - ((_QERPlugModelTable*)pRequireAPI->mpTable)->m_nSize = sizeof(_QERPlugModelTable); - pRequireAPI->mSize = sizeof(_QERPlugModelTable); - mAPIs.push_front(pRequireAPI); - return pRequireAPI; - } - - // Model Manager specific - const _QERPlugModelTable* GetModelTable(const char* version) - { - APIDescriptorList::iterator i; - for(i=mAPIs.begin(); i!=mAPIs.end(); i++) - if(strcmp(version, (*i)->minor_name) == 0) - return ((_QERPlugModelTable*)(*i)->mpTable); - return NULL; - } -}; - -CRadiantModelModuleManager g_ModelManager; - -/*! One of these exists for each unique model ID in use */ -class CModelWrapper -{ - friend class CModelManager; -public: - CModelWrapper (const char *id, const char* version) : refcount(1) - { - copy(id, version); - construct(); - } - void Refresh() - { - destroy(); - construct(); - } - ~CModelWrapper () - { - destroy(); - } -private: - void copy(const char* id, const char* version) - { - m_id = id; - m_version = version; - } - void construct() - { - m_model.pRender = NULL; - m_model.pSelect = NULL; - m_model.pEdit = NULL; - - const _QERPlugModelTable* pTable = g_ModelManager.GetModelTable(m_version.c_str()); - - if(pTable != NULL) - pTable->m_pfnLoadModel(&m_model, m_id.c_str()); - } - void destroy() - { - if (m_model.pRender) m_model.pRender->DecRef(); - if (m_model.pSelect) m_model.pSelect->DecRef(); - if (m_model.pEdit) m_model.pEdit->DecRef(); - } - string_t m_id; - string_t m_version; - entity_interfaces_t m_model; - int refcount; -}; - -/*! Creates and tracks CModelWrapper instances. -Creates a new instance for each unique ID requested, keeps count of the number of -times an ID is being referenced, and destroys any instance that is no longer in use */ -class CModelManager : public IModelCache -{ -public: - CModelManager() - { - m_ptrs = g_ptr_array_new (); - } - virtual ~CModelManager() - { - g_ptr_array_free(m_ptrs, FALSE); - } - - virtual void DeleteByID(const char *id, const char* version) - { - unsigned int i; - CModelWrapper *elem; - for(i=0; ilen; i++) - { - elem = (CModelWrapper*)m_ptrs->pdata[i]; - if(strcmp(elem->m_version.c_str(), version) == 0 - && strcmp(elem->m_id.c_str(), id) == 0 - && --elem->refcount == 0) - { - g_ptr_array_remove_index_fast(m_ptrs, i); - delete elem; - return; - } - } - } - - virtual entity_interfaces_t *GetByID(const char *id, const char* version) - { - unsigned int i; - CModelWrapper *elem; - for(i=0; ilen; i++) - { - elem = (CModelWrapper*)m_ptrs->pdata[i]; - if(strcmp(elem->m_version.c_str(), version) == 0 - && strcmp(elem->m_id.c_str(), id) == 0) - { - elem->refcount++; - return &elem->m_model; - } - } - - elem = new CModelWrapper(id, version); - g_ptr_array_add(m_ptrs, elem); - - return &elem->m_model; - } - - virtual void RefreshAll() - { - for(unsigned int i=0; ilen; ++i) - ((CModelWrapper*)m_ptrs->pdata[i])->Refresh(); - } -private: - GPtrArray *m_ptrs; // array of CModelWrapper* -}; - -CModelManager g_model_cache; - -IModelCache* GetModelCache() -{ - return &g_model_cache; -} - -// toolbar manager -class CRadiantToolbarModuleManager : public CSynapseAPIManager -{ - typedef list APIDescriptorList; - - APIDescriptorList mAPIs; -public: - CRadiantToolbarModuleManager() - { - SetMatchAPI(TOOLBAR_MAJOR, "*"); - } - virtual ~CRadiantToolbarModuleManager() - { - APIDescriptorList::iterator i; - for(i=mAPIs.begin(); i!=mAPIs.end(); i++) - { - delete (_QERPlugToolbarTable*)(*i)->mpTable; - delete *i; - *i = NULL; - } - mAPIs.clear(); - } - - // CSynapseAPIManager interface ------------------- - APIDescriptor_t* BuildRequireAPI(APIDescriptor_t* pAPI) - { - APIDescriptor_t* pRequireAPI = CSynapseAPIManager::PrepareRequireAPI(pAPI); - pRequireAPI->mpTable = new _QERPlugToolbarTable; - ((_QERPlugToolbarTable*)pRequireAPI->mpTable)->m_nSize = sizeof(_QERPlugToolbarTable); - pRequireAPI->mSize = sizeof(_QERPlugToolbarTable); - mAPIs.push_front(pRequireAPI); - return pRequireAPI; - } - - // Toolbar Manager specific - void ConstructToolbar() - { - APIDescriptorList::iterator i; - for(i=mAPIs.begin(); i!=mAPIs.end(); i++) - AddItem((_QERPlugToolbarTable*)(*i)->mpTable); - } - -private: - - void AddItem(_QERPlugToolbarTable* pTable) - { - const unsigned int count = pTable->m_pfnToolbarButtonCount(); - for(unsigned int i=0; im_pfnGetToolbarButton(i); - g_pParentWnd->AddPlugInToolbarButton(button); - } - } -}; - -CRadiantToolbarModuleManager g_ToolbarModuleManager; - - -/* image manager ---------------------------------------- */ - -CRadiantImageManager::~CRadiantImageManager() -{ - list::iterator iSlot; - for(iSlot = mSlots.begin(); iSlot != mSlots.end(); iSlot++) - { - delete *iSlot; - *iSlot = NULL; - } -} - -void CImageTableSlot::InitForFillAPITable(APIDescriptor_t *pAPI) -{ - mpAPI = pAPI; - mpTable = new _QERPlugImageTable; - mpTable->m_nSize = sizeof(_QERPlugImageTable); - mpAPI->mSize = sizeof(_QERPlugImageTable); - mpAPI->mpTable = mpTable; -} - -void CRadiantImageManager::FillAPITable(APIDescriptor_t *pAPI) -{ - CImageTableSlot *pSlot = new CImageTableSlot(); - pSlot->InitForFillAPITable(pAPI); - mSlots.push_front(pSlot); -} - -/*! - Loads an image by calling the module that handles the extension extracted from the filename - \param name The filename to load. If no extension is provided, we walk the list of supported extensions. - \param pic The returned image data - \param width The returned width of the image - \param height The returned height of the image -*/ -void CRadiantImageManager::LoadImage(const char *name, byte **pic, int *width, int *height) -{ - const char *ext = NULL; - int len; - - // extract extension - len = strlen (name); - if ((len > 5) && (name[len-4] == '.')) - ext = &name[len-3]; - - if (ext == NULL) - { - // if no extension is provided, start walking through the list - Str fullname; - list::iterator iSlot; - for(iSlot = mSlots.begin(); iSlot != mSlots.end(); iSlot++) - { - APIDescriptor_t *pAPI = (*iSlot)->GetDescriptor(); - fullname.Format("%s.%s", name, pAPI->minor_name); - (*iSlot)->GetTable()->m_pfnLoadImage(fullname.GetBuffer(), pic, width, height); - if (*pic) - return; // this was the right extension, we loaded - } - return; - } - - // start walking the interfaces - list::iterator iSlot; - for(iSlot = mSlots.begin(); iSlot != mSlots.end(); iSlot++) - { - APIDescriptor_t *pAPI = (*iSlot)->GetDescriptor(); - if (!strcmp(pAPI->minor_name, ext)) - { - (*iSlot)->GetTable()->m_pfnLoadImage(name, pic, width, height); - return; - } - } - Sys_FPrintf(SYS_WRN, "WARNING: no image table for extension '%s'\n", ext); -} - -void CRadiantImageManager::BeginExtensionsScan() -{ - mExtScanSlot = mSlots.begin(); -} - -const char* CRadiantImageManager::GetNextExtension() -{ - if (mExtScanSlot != mSlots.end()) - { - char *ext = (*mExtScanSlot)->GetDescriptor()->minor_name; - mExtScanSlot++; - return ext; - } - return NULL; -} - -/* plugin manager --------------------------------------- */ -APIDescriptor_t* CRadiantPluginManager::BuildRequireAPI(APIDescriptor_t *pAPI) -{ - CPluginSlot *pSlot = new CPluginSlot(pAPI); - mSlots.push_front(pSlot); - return pSlot->GetDescriptor(); -} - -void CRadiantPluginManager::PopulateMenu() -{ - list::iterator iPlug; - for(iPlug=mSlots.begin(); iPlug != mSlots.end(); iPlug++) - { - g_pParentWnd->AddPlugInMenuItem(*iPlug); - } -} - -void CSynapseClientRadiant::ImportMap(IDataStream *in, CPtrArray *ents, const char *type) -{ - if (strcmp(type,"map")==0) - { - g_MapTable.m_pfnMap_Read(in, ents); - } - else if (strcmp(type,"xmap")==0) - { - g_MapTable2.m_pfnMap_Read(in, ents); - } - else - Sys_FPrintf(SYS_WRN, "WARNING: no module found for map interface type '%s'\n", type); -} - -void CSynapseClientRadiant::ExportMap(CPtrArray *ents, IDataStream *out, const char *type) -{ - if (strcmp(type,"map")==0) - { - g_MapTable.m_pfnMap_Write(ents, out); - } - else if (strcmp(type,"xmap")==0) - { - g_MapTable2.m_pfnMap_Write(ents, out); - } - else - Sys_FPrintf(SYS_WRN, "WARNING: no module found for map interface type '%s'\n", type); -} - -CPluginSlot::CPluginSlot(APIDescriptor_t *pAPI) -{ - mpAPI = CSynapseAPIManager::PrepareRequireAPI(pAPI); - mpTable = new _QERPluginTable; - mpTable->m_nSize = sizeof(_QERPluginTable); - mpAPI->mSize = sizeof(_QERPluginTable); - mpAPI->mpTable = mpTable; - m_CommandStrings = NULL; - m_CommandIDs = NULL; - m_bReady = false; -} - -CPluginSlot::~CPluginSlot() -{ - delete mpAPI; - delete mpTable; - while (m_CommandStrings) - { - ::free (m_CommandStrings->data); - m_CommandStrings = g_slist_remove (m_CommandStrings, m_CommandStrings->data); - } -} - -void CPluginSlot::Init() -{ - CString str = mpTable->m_pfnQERPlug_GetCommandList(); - char cTemp[1024]; - strcpy(cTemp, str); - char* token = strtok(cTemp, ",;"); - if (token && *token == ' ') - { - while (*token == ' ') - token++; - } - while (token != NULL) - { - m_CommandStrings = g_slist_append (m_CommandStrings, strdup (token)); - token = strtok(NULL, ",;"); - } - mpTable->m_pfnQERPlug_Init(NULL, (void*)g_pParentWnd->m_pWidget); - m_bReady = true; -} - -const char* CPluginSlot::getMenuName() -{ - return mpAPI->minor_name; -} - -int CPluginSlot::getCommandCount() -{ - if (!m_bReady) - Init(); - return g_slist_length (m_CommandStrings); -} - -const char* CPluginSlot::getCommand(int n) -{ - if (!m_bReady) - Init(); - return (char*)g_slist_nth_data (m_CommandStrings, n); -} - -void CPluginSlot::addMenuID(int n) -{ - m_CommandIDs = g_slist_append (m_CommandIDs, GINT_TO_POINTER (n)); -} - -bool CPluginSlot::ownsCommandID(int n) -{ - GSList* lst; - - for (lst = m_CommandIDs; lst != NULL; lst = g_slist_next (lst)) - { - if (GPOINTER_TO_INT (lst->data) == n) - return true; - } - return false; -} - -void CPluginSlot::Dispatch(const char *p) -{ - vec3_t vMin, vMax; - if (selected_brushes.next == &selected_brushes) - { - vMin[0] = vMin[1] = vMin[2] = 0; - VectorCopy(vMin, vMax); - } else - { - Select_GetBounds (vMin, vMax); - } - mpTable->m_pfnQERPlug_Dispatch(p, vMin, vMax, QE_SingleBrush(true)); -} - -CRadiantPluginManager::~CRadiantPluginManager() -{ - list::iterator iSlot; - for(iSlot=mSlots.begin(); iSlot!=mSlots.end(); iSlot++) - { - delete *iSlot; - *iSlot = NULL; - } -} - -bool CRadiantPluginManager::Dispatch(int n, const char* p) -{ - list::iterator iPlug; - for(iPlug=mSlots.begin(); iPlug!=mSlots.end(); iPlug++) - { - CPluginSlot *pPlug = *iPlug; - if (pPlug->ownsCommandID(n)) - { - pPlug->Dispatch(p); - return true; - } - } - return false; -} - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -CPlugInManager::CPlugInManager() -{ - PatchesMode = EActivePatches; - m_PlugIns = NULL; -} - -CPlugInManager::~CPlugInManager() -{ - Cleanup(); -} - -void CPlugInManager::InitForDir(const Str &dir) -{ - Str path; - - path = dir; - path += g_strPluginsDir; - // SYNAPSE - g_pParentWnd->GetSynapseServer().AddSearchPath(path); - - if (strcmp(g_strPluginsDir.GetBuffer(), g_strModulesDir.GetBuffer()) != 0) - { - path = dir; - path += g_strModulesDir; - // SYNAPSE - g_pParentWnd->GetSynapseServer().AddSearchPath(path); - } -} - -static const XMLConfigEntry_t manager_entries[] = - { - { VFS_MAJOR, SYN_REQUIRE, sizeof(g_FileSystemTable), &g_FileSystemTable }, - { SHADERS_MAJOR, SYN_REQUIRE, sizeof(g_ShadersTable), &g_ShadersTable }, - { MAP_MAJOR, SYN_REQUIRE, sizeof(g_MapTable), &g_MapTable }, - { ECLASS_MAJOR, SYN_REQUIRE, sizeof(g_EClassDefTable), &g_EClassDefTable }, - { SURFACEDIALOG_MAJOR, SYN_REQUIRE, sizeof(g_SurfaceTable), &g_SurfaceTable }, - { NULL, SYN_UNKNOWN, 0, NULL } }; - -void CPlugInManager::Init() -{ - Str synapse_config; - - Cleanup(); - - // set some globals - g_qeglobals.bBSPFrontendPlugin = false; - - InitForDir(g_strGameToolsPath); - InitForDir(g_strAppPath); - - synapse_config = g_strGameToolsPath; - synapse_config += "synapse.config"; - if (!g_pParentWnd->GetSynapseServer().Initialize(synapse_config.GetBuffer(), &Sys_Printf_VA)) - Error("Synpase server initialization failed (see console)\n"); - - // builtin modules - g_pParentWnd->GetSynapseServer().EnumerateBuiltinModule(&eclass_def); - - // APIs we provide - g_pParentWnd->GetSynapseClient().AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1)); - g_pParentWnd->GetSynapseClient().AddAPI(SCRIPLIB_MAJOR, NULL, sizeof(_QERScripLibTable)); - g_pParentWnd->GetSynapseClient().AddAPI(BRUSH_MAJOR, NULL, sizeof(_QERBrushTable)); - g_pParentWnd->GetSynapseClient().AddAPI(APPSHADERS_MAJOR, NULL, sizeof(_QERAppShadersTable)); - g_pParentWnd->GetSynapseClient().AddAPI(QGL_MAJOR, NULL, sizeof(_QERQglTable)); - g_pParentWnd->GetSynapseClient().AddAPI(DATA_MAJOR, NULL, sizeof(_QERAppDataTable)); - g_pParentWnd->GetSynapseClient().AddAPI(PATCH_MAJOR, NULL, sizeof(_QERPatchTable)); - g_pParentWnd->GetSynapseClient().AddAPI(ECLASSMANAGER_MAJOR, NULL, sizeof(_EClassManagerTable)); - g_pParentWnd->GetSynapseClient().AddAPI(SELECTEDFACE_MAJOR, NULL, sizeof(_QERSelectedFaceTable)); - g_pParentWnd->GetSynapseClient().AddAPI(APPSURFACEDIALOG_MAJOR, NULL, sizeof(_QERAppSurfaceTable)); - g_pParentWnd->GetSynapseClient().AddAPI(UNDO_MAJOR, NULL, sizeof(_QERUndoTable)); - g_pParentWnd->GetSynapseClient().AddAPI(UI_MAJOR, NULL, sizeof(_QERUITable)); - g_pParentWnd->GetSynapseClient().AddAPI(UIGTK_MAJOR, NULL, sizeof(_QERUIGtkTable)); - g_pParentWnd->GetSynapseClient().AddAPI(CAMERA_MAJOR, NULL, sizeof(_QERCameraTable)); - - // modules configured by XML - if ( !g_pParentWnd->GetSynapseClient().ConfigXML( &g_pParentWnd->GetSynapseServer(), "core", manager_entries ) ) { - Error("Synapse server initialization failed (see console)\n"); - } - - // adding a manager is a special case that ConfigXML doesn't take care of - g_pParentWnd->GetSynapseServer().SelectClientConfig( "core" ); - char *minor; - if ( !g_pParentWnd->GetSynapseServer().GetConfigForAPI( IMAGE_MAJOR, &minor ) ) { - Syn_Printf( "GetConfigForAPI '%s' failed - invalid XML config file?\n", IMAGE_MAJOR ); - Error("Synapse server initialization failed (see console)\n"); - } - g_ImageManager.SetMatchAPI( IMAGE_MAJOR, minor ); - g_pParentWnd->GetSynapseClient().AddManager( &g_ImageManager ); - - // SYN_REQUIRE entries which are still hardcoded - g_pParentWnd->GetSynapseClient().AddAPI(MAP_MAJOR, "mapxml", sizeof(g_MapTable2), SYN_REQUIRE, &g_MapTable2); - g_pParentWnd->GetSynapseClient().AddAPI(ENTITY_MAJOR, NULL, sizeof(g_EntityTable), SYN_REQUIRE, &g_EntityTable); - - // plugins: load anything that claims to be a plugin - // minor becomes some kind of matching pattern - // g_PluginsManager is an API any class, it receives several function tables as needed - // you can't do a SYN_PROVIDE with that, has to be a SYN_REQUIRE ? - g_PluginsManager.SetMatchAPI(PLUGIN_MAJOR, "*"); - g_pParentWnd->GetSynapseClient().AddManager(&g_PluginsManager); - g_pParentWnd->GetSynapseClient().AddManager(&g_ToolbarModuleManager); - g_pParentWnd->GetSynapseClient().AddManager(&g_ModelManager); - if (!g_pParentWnd->GetSynapseServer().Resolve(&g_pParentWnd->GetSynapseClient())) - { - Error("synapse initialization fail (see console)"); - } - g_PluginsManager.PopulateMenu(); - g_ToolbarModuleManager.ConstructToolbar(); - InitFileTypes(); -} - -void CPlugInManager::Shutdown() -{ - g_pParentWnd->GetSynapseServer().Shutdown(); -} - -void CPlugInManager::Cleanup() -{ - int i; - - for (i = 0; i < m_BrushHandles.GetSize(); i++) - { - brush_t *pb = reinterpret_cast(m_BrushHandles.GetAt(i)); - Brush_Free(pb); - } - m_BrushHandles.RemoveAll(); - - for (i = 0; i < m_EntityHandles.GetSize(); i++) - { - entity_t *pe = reinterpret_cast(m_EntityHandles.GetAt(i)); - Entity_Free(pe); - } - m_EntityHandles.RemoveAll(); - - // patches - // these are linked into the map - m_PatchesHandles.RemoveAll(); - // these patches were allocated by Radiant on plugin request - // if the list is not empty, it means either the plugin asked for allocation and never commited them to the map - // in which case we are supposed to delete them - // or it commited them but never called m_pfnReleasePatchHandles, in case the patches may have already been - // erased and we are trying a second time, therefore crashing .. - //++timo FIXME: for now I leave a leak warning, we'd need a table to keep track of commited patches -#ifdef _DEBUG - if (m_PluginPatches.GetSize() != 0) - Sys_Printf("WARNING: m_PluginPatches.GetSize() != 0 in CPlugInManager::Cleanup, possible leak\n"); -#endif - -/* for (i = 0; i < m_PluginPatches.GetSize(); i++) - { - patchMesh_t *pMesh = reinterpret_cast(m_PluginPatches.GetAt(i)); - if (pMesh->pSymbiot) - delete pMesh; - } - m_PluginPatches.RemoveAll(); */ -} - -void CPlugInManager::Dispatch(int n, const char * p) -{ - g_PluginsManager.Dispatch(n, p); -} - -void WINAPI QERApp_GetDispatchParams(vec3_t vMin, vec3_t vMax, bool *bSingleBrush) -{ - if (selected_brushes.next == &selected_brushes) - { - vMin[0] = vMin[1] = vMin[2] = 0; - VectorCopy(vMin, vMax); - } else - { - Select_GetBounds (vMin, vMax); - } - - if( bSingleBrush ) - *bSingleBrush = QE_SingleBrush(true); -} - - -// creates a dummy brush in the active brushes list -// FIXME : is this one really USED ? -void WINAPI QERApp_CreateBrush(vec3_t vMin, vec3_t vMax) -{ - - brush_t* pBrush = Brush_Create(vMin, vMax, &g_qeglobals.d_texturewin.texdef); - Entity_LinkBrush (world_entity, pBrush); - Brush_Build(pBrush); - Brush_AddToList (pBrush, &active_brushes); - Select_Brush(pBrush); - Sys_UpdateWindows(W_ALL); -} - -void* CPlugInManager::CreateBrushHandle() -{ - brush_t *pb = Brush_Alloc(); - pb->numberId = g_nBrushId++; - m_BrushHandles.Add(pb); - return(void*)pb; -} - -void CPlugInManager::DeleteBrushHandle(void * vp) -{ - CPtrArray* pHandles[3]; - pHandles[0] = &m_SelectedBrushHandles; - pHandles[1] = &m_ActiveBrushHandles; - pHandles[2] = &m_BrushHandles; - - for (int j = 0; j < 3; j++) - { - for (int i = 0; i < pHandles[j]->GetSize(); i++) - { - brush_t *pb = reinterpret_cast(pHandles[j]->GetAt(i)); - if (pb == reinterpret_cast(vp)) - { - if (j == 2) - { - // only remove it from the list if it is work area - // this allows the selected and active list indexes to remain constant - // throughout a session (i.e. between an allocate and release) - pHandles[j]->RemoveAt(i); - } - Brush_Free(pb); - Sys_MarkMapModified(); // PGM - return; - } - } - } -} - -void CPlugInManager::CommitBrushHandleToMap(void * vp) -{ - g_bScreenUpdates = false; - for (int i = 0; i < m_BrushHandles.GetSize(); i++) - { - brush_t *pb = reinterpret_cast(m_BrushHandles.GetAt(i)); - if (pb == reinterpret_cast(vp)) - { - m_BrushHandles.RemoveAt(i); - Entity_LinkBrush (world_entity, pb); - Brush_Build(pb); - Brush_AddToList (pb, &active_brushes); - Select_Brush(pb); - } - } - g_bScreenUpdates = true; - Sys_UpdateWindows(W_ALL); -} - -void CPlugInManager::AddFaceToBrushHandle(void * vp, vec3_t v1, vec3_t v2, vec3_t v3) -{ - brush_t *bp = FindBrushHandle(vp); - if (bp != NULL) - { - face_t *f = Face_Alloc(); - f->texdef = g_qeglobals.d_texturewin.texdef; - f->texdef.flags &= ~SURF_KEEP; - f->texdef.contents &= ~CONTENTS_KEEP; - f->next = bp->brush_faces; - bp->brush_faces = f; - VectorCopy (v1, f->planepts[0]); - VectorCopy (v2, f->planepts[1]); - VectorCopy (v3, f->planepts[2]); - } -} - -brush_t* CPlugInManager::FindBrushHandle(void * vp) -{ - CPtrArray* pHandles[4]; - pHandles[0] = &m_SelectedBrushHandles; - pHandles[1] = &m_ActiveBrushHandles; - pHandles[2] = &m_BrushHandles; - pHandles[3] = &m_EntityBrushHandles; - - for (int j = 0; j < 4; j++) - { - for (int i = 0; i < pHandles[j]->GetSize(); i++) - { - brush_t *pb = reinterpret_cast(pHandles[j]->GetAt(i)); - if (pb == reinterpret_cast(vp)) - { - return pb; - } - } - } - return NULL; -} - -patchMesh_t* CPlugInManager::FindPatchHandle(int index) -{ - switch (PatchesMode) - { - case EActivePatches: - case ESelectedPatches: - if ( index < m_PatchesHandles.GetSize() ) - { - brush_t *pb = reinterpret_cast(m_PatchesHandles.GetAt(index)); - return pb->pPatch; - } -#ifdef _DEBUG - Sys_Printf("WARNING: out of bounds in CPlugInManager::FindPatchHandle\n"); -#endif - break; - case EAllocatedPatches: - if ( index < m_PluginPatches.GetSize() ) - { - patchMesh_t *pPatch = reinterpret_cast(m_PluginPatches.GetAt(index)); - return pPatch; - } -#ifdef _DEBUG - Sys_Printf("WARNING: out of bounds in CPlugInManager::FindPatchHandle\n"); -#endif - break; - } - return NULL; -} - -void* WINAPI QERApp_CreateBrushHandle() -{ - return g_pParentWnd->GetPlugInMgr().CreateBrushHandle(); -} - -void WINAPI QERApp_DeleteBrushHandle(void* vp) -{ - g_pParentWnd->GetPlugInMgr().DeleteBrushHandle(vp); -} - -void WINAPI QERApp_CommitBrushHandleToMap(void* vp) -{ - g_pParentWnd->GetPlugInMgr().CommitBrushHandleToMap(vp); -} - -void WINAPI QERApp_AddFace(void* vp, vec3_t v1, vec3_t v2, vec3_t v3) -{ - g_pParentWnd->GetPlugInMgr().AddFaceToBrushHandle(vp, v1, v2, v3); -} - -void WINAPI QERApp_DeleteSelection() -{ - Select_Delete(); -} - -void QERApp_GetCamera( vec3_t origin, vec3_t angles ) -{ - VectorCopy( g_pParentWnd->GetCamWnd()->Camera()->origin, origin ); - VectorCopy( g_pParentWnd->GetCamWnd()->Camera()->angles, angles ); -} - -void QERApp_SetCamera( vec3_t origin, vec3_t angles ) -{ - VectorCopy( origin, g_pParentWnd->GetCamWnd()->Camera()->origin ); - VectorCopy( angles, g_pParentWnd->GetCamWnd()->Camera()->angles ); - - Sys_UpdateWindows( W_ALL ); // specify - g_pParentWnd->OnTimer(); -} - -void QERApp_GetCamWindowExtents( int *x, int *y, int *width, int *height ) -{ - GtkWidget *widget; - - if (g_pParentWnd->CurrentStyle() == MainFrame::eFloating) - widget = g_pParentWnd->GetCamWnd()->m_pParent; - else - widget = g_pParentWnd->GetCamWnd()->GetWidget(); - - get_window_pos (widget, x, y); - - *width = g_pParentWnd->GetCamWnd()->Camera()->width; - *height = g_pParentWnd->GetCamWnd()->Camera()->height; -} - -//FIXME: this AcquirePath stuff is pretty much a mess and needs cleaned up -bool g_bPlugWait = false; -bool g_bPlugOK = false; -int g_nPlugCount = 0; - -void _PlugDone(bool b, int n) -{ - g_bPlugWait = false; - g_bPlugOK = b; - g_nPlugCount = n; -} - -void WINAPI QERApp_GetPoints(int nMax, _QERPointData *pData, char* pMsg) -{ - ShowInfoDialog(pMsg); - g_bPlugWait = true; - g_bPlugOK = false; - g_nPlugCount = 0; -// g_nPlugCount=nMax-1; - AcquirePath(nMax, &_PlugDone); - - while (g_bPlugWait) - gtk_main_iteration (); - - HideInfoDialog(); - - pData->m_nCount = 0; - pData->m_pVectors = NULL; - - if (g_bPlugOK && g_nPlugCount > 0) - { - pData->m_nCount = g_nPlugCount; - pData->m_pVectors = reinterpret_cast(qmalloc(g_nPlugCount * sizeof(vec3_t))); - vec3_t *pOut = pData->m_pVectors; - for (int i = 0; i < g_nPlugCount; i++) - { - memcpy(pOut, &g_PathPoints[i],sizeof(vec3_t)); - pOut++; - } - } -} - -//#define DBG_PAPI - -void CheckTexture(face_t *f) -{ - if (!f->d_texture) - { -#ifdef DBG_PAPI - Sys_Printf("CheckTexture: requesting %s\n", f->texdef.name); -#endif - f->pShader = QERApp_Shader_ForName (f->texdef.GetName()); - f->pShader->IncRef(); - f->d_texture = f->pShader->getTexture(); - } -} - -// expects pData->m_TextureName to be relative to "textures/" -void WINAPI QERApp_AddFaceData(void* pv, _QERFaceData *pData) -{ -#ifdef DBG_PAPI - Sys_Printf("FindBrushHandle..."); -#endif - brush_t* pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); -#ifdef DBG_PAPI - Sys_Printf("Done\n"); -#endif - if (pBrush != NULL) - { - face_t *f = Face_Alloc(); - f->texdef = g_qeglobals.d_texturewin.texdef; - f->texdef.flags = pData->m_nFlags; - f->texdef.contents = pData->m_nContents; - f->texdef.value = pData->m_nValue; - f->texdef.SetName(pData->m_TextureName); - f->next = pBrush->brush_faces; - pBrush->brush_faces = f; - VectorCopy (pData->m_v1, f->planepts[0]); - VectorCopy (pData->m_v2, f->planepts[1]); - VectorCopy (pData->m_v3, f->planepts[2]); - // we might need to convert one way or the other if the input and the brush coordinates setting don't match - if (pData->m_bBPrimit == true) - { - f->brushprimit_texdef = pData->brushprimit_texdef; - if (!g_qeglobals.m_bBrushPrimitMode) - { - // before calling into the conversion, make sure we have a texture! - CheckTexture (f); -#ifdef DBG_PAPI - Sys_Printf("BrushPrimitFaceToFace..."); -#endif - - // convert BP to regular - BrushPrimitFaceToFace (f); -#ifdef DBG_PAPI - Sys_Printf("Done\n"); -#endif - } - } else - { -#ifdef _DEBUG - if (pData->m_bBPrimit != false) - Sys_FPrintf (SYS_WRN, "non-initialized pData->m_bBPrimit in QERApp_AddFaceData\n"); -#endif - f->texdef.rotate = pData->m_fRotate; - f->texdef.shift[0] = pData->m_fShift[0]; - f->texdef.shift[1] = pData->m_fShift[1]; - f->texdef.scale[0] = pData->m_fScale[0]; - f->texdef.scale[1] = pData->m_fScale[1]; - if (g_qeglobals.m_bBrushPrimitMode) - { - CheckTexture (f); -#ifdef DBG_PAPI - Sys_Printf("FaceToBrushPrimitFace..."); -#endif - - // convert regular to BP - FaceToBrushPrimitFace (f); -#ifdef DBG_PAPI - Sys_Printf("Done\n"); -#endif - } - } - Sys_MarkMapModified(); // PGM - } -} - -int WINAPI QERApp_GetFaceCount(void* pv) -{ - int n = 0; - brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); - if (pBrush != NULL) - { - for (face_t *f = pBrush->brush_faces ; f; f = f->next) - { - n++; - } - } - return n; -} - -_QERFaceData* WINAPI QERApp_GetFaceData(void* pv, int nFaceIndex) -{ - static _QERFaceData face; - int n = 0; - brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); - - if (pBrush != NULL) - { - for (face_t *f = pBrush->brush_faces ; f; f = f->next) - { - -#ifdef _DEBUG - if (!pBrush->brush_faces) - { - Sys_Printf( "Warning : pBrush->brush_faces is NULL in QERApp_GetFaceData\n" ); - return NULL; - } -#endif - - if (n == nFaceIndex) - { - face.m_nContents = f->texdef.contents; - face.m_nFlags = f->texdef.flags; - face.m_nValue = f->texdef.value; - if (g_qeglobals.m_bBrushPrimitMode) - { - //++timo NOTE: we may want to convert back to old format for backward compatibility with some old plugins? - face.m_bBPrimit = true; - face.brushprimit_texdef = f->brushprimit_texdef; - } else - { - face.m_fRotate = f->texdef.rotate; - face.m_fScale[0] = f->texdef.scale[0]; - face.m_fScale[1] = f->texdef.scale[1]; - face.m_fShift[0] = f->texdef.shift[0]; - face.m_fShift[1] = f->texdef.shift[1]; - } - strcpy(face.m_TextureName, f->texdef.GetName()); - VectorCopy(f->planepts[0], face.m_v1); - VectorCopy(f->planepts[1], face.m_v2); - VectorCopy(f->planepts[2], face.m_v3); - return &face; - } - n++; - } - } - return NULL; -} - -void WINAPI QERApp_SetFaceData(void* pv, int nFaceIndex, _QERFaceData *pData) -{ - int n = 0; - brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); - - if (pBrush != NULL) - { - for (face_t *f = pBrush->brush_faces ; f; f = f->next) - { - if (n == nFaceIndex) - { - f->texdef.flags = pData->m_nFlags; - f->texdef.contents = pData->m_nContents; - f->texdef.value = pData->m_nValue; - f->texdef.rotate = pData->m_fRotate; - f->texdef.shift[0] = pData->m_fShift[0]; - f->texdef.shift[1] = pData->m_fShift[1]; - f->texdef.scale[0] = pData->m_fScale[0]; - f->texdef.scale[1] = pData->m_fScale[1]; - //strcpy(f->texdef.name, pData->m_TextureName); - f->texdef.SetName(pData->m_TextureName); - VectorCopy(pData->m_v1, f->planepts[0]); - VectorCopy(pData->m_v2, f->planepts[1]); - VectorCopy(pData->m_v3, f->planepts[2]); - Sys_MarkMapModified(); // PGM - return; // PGM - } - n++; - } - } -} - -void WINAPI QERApp_DeleteFace(void* pv, int nFaceIndex) -{ - int n = 0; - brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); - if (pBrush != NULL) - { - face_t *pPrev = pBrush->brush_faces; - for (face_t *f = pBrush->brush_faces; f; f = f->next) - { - if (n == nFaceIndex) - { - pPrev->next = f->next; - Face_Free (f); - Sys_MarkMapModified(); // PGM - return; - } - n++; - pPrev = f; - } - } -} - -//========== -//PGM -void WINAPI QERApp_BuildBrush (void* pv) -{ - brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); - if (pBrush != NULL) - { - Brush_Build(pBrush); - Sys_UpdateWindows(W_ALL); - } -} - -//Timo : another version with bConvert flag -//++timo since 1.7 is not compatible with earlier plugin versions, remove this one and update QERApp_BuildBrush -void WINAPI QERApp_BuildBrush2 (void* pv, int bConvert) -{ - brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); - if (pBrush != NULL) - { - Brush_Build( pBrush, true, true, bConvert ); - Sys_UpdateWindows(W_ALL); - } -} - -void WINAPI QERApp_SelectBrush (void* pv) -{ - brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); - if (pBrush != NULL) - { - Select_Brush(pBrush, false); - Sys_UpdateWindows(W_ALL); - } - -} - -void WINAPI QERApp_DeselectBrush (void* pv) -{ - // FIXME - implement this! -} - -void WINAPI QERApp_ResetPlugins() -{ - g_pParentWnd->OnPluginsRefresh(); -} - -void WINAPI QERApp_DeselectAllBrushes () -{ - Select_Deselect(); - Sys_UpdateWindows(W_ALL); -} -//PGM -//========== - -void WINAPI QERApp_TextureBrush(void* pv, char* pName) -{ - brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); - if (pBrush != NULL) - { - for (face_t *f = pBrush->brush_faces ; f; f = f->next) - { - //strcpy(f->texdef.name, pName); - f->texdef.SetName(pName); - } - Sys_MarkMapModified(); // PGM - } -} - -int WINAPI QERApp_SelectedBrushCount() -{ - int n = 0; - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - n++; - } - return n; -} - -int WINAPI QERApp_ActiveBrushCount() -{ - int n = 0; - for (brush_t *pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next) - { - n++; - } - return n; -} - -int WINAPI QERApp_AllocateSelectedBrushHandles() -{ - int n = 0; - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - n++; - g_pParentWnd->GetPlugInMgr().GetSelectedHandles().Add(pb); - } - return n; -} - -int WINAPI QERApp_AllocateActiveBrushHandles() -{ - int n = 0; - for (brush_t *pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next) - { - n++; - g_pParentWnd->GetPlugInMgr().GetActiveHandles().Add(pb); - } - return n; -} - -void WINAPI QERApp_ReleaseSelectedBrushHandles() -{ - g_pParentWnd->GetPlugInMgr().GetSelectedHandles().RemoveAll(); - Sys_UpdateWindows(W_ALL); -} - -void WINAPI QERApp_ReleaseActiveBrushHandles() -{ - g_pParentWnd->GetPlugInMgr().GetActiveHandles().RemoveAll(); - Sys_UpdateWindows(W_ALL); -} - -void* WINAPI QERApp_GetActiveBrushHandle(int nIndex) -{ - if (nIndex < g_pParentWnd->GetPlugInMgr().GetActiveHandles().GetSize()) - { - return reinterpret_cast(g_pParentWnd->GetPlugInMgr().GetActiveHandles().GetAt(nIndex)); - } - return NULL; -} - -void* WINAPI QERApp_GetSelectedBrushHandle(int nIndex) -{ - if (nIndex < g_pParentWnd->GetPlugInMgr().GetSelectedHandles().GetSize()) - { - return reinterpret_cast(g_pParentWnd->GetPlugInMgr().GetSelectedHandles().GetAt(nIndex)); - } - return NULL; -} - -int WINAPI QERApp_TextureCount() -{ - //++timo TODO: replace by QERApp_GetActiveShaderCount and verify - Texture_StartPos (); - int x, y; - int n = 0; - while (1) - { - IShader *pShader = Texture_NextPos (&x, &y); - if (!pShader) - break; - n++; - } - return n; -} - -char* WINAPI QERApp_GetTexture(int nIndex) -{ - //++timo TODO: replace by QERApp_ActiveShader_ForIndex - // these funcs would end up being provided for backward compatibility - static char name[QER_MAX_NAMELEN]; - Texture_StartPos (); - int x, y; - int n = 0; - while (1) - { - IShader *pShader = Texture_NextPos (&x, &y); - if (!pShader) - break; - if (n == nIndex) - { - strcpy(name, pShader->getName()); - return name; - } - n++; - } - return NULL; -} - -char* WINAPI QERApp_GetCurrentTexture() -{ - static char current_tex[1024]; - strcpy(current_tex,g_qeglobals.d_texturewin.texdef.GetName()); - return current_tex; -} - -void WINAPI QERApp_SetCurrentTexture(char* strName) -{ - //++timo hu ?? tex is not initialized ?? can be any value .. - texdef_t tex; - //++timo added a brushprimit_texdef .. - // smthg to be done here - brushprimit_texdef_t brushprimit_tex; - //strcpy(tex.name, strName); - tex.SetName(strName); - Texture_SetTexture(&tex,&brushprimit_tex); -} - -int WINAPI QERApp_GetEClassCount() -{ - int n = 0; - for (eclass_t *e = eclass ; e ; e = e->next) - { - n++; - } - return n; -} - -char* WINAPI QERApp_GetEClass(int nIndex) -{ - int n = 0; - for (eclass_t *e = eclass ; e ; e = e->next) - { - if (n == nIndex) - { - return e->name; - } - } - return NULL; -} - -// v1.70 code -// world_entity holds the worldspawn and is indexed as 0 -// other entities are in the entities doubly linked list -// QERApp_GetEntityCount counts the entities like in any C array: [0..length-1] -int WINAPI QERApp_GetEntityCount() -{ - int n = 1; - for (entity_t *pe = entities.next ; pe != &entities ; pe = pe->next) - { - n++; - } - return n; -} - -// We don't store entities in CPtrArray, we need to walk the list -void* WINAPI QERApp_GetEntityHandle(int nIndex) -{ - if (nIndex==0) - // looks for the worldspawn - return static_cast(world_entity); - entity_t *pe = &entities; - int n = 0; - while ( n < nIndex ) - { - pe = pe->next; - n++; - } - return static_cast(pe); -} - -epair_t* WINAPI QERApp_AllocateEpair( char *key, char *val ) -{ - epair_t *e = (epair_t*)qmalloc (sizeof(*e)); - e->key = (char*)qmalloc(strlen(key)+1); - strcpy (e->key, key); - e->value = (char*)qmalloc(strlen(val)+1); - strcpy (e->value, val); - return e; -} - -/* -IEpair* WINAPI QERApp_IEpairForEntityHandle(void *vp) -{ - entity_t *pe = static_cast(vp); - CEpairsWrapper *pEp = new CEpairsWrapper(pe); - pEp->IncRef(); - return pEp; -} - -IEpair* WINAPI QERApp_IEpairForProjectKeys() -{ - CEpairsWrapper *pEp = new CEpairsWrapper(g_qeglobals.d_project_entity); - pEp->IncRef(); - return pEp; -} -*/ - -int WINAPI QERApp_AllocateEntityBrushHandles(void* vp) -{ - entity_t *pe = static_cast(vp); - int n = 0; - if (!pe->brushes.onext) - return 0; - g_pParentWnd->GetPlugInMgr().GetEntityBrushHandles().RemoveAll(); - for (brush_t *pb = pe->brushes.onext ; pb != &pe->brushes ; pb=pb->onext) - { - n++; - g_pParentWnd->GetPlugInMgr().GetEntityBrushHandles().Add(pb); - } - return n; -} - -void WINAPI QERApp_ReleaseEntityBrushHandles() -{ - g_pParentWnd->GetPlugInMgr().GetEntityBrushHandles().RemoveAll(); -} - -void* WINAPI QERApp_GetEntityBrushHandle(int nIndex) -{ - if (nIndex < g_pParentWnd->GetPlugInMgr().GetEntityBrushHandles().GetSize()) - return g_pParentWnd->GetPlugInMgr().GetEntityBrushHandles().GetAt(nIndex); - return NULL; -} - -// FIXME TTimo that entity handles thing sucks .. we should get rid of it .. - -void* WINAPI QERApp_CreateEntityHandle() -{ - entity_t *pe = reinterpret_cast(qmalloc(sizeof(entity_t))); - pe->brushes.onext = pe->brushes.oprev = &pe->brushes; - g_pParentWnd->GetPlugInMgr().GetEntityHandles().Add(static_cast(pe)); - return static_cast(pe); -} - -// the vpBrush needs to be in m_BrushHandles -//++timo we don't have allocation nor storage for vpEntity, no checks for this one -void WINAPI QERApp_CommitBrushHandleToEntity(void* vpBrush, void* vpEntity) -{ - g_pParentWnd->GetPlugInMgr().CommitBrushHandleToEntity(vpBrush, vpEntity); - return; -} - -const char* QERApp_ReadProjectKey(const char* key) -{ - return ValueForKey(g_qeglobals.d_project_entity, key); -} - -#ifdef USEPLUGINENTITIES - -int WINAPI QERApp_ScanFileForEClass(char *filename ) -{ - // set single class parsing - parsing_single = true; - Eclass_ScanFile(filename); - if (eclass_found) - { - eclass_e->nShowFlags |= ECLASS_PLUGINENTITY; - return 1; - } - return 0; -} -#endif // USEPLUGINENTITIES - -// the vpBrush needs to be in m_BrushHandles -//++timo add a debug check to see if we found the brush handle -// NOTE : seems there's no way to check vpEntity is valid .. this is dangerous -// links the brush to its entity, everything else is done when commiting the entity to the map -void CPlugInManager::CommitBrushHandleToEntity(void* vpBrush, void* vpEntity) -{ - brush_t* pb; - entity_t* pe; - for (int i=0 ; i < m_BrushHandles.GetSize() ; i++) - { - if (vpBrush == m_BrushHandles.GetAt(i)) - { - m_BrushHandles.RemoveAt(i); - pb = reinterpret_cast(vpBrush); - pe = reinterpret_cast(vpEntity); - Entity_LinkBrush (pe, pb); - } - } - Sys_UpdateWindows(W_ALL); -} - -// the vpEntity must be in m_EntityHandles -void WINAPI QERApp_CommitEntityHandleToMap(void* vpEntity) -{ - g_pParentWnd->GetPlugInMgr().CommitEntityHandleToMap(vpEntity); - return; -} - -int WINAPI QERApp_LoadFile( const char *pLocation, void ** buffer ) -{ - int nSize = vfsLoadFile(pLocation, buffer, 0); - return nSize; -} - -char * WINAPI QERApp_ExpandReletivePath (char *p) -{ - return ExpandReletivePath(p); -} - -qtexture_t* WINAPI QERApp_Texture_ForName (const char *name) -{ - // if the texture is not loaded yet, this call will get it loaded - // but: when we assign a GL bind number, we need to be in the g_qeglobals.d_xxxBase GL context - // the plugin may set the GL context to whatever he likes, but then load would fail - // NOTE: is context switching time-consuming? then maybe the plugin could handle the context - // switch and only add a sanity check in debug mode here - // read current context - gtk_glwidget_make_current (g_qeglobals_gui.d_glBase); - - //++timo debugging - Sys_Printf("WARNING: QERApp_Texture_ForName ... don't call that!!\n"); - qtexture_t* qtex = QERApp_Texture_ForName2( name ); - return qtex; -} - -char* QERApp_Token() -{ - return token; -} - -int QERApp_ScriptLine() -{ - return scriptline; -} - -// we save the map and return the name .. either .map or .reg to support region compiling -char* QERApp_GetMapName() -{ - static char name[PATH_MAX]; - SaveWithRegion (name); - return name; -} - -void CPlugInManager::CommitEntityHandleToMap(void* vpEntity) -{ - entity_t *pe; - eclass_t *e; - brush_t *b; - vec3_t mins,maxs; - bool has_brushes; - for (int i=0 ; i < m_EntityHandles.GetSize() ; i++ ) - { - if (vpEntity == m_EntityHandles.GetAt(i)) - { - m_EntityHandles.RemoveAt(i); - pe = reinterpret_cast(vpEntity); - // fill additional fields - // straight copy from Entity_Parse - // entity_t::origin - GetVectorForKey (pe, "origin", pe->origin); - // entity_t::eclass - if (pe->brushes.onext == &pe->brushes) - has_brushes = false; - else - has_brushes = true; - e = Eclass_ForName (ValueForKey (pe, "classname"), has_brushes); - pe->eclass = e; - // fixedsize - if (e->fixedsize) - { - if (pe->brushes.onext != &pe->brushes) - { - Sys_Printf("Warning : Fixed size entity with brushes in CPlugInManager::CommitEntityHandleToMap\n"); - } - // create a custom brush - VectorAdd(e->mins, pe->origin, mins); - VectorAdd(e->maxs, pe->origin, maxs); -/* - float a = 0; - if (e->nShowFlags & ECLASS_MISCMODEL) - { - char* p = ValueForKey(pe, "model"); - if (p != NULL && strlen(p) > 0) - { - vec3_t vMin, vMax; - a = FloatForKey (pe, "angle"); - if (GetCachedModel(pe, p, vMin, vMax)) - { - // create a custom brush - VectorAdd (pe->md3Class->mins, pe->origin, mins); - VectorAdd (pe->md3Class->maxs, pe->origin, maxs); - } - } - } -*/ - b = Brush_Create (mins, maxs, &e->texdef); -/* - if (a) - { - vec3_t vAngle; - vAngle[0] = vAngle[1] = 0; - vAngle[2] = a; - Brush_Rotate(b, vAngle, pe->origin, false); - } -*/ - b->owner = pe; - - b->onext = pe->brushes.onext; - b->oprev = &pe->brushes; - pe->brushes.onext->oprev = b; - pe->brushes.onext = b; - } else - { // brush entity - if (pe->brushes.next == &pe->brushes) - Sys_Printf ("Warning: Brush entity with no brushes in CPlugInManager::CommitEntityHandleToMap\n"); - } - - // add brushes to the active brushes list - // and build them along the way - for (b=pe->brushes.onext ; b != &pe->brushes ; b=b->onext) - { - // convert between old brushes and brush primitive - if (g_qeglobals.m_bBrushPrimitMode) - { - // we only filled the shift scale rot fields, needs conversion - Brush_Build( b, true, true, true ); - } else - { - // we are using old brushes - Brush_Build( b ); - } - b->next = active_brushes.next; - active_brushes.next->prev = b; - b->prev = &active_brushes; - active_brushes.next = b; - } - - // handle worldspawn entities - // if worldspawn has no brushes, use the new one - if (!strcmp(ValueForKey (pe, "classname"), "worldspawn")) - { - if ( world_entity && ( world_entity->brushes.onext != &world_entity->brushes ) ) - { - // worldspawn already has brushes - Sys_Printf ("Commiting worldspawn as func_group\n"); - SetKeyValue(pe, "classname", "func_group"); - // add the entity to the end of the entity list - pe->next = &entities; - pe->prev = entities.prev; - entities.prev->next = pe; - entities.prev = pe; - g_qeglobals.d_num_entities++; - } else - { - // there's a worldspawn with no brushes, we assume the map is empty - if ( world_entity ) - { - Entity_Free( world_entity ); - world_entity = pe; - } else - Sys_Printf("Warning : unexpected world_entity == NULL in CommitEntityHandleToMap\n"); - } - } else - { - // add the entity to the end of the entity list - pe->next = &entities; - pe->prev = entities.prev; - entities.prev->next = pe; - entities.prev = pe; - g_qeglobals.d_num_entities++; - } - } - } -} - -void WINAPI QERApp_SetScreenUpdate(int bScreenUpdates) -{ - g_bScreenUpdates = bScreenUpdates; -} - -texturewin_t* QERApp_QeglobalsTexturewin() -{ - return &g_qeglobals.d_texturewin; -} - -texdef_t* QERApp_QeglobalsSavedinfo_SIInc() -{ - return &g_qeglobals.d_savedinfo.m_SIIncrement; -} - -patchMesh_t* QERApp_GetSelectedPatch( ) -{ - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - return pb->pPatch; - } - } -#ifdef _DEBUG - Sys_Printf("WARNING: QERApp_GetSelectedPatchTexdef called with no patch selected\n"); -#endif - return NULL; -} - -const char* WINAPI QERApp_GetGamePath() -{ - return g_pGameDescription->mEnginePath.GetBuffer(); -} - -/*! -\todo the name of this API should prolly be changed -would also need to prompt g_strAppPath / g_strGameToolsPath independently? -*/ -// SPoG -// changed g_strGameToolsPath to g_strAppPath -const char* WINAPI QERApp_GetQERPath() -{ - return g_strAppPath.GetBuffer(); -} - -const char* WINAPI QERApp_GetGameFile() -{ - // FIXME: Arnout: temp solution, need proper 'which game is this' indicator or a different solution for plugins/modules - return g_pGameDescription->mGameFile.GetBuffer(); -} - -// patches in/out ----------------------------------- -int WINAPI QERApp_AllocateActivePatchHandles() -{ - return g_pParentWnd->GetPlugInMgr().AllocateActivePatchHandles(); -} - -// Grid Size -float QERApp_QeglobalsGetGridSize() -{ - return g_qeglobals.d_gridsize; -} - -int CPlugInManager::AllocateActivePatchHandles() -{ - int n = 0; - for (brush_t *pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - n++; - m_PatchesHandles.Add(pb); - } - } - return n; -} - -int WINAPI QERApp_AllocateSelectedPatchHandles() -{ - return g_pParentWnd->GetPlugInMgr().AllocateSelectedPatchHandles(); -} - -int CPlugInManager::AllocateSelectedPatchHandles() -{ - int n = 0; - // change mode - PatchesMode = ESelectedPatches; - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - n++; - m_PatchesHandles.Add(pb); - } - } - return n; -} - -void WINAPI QERApp_ReleasePatchHandles() -{ - g_pParentWnd->GetPlugInMgr().ReleasePatchesHandles(); -} - -patchMesh_t* WINAPI QERApp_GetPatchData(int index) -{ - static patchMesh_t patch; - patchMesh_t *pPatch = g_pParentWnd->GetPlugInMgr().FindPatchHandle(index); - if (pPatch) - { - memcpy( &patch, pPatch, sizeof(patchMesh_t) ); - return &patch; - } - return NULL; -} - -patchMesh_t* WINAPI QERApp_GetPatchHandle(int index) -{ - return g_pParentWnd->GetPlugInMgr().FindPatchHandle(index); -} - -void WINAPI QERApp_DeletePatch(int index) -{ - patchMesh_t *pPatch = g_pParentWnd->GetPlugInMgr().FindPatchHandle(index); - if (pPatch) - { - brush_t *pb = pPatch->pSymbiot; - Patch_Delete( pPatch ); - if (pb) - Brush_Free( pb ); - } -#ifdef _DEBUG - Sys_Printf("Warning: QERApp_DeletePatch: FindPatchHandle failed\n"); -#endif -} - -int WINAPI QERApp_CreatePatchHandle() -{ - return g_pParentWnd->GetPlugInMgr().CreatePatchHandle(); -} - -int CPlugInManager::CreatePatchHandle() -{ - // NOTE: we can't call the AddBrushForPatch until we have filled the patchMesh_t structure - patchMesh_t *pPatch = MakeNewPatch(); - m_PluginPatches.Add( pPatch ); - // change mode - PatchesMode = EAllocatedPatches; - return m_PluginPatches.GetSize()-1; -} - -void WINAPI QERApp_CommitPatchHandleToMap(int index, patchMesh_t *pMesh, char *texName) -{ -#ifdef DBG_PAPI - Sys_Printf ("QERApp_CommitPatchHandleToMap %i..", index); -#endif - g_pParentWnd->GetPlugInMgr().CommitPatchHandleToMap(index, pMesh, texName); -#ifdef DBG_PAPI - Sys_Printf ("Done\n"); -#endif -} - -void WINAPI QERApp_CommitPatchHandleToEntity(int index, patchMesh_t *pMesh, char *texName, void* vpEntity) -{ -#ifdef DBG_PAPI - Sys_Printf ("QERApp_CommitPatchHandleToEntity %i..", index); -#endif - g_pParentWnd->GetPlugInMgr().CommitPatchHandleToEntity(index, pMesh, texName, vpEntity); -#ifdef DBG_PAPI - Sys_Printf ("Done\n"); -#endif -} - -void CPlugInManager::CommitPatchHandleToMap(int index, patchMesh_t *pMesh, char *texName) -{ - if (PatchesMode==EAllocatedPatches) - { - patchMesh_t *pPatch = reinterpret_cast( m_PluginPatches.GetAt(index) ); - memcpy( pPatch, pMesh, sizeof( patchMesh_t ) ); - // patch texturing, if none given use current texture - if (texName) - pPatch->pShader = QERApp_Shader_ForName (texName); - else - pPatch->pShader = QERApp_Shader_ForName(g_qeglobals.d_texturewin.texdef.GetName()); - pPatch->d_texture = pPatch->pShader->getTexture(); - pPatch->pShader->IncRef(); - g_bScreenUpdates = false; - // the bLinkToWorld flag in AddBrushForPatch takes care of Brush_AddToList Entity_linkBrush and Brush_Build - brush_t *pb = AddBrushForPatch( pPatch, true ); - Select_Brush( pb ); - g_bScreenUpdates = true; - Sys_UpdateWindows(W_ALL); - } else - { - brush_t *pBrush = reinterpret_cast( m_PatchesHandles.GetAt(index) ); - patchMesh_t *pPatch = pBrush->pPatch; - pPatch->width = pMesh->width; - pPatch->height = pMesh->height; - pPatch->contents = pMesh->contents; - pPatch->flags = pMesh->flags; - pPatch->value = pMesh->value; - pPatch->type = pMesh->type; - memcpy( pPatch->ctrl, pMesh->ctrl, sizeof(drawVert_t)*MAX_PATCH_HEIGHT*MAX_PATCH_WIDTH ); - pPatch->bDirty = true; - } -} - -void CPlugInManager::CommitPatchHandleToEntity(int index, patchMesh_t *pMesh, char *texName, void *vpEntity) -{ - entity_t* pe = reinterpret_cast(vpEntity); - - if (PatchesMode==EAllocatedPatches) - { - patchMesh_t *pPatch = reinterpret_cast( m_PluginPatches.GetAt(index) ); - memcpy( pPatch, pMesh, sizeof( patchMesh_t ) ); - // patch texturing, if none given use current texture - if (texName) - pPatch->pShader = QERApp_Shader_ForName (texName); - else - pPatch->pShader = QERApp_Shader_ForName(g_qeglobals.d_texturewin.texdef.GetName()); - pPatch->d_texture = pPatch->pShader->getTexture(); - pPatch->pShader->IncRef(); - g_bScreenUpdates = false; - brush_t *pb = AddBrushForPatch( pPatch, false ); // false, sp have to do the brush building/entity linking ourself - Brush_AddToList (pb, &active_brushes); - Entity_LinkBrush (pe, pb); - Brush_Build( pb ); - g_bScreenUpdates = true; - Sys_UpdateWindows(W_ALL); - } else - { - brush_t *pBrush = reinterpret_cast( m_PatchesHandles.GetAt(index) ); - patchMesh_t *pPatch = pBrush->pPatch; - pPatch->width = pMesh->width; - pPatch->height = pMesh->height; - pPatch->contents = pMesh->contents; - pPatch->flags = pMesh->flags; - pPatch->value = pMesh->value; - pPatch->type = pMesh->type; - memcpy( pPatch->ctrl, pMesh->ctrl, sizeof(drawVert_t)*MAX_PATCH_HEIGHT*MAX_PATCH_WIDTH ); - pPatch->bDirty = true; - } -} - -#if 0 - -#if defined (__linux__) || defined (__APPLE__) - #include - -XVisualInfo* QEX_ChooseVisual (bool zbuffer) -{ - int attrlist_z[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 16, 0}; - int attrlist[] = { GLX_RGBA, GLX_DOUBLEBUFFER, 0}; - XVisualInfo *vi; - Display *dpy; - - dpy = GDK_DISPLAY(); - if (dpy == NULL) - Error ("OpenGL fatal error: Cannot get display.\n"); - vi = qglXChooseVisual(dpy, DefaultScreen(dpy), zbuffer ? attrlist_z : attrlist); - if (vi == NULL) - Error ("OpenGL fatal error: glXChooseVisual failed.\n"); - - return vi; -} -#endif - -#endif - -/*! -\todo FIXME TTimo broken most likely -actually .. that's not enough, you have to go down for the game pack specific? -*/ -const char* WINAPI QERApp_ProfileGetDirectory () -{ - return g_strTempPath; -} - -GtkWidget* WINAPI QERApp_GetQeGlobalsGLWidget () -{ - return g_qeglobals_gui.d_glBase; -} - -qboolean WINAPI BrushPrimitMode () -{ - return g_qeglobals.m_bBrushPrimitMode; -} - -brush_t* WINAPI QERApp_ActiveBrushes() -{ - return &active_brushes; -} - -brush_t* WINAPI QERApp_SelectedBrushes() -{ - return &selected_brushes; -} - -brush_t* WINAPI QERApp_FilteredBrushes() -{ - return &filtered_brushes; -} - -CPtrArray* WINAPI QERApp_LstSkinCache() -{ - return &g_lstSkinCache; -} - -qtexture_t** WINAPI QERApp_QTextures() -{ - return &g_qeglobals.d_qtextures; -} - -GHashTable* WINAPI QERApp_QTexmap() -{ - return g_qeglobals.d_qtexmap; -} - -// a simplified version of Texture_SetTexture -void WINAPI QERApp_Texture_SetTexture (texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef) -{ - Texture_SetTexture (texdef, brushprimit_texdef); -} - -void QERApp_LoadImage (const char *name, unsigned char **pic, int *width, int *height) -{ - g_ImageManager.LoadImage(name, pic, width, height); -} - -unsigned long QERApp_GetTickCount() -{ -#ifdef _WIN32 - return GetTickCount(); -#else - struct timeval tp; - struct timezone tzp; - static int basetime=0; - - gettimeofday(&tp, &tzp); - if (!basetime) - basetime = tp.tv_sec; - return (tp.tv_sec-basetime) + tp.tv_usec/1000; -#endif -} - -bool CSynapseClientRadiant::RequestAPI(APIDescriptor_t *pAPI) -{ - if (!strcmp(pAPI->major_name, RADIANT_MAJOR)) - { - _QERFuncTable_1* pTable= static_cast<_QERFuncTable_1*>(pAPI->mpTable); - pTable->m_pfnCreateBrush = &QERApp_CreateBrush; - pTable->m_pfnCreateBrushHandle = &QERApp_CreateBrushHandle; - pTable->m_pfnDeleteBrushHandle = &QERApp_DeleteBrushHandle; - pTable->m_pfnCommitBrushHandle = &QERApp_CommitBrushHandleToMap; - pTable->m_pfnAddFace = &QERApp_AddFace; - pTable->m_pfnAddFaceData = &QERApp_AddFaceData; - pTable->m_pfnGetFaceData = &QERApp_GetFaceData; - pTable->m_pfnGetFaceCount = &QERApp_GetFaceCount; - pTable->m_pfnSetFaceData = &QERApp_SetFaceData; - pTable->m_pfnDeleteFace = &QERApp_DeleteFace; - pTable->m_pfnTextureBrush = &QERApp_TextureBrush; - pTable->m_pfnBuildBrush = &QERApp_BuildBrush; // PGM - pTable->m_pfnSelectBrush = &QERApp_SelectBrush; // PGM - pTable->m_pfnDeselectBrush = &QERApp_DeselectBrush; // PGM - pTable->m_pfnDeselectAllBrushes = &QERApp_DeselectAllBrushes; // PGM - pTable->m_pfnDeleteSelection = &QERApp_DeleteSelection; - pTable->m_pfnGetPoints = &QERApp_GetPoints; - pTable->m_pfnSelectedBrushCount = &QERApp_SelectedBrushCount; - pTable->m_pfnAllocateSelectedBrushHandles = &QERApp_AllocateSelectedBrushHandles; - pTable->m_pfnReleaseSelectedBrushHandles = &QERApp_ReleaseSelectedBrushHandles; - pTable->m_pfnGetSelectedBrushHandle = &QERApp_GetSelectedBrushHandle; - pTable->m_pfnActiveBrushCount = &QERApp_ActiveBrushCount; - pTable->m_pfnAllocateActiveBrushHandles = &QERApp_AllocateActiveBrushHandles; - pTable->m_pfnReleaseActiveBrushHandles = &QERApp_ReleaseActiveBrushHandles; - pTable->m_pfnGetActiveBrushHandle = &QERApp_GetActiveBrushHandle; - pTable->m_pfnTextureCount = &QERApp_TextureCount; - pTable->m_pfnGetTexture = &QERApp_GetTexture; - pTable->m_pfnGetCurrentTexture = &QERApp_GetCurrentTexture; - pTable->m_pfnSetCurrentTexture = &QERApp_SetCurrentTexture; - pTable->m_pfnGetEClassCount = &QERApp_GetEClassCount; - pTable->m_pfnGetEClass = &QERApp_GetEClass; - pTable->m_pfnResetPlugins = &QERApp_ResetPlugins; - pTable->m_pfnLoadTextureRGBA = &QERApp_LoadTextureRGBA; - pTable->m_pfnGetEntityCount = &QERApp_GetEntityCount; - pTable->m_pfnGetEntityHandle = &QERApp_GetEntityHandle; - pTable->m_pfnAllocateEpair = &QERApp_AllocateEpair; - pTable->m_pfnAllocateEntityBrushHandles = &QERApp_AllocateEntityBrushHandles; - pTable->m_pfnReleaseEntityBrushHandles = &QERApp_ReleaseEntityBrushHandles; - pTable->m_pfnGetEntityBrushHandle = &QERApp_GetEntityBrushHandle; - pTable->m_pfnCreateEntityHandle = &QERApp_CreateEntityHandle; - pTable->m_pfnCommitBrushHandleToEntity = &QERApp_CommitBrushHandleToEntity; - pTable->m_pfnCommitEntityHandleToMap = &QERApp_CommitEntityHandleToMap; - pTable->m_pfnSetScreenUpdate = &QERApp_SetScreenUpdate; - pTable->m_pfnBuildBrush2 = &QERApp_BuildBrush2; - pTable->m_pfnGetDispatchParams = &QERApp_GetDispatchParams; -// pTable->m_pfnRequestInterface = &QERApp_RequestInterface; - pTable->m_pfnError = &Error; - pTable->m_pfnLoadFile = &QERApp_LoadFile; - pTable->m_pfnExpandReletivePath = &QERApp_ExpandReletivePath; - pTable->m_pfnQE_ConvertDOSToUnixName = &QE_ConvertDOSToUnixName; - pTable->m_pfnHasShader = QERApp_HasShader; - pTable->m_pfnTexture_LoadSkin = &Texture_LoadSkin; - pTable->m_pfnGetGamePath = &QERApp_GetGamePath; - pTable->m_pfnGetQERPath = &QERApp_GetQERPath; - pTable->m_pfnGetGameFile = &QERApp_GetGameFile; - pTable->m_pfnAllocateActivePatchHandles = &QERApp_AllocateActivePatchHandles; - pTable->m_pfnAllocateSelectedPatchHandles = &QERApp_AllocateSelectedPatchHandles; - pTable->m_pfnReleasePatchHandles = &QERApp_ReleasePatchHandles; - pTable->m_pfnGetPatchData = &QERApp_GetPatchData; - pTable->m_pfnGetPatchHandle = &QERApp_GetPatchHandle; - pTable->m_pfnDeletePatch = &QERApp_DeletePatch; - pTable->m_pfnCreatePatchHandle = &QERApp_CreatePatchHandle; - pTable->m_pfnCommitPatchHandleToMap = &QERApp_CommitPatchHandleToMap; - pTable->m_pfnLoadImage = &QERApp_LoadImage; - pTable->m_pfnMessageBox = >k_MessageBox; - pTable->m_pfnFileDialog = &file_dialog; - pTable->m_pfnColorDialog = &color_dialog; - pTable->m_pfnDirDialog = &dir_dialog; - pTable->m_pfnLoadBitmap = &load_plugin_bitmap; - pTable->m_pfnProfileGetDirectory = &QERApp_ProfileGetDirectory; - pTable->m_pfnProfileSaveInt = &profile_save_int; - pTable->m_pfnProfileSaveString = &profile_save_string; - pTable->m_pfnProfileLoadInt = &profile_load_int; - pTable->m_pfnProfileLoadString = &profile_load_string; - pTable->m_pfnSysUpdateWindows = &Sys_UpdateWindows; - pTable->m_pfnSysPrintf = &Sys_Printf; - pTable->m_pfnSysFPrintf = &Sys_FPrintf; - pTable->m_pfnSysBeginWait = &Sys_BeginWait; - pTable->m_pfnSysEndWait = &Sys_EndWait; - pTable->m_pfnSys_SetTitle = &Sys_SetTitle; - pTable->m_pfnSysBeep = &Sys_Beep; - pTable->m_pfnSys_Status = &Sys_Status; - pTable->m_pfnMapFree = &Map_Free; - pTable->m_pfnMapNew = &Map_New; - pTable->m_pfnMapBuildBrushData = &Map_BuildBrushData; - pTable->m_pfnMap_IsBrushFiltered = &Map_IsBrushFiltered; - pTable->m_pfnMapStartPosition = &Map_StartPosition; - pTable->m_pfnMapRegionOff = &Map_RegionOff; - pTable->m_pfnSetBuildWindingsNoTexBuild = &Brush_SetBuildWindingsNoTexBuild; - pTable->m_pfnPointFileClear = &Pointfile_Clear; - pTable->m_pfnCSG_MakeHollow = &CSG_MakeHollow; - pTable->m_pfnRegionSpawnPoint = &Region_SpawnPoint; - pTable->m_pfnQGetTickCount = &QERApp_GetTickCount; - pTable->m_pfnGetModelCache = &GetModelCache; - pTable->m_pfnGetFileTypeRegistry = &GetFileTypeRegistry; - pTable->m_pfnReadProjectKey = &QERApp_ReadProjectKey; - pTable->m_pfnGetMapName = &QERApp_GetMapName; - - return true; - } - if (!strcmp(pAPI->major_name, SCRIPLIB_MAJOR)) - { - _QERScripLibTable *pScripLibTable = static_cast<_QERScripLibTable *>(pAPI->mpTable); - pScripLibTable->m_pfnGetToken = &GetToken; - pScripLibTable->m_pfnGetTokenExtra = &GetTokenExtra; - pScripLibTable->m_pfnToken = &QERApp_Token; - pScripLibTable->m_pfnUnGetToken = &UngetToken; - pScripLibTable->m_pfnStartTokenParsing = &StartTokenParsing; - pScripLibTable->m_pfnScriptLine = &QERApp_ScriptLine; - pScripLibTable->m_pfnTokenAvailable = &TokenAvailable; - pScripLibTable->m_pfnCOM_Parse = &COM_Parse; - pScripLibTable->m_pfnGet_COM_Token = &Get_COM_Token; - - return true; - } - if (!strcmp(pAPI->major_name, BRUSH_MAJOR)) - { - _QERBrushTable *pBrushTable = static_cast<_QERBrushTable *>(pAPI->mpTable); - pBrushTable->m_pfnBP_MessageBox = &BP_MessageBox; - pBrushTable->m_pfnBrush_AddToList = &Brush_AddToList; - pBrushTable->m_pfnBrush_Build = &Brush_Build; - pBrushTable->m_pfnBrush_Create = &Brush_Create; - pBrushTable->m_pfnBrush_Free = &Brush_Free; - pBrushTable->m_pfnBrush_Rotate = &Brush_Rotate; - pBrushTable->m_pfnBrushAlloc = &Brush_Alloc; - pBrushTable->m_pfnFace_Alloc = &Face_Alloc; - pBrushTable->m_pfnHasModel = NULL;// &HasModel; - - return true; - } - if (!strcmp(pAPI->major_name, APPSHADERS_MAJOR)) - { - _QERAppShadersTable *pShadersTable = static_cast<_QERAppShadersTable*>(pAPI->mpTable); - pShadersTable->m_pfnQTextures = QERApp_QTextures; - pShadersTable->m_pfnQTexmap = QERApp_QTexmap; - pShadersTable->m_pfnQeglobalsTexturewin = QERApp_QeglobalsTexturewin; - pShadersTable->m_pfnTexture_SetTexture = QERApp_Texture_SetTexture; - pShadersTable->m_pfnTexture_ShowInuse = Texture_ShowInuse; - pShadersTable->m_pfnBuildShaderList = &BuildShaderList; - pShadersTable->m_pfnPreloadShaders = &PreloadShaders; - - return true; - } - if (!strcmp(pAPI->major_name, QGL_MAJOR)) - { - _QERQglTable *pQglTable = static_cast<_QERQglTable *>(pAPI->mpTable); - pQglTable->m_pfn_qglAlphaFunc = qglAlphaFunc; - pQglTable->m_pfn_qglBegin = qglBegin; - pQglTable->m_pfn_qglBindTexture = qglBindTexture; - pQglTable->m_pfn_qglBlendFunc = qglBlendFunc; - pQglTable->m_pfn_qglCallList = qglCallList; - pQglTable->m_pfn_qglCallLists = qglCallLists; - pQglTable->m_pfn_qglClear = qglClear; - pQglTable->m_pfn_qglClearColor = qglClearColor; - pQglTable->m_pfn_qglClearDepth = qglClearDepth; - pQglTable->m_pfn_qglColor3f = qglColor3f; - pQglTable->m_pfn_qglColor3fv = qglColor3fv; - pQglTable->m_pfn_qglColor4f = qglColor4f; - pQglTable->m_pfn_qglColor4fv = qglColor4fv; - pQglTable->m_pfn_qglColor4ubv = qglColor4ubv; - pQglTable->m_pfn_qglColorPointer = qglColorPointer; - pQglTable->m_pfn_qglCullFace = qglCullFace; - pQglTable->m_pfn_qglDepthFunc = qglDepthFunc; - pQglTable->m_pfn_qglDepthMask = qglDepthMask; - pQglTable->m_pfn_qglDisable = qglDisable; - pQglTable->m_pfn_qglDisableClientState = qglDisableClientState; - pQglTable->m_pfn_qglDeleteLists = qglDeleteLists; - pQglTable->m_pfn_qglDeleteTextures = qglDeleteTextures; - pQglTable->m_pfn_qglDrawElements = qglDrawElements; - pQglTable->m_pfn_qglEnable = qglEnable; - pQglTable->m_pfn_qglEnableClientState = qglEnableClientState; - pQglTable->m_pfn_qglEnd = qglEnd; - pQglTable->m_pfn_qglEndList = qglEndList; - pQglTable->m_pfn_qglFogf = qglFogf; - pQglTable->m_pfn_qglFogfv = qglFogfv; - pQglTable->m_pfn_qglFogi = qglFogi; - pQglTable->m_pfn_qglGenLists = qglGenLists; - pQglTable->m_pfn_qglGenTextures = qglGenTextures; - pQglTable->m_pfn_qglGetDoublev = qglGetDoublev; - pQglTable->m_pfn_qglGetIntegerv = qglGetIntegerv; - pQglTable->m_pfn_qglHint = qglHint; - pQglTable->m_pfn_qglLightfv = qglLightfv; - pQglTable->m_pfn_qglLineStipple = qglLineStipple; - pQglTable->m_pfn_qglLineWidth = qglLineWidth; - pQglTable->m_pfn_qglListBase = qglListBase; - pQglTable->m_pfn_qglLoadIdentity = qglLoadIdentity; - pQglTable->m_pfn_qglMaterialf = qglMaterialf; - pQglTable->m_pfn_qglMaterialfv = qglMaterialfv; - pQglTable->m_pfn_qglMatrixMode = qglMatrixMode; - pQglTable->m_pfn_qglMultMatrixf = qglMultMatrixf; - pQglTable->m_pfn_qglNewList = qglNewList; - pQglTable->m_pfn_qglNormal3f = qglNormal3f; - pQglTable->m_pfn_qglNormal3fv = qglNormal3fv; - pQglTable->m_pfn_qglNormalPointer = qglNormalPointer; - pQglTable->m_pfn_qglOrtho = qglOrtho; - pQglTable->m_pfn_qglPointSize = qglPointSize; - pQglTable->m_pfn_qglPolygonMode = qglPolygonMode; - pQglTable->m_pfn_qglPopAttrib = qglPopAttrib; - pQglTable->m_pfn_qglPopMatrix = qglPopMatrix; - pQglTable->m_pfn_qglPushAttrib = qglPushAttrib; - pQglTable->m_pfn_qglPushMatrix = qglPushMatrix; - pQglTable->m_pfn_qglRasterPos3fv = qglRasterPos3fv; - pQglTable->m_pfn_qglRotated = qglRotated; - pQglTable->m_pfn_qglRotatef = qglRotatef; - pQglTable->m_pfn_qglScalef = qglScalef; - pQglTable->m_pfn_qglScissor = qglScissor; - pQglTable->m_pfn_qglShadeModel = qglShadeModel; - pQglTable->m_pfn_qglTexCoord2f = qglTexCoord2f; - pQglTable->m_pfn_qglTexCoord2fv = qglTexCoord2fv; - pQglTable->m_pfn_qglTexCoordPointer = qglTexCoordPointer; - pQglTable->m_pfn_qglTexEnvf = qglTexEnvf; - pQglTable->m_pfn_qglTexGenf = qglTexGenf; - pQglTable->m_pfn_qglTexImage1D = qglTexImage1D; - pQglTable->m_pfn_qglTexImage2D = qglTexImage2D; - pQglTable->m_pfn_qglTexParameterf = qglTexParameterf; - pQglTable->m_pfn_qglTexParameterfv = qglTexParameterfv; - pQglTable->m_pfn_qglTexParameteri = qglTexParameteri; - pQglTable->m_pfn_qglTexParameteriv = qglTexParameteriv; - pQglTable->m_pfn_qglTexSubImage1D = qglTexSubImage1D; - pQglTable->m_pfn_qglTexSubImage2D = qglTexSubImage2D; - pQglTable->m_pfn_qglTranslated = qglTranslated; - pQglTable->m_pfn_qglTranslatef = qglTranslatef; - pQglTable->m_pfn_qglVertex2f = qglVertex2f; - pQglTable->m_pfn_qglVertex3f = qglVertex3f; - pQglTable->m_pfn_qglVertex3fv = qglVertex3fv; - pQglTable->m_pfn_qglVertexPointer = qglVertexPointer; - pQglTable->m_pfn_qglViewport = qglViewport; - - pQglTable->m_pfn_QE_CheckOpenGLForErrors = &QE_CheckOpenGLForErrors; - - pQglTable->m_pfn_qgluPerspective = qgluPerspective; - pQglTable->m_pfn_qgluLookAt = qgluLookAt; - pQglTable->m_pfnHookGL2DWindow = QERApp_HookGL2DWindow; - pQglTable->m_pfnUnHookGL2DWindow = QERApp_UnHookGL2DWindow; - pQglTable->m_pfnHookGL3DWindow = QERApp_HookGL3DWindow; - pQglTable->m_pfnUnHookGL3DWindow = QERApp_UnHookGL3DWindow; - - return true; - } - if (!strcmp(pAPI->major_name, DATA_MAJOR)) - { - _QERAppDataTable *pDataTable = static_cast<_QERAppDataTable *>(pAPI->mpTable); - pDataTable->m_pfnActiveBrushes = QERApp_ActiveBrushes; - pDataTable->m_pfnSelectedBrushes = QERApp_SelectedBrushes; - pDataTable->m_pfnFilteredBrushes = QERApp_FilteredBrushes; - pDataTable->m_pfnLstSkinCache = QERApp_LstSkinCache; - - return true; - } - if (!strcmp(pAPI->major_name, PATCH_MAJOR)) - { - _QERPatchTable *pPatchTable = static_cast<_QERPatchTable *>(pAPI->mpTable); - pPatchTable->m_pfnPatch_Alloc = &Patch_Alloc; - pPatchTable->m_pfnAddBrushForPatch = &AddBrushForPatch; - pPatchTable->m_pfnMakeNewPatch = &MakeNewPatch; - - return true; - } - if (!strcmp(pAPI->major_name, ECLASSMANAGER_MAJOR)) - { - _EClassManagerTable *pEClassManTable = static_cast<_EClassManagerTable *>(pAPI->mpTable); - - pEClassManTable->m_pfnEclass_InsertAlphabetized = &Eclass_InsertAlphabetized; - pEClassManTable->m_pfnGet_Eclass_E = &Get_EClass_E; - pEClassManTable->m_pfnSet_Eclass_Found = &Set_Eclass_Found; - pEClassManTable->m_pfnGet_Parsing_Single = &Get_Parsing_Single; - pEClassManTable->m_pfnEClass_Create = &EClass_Create; - pEClassManTable->m_pfnEclass_ForName = &Eclass_ForName; - - return true; - } - if (!strcmp(pAPI->major_name, SELECTEDFACE_MAJOR)) - { - _QERSelectedFaceTable *pSelectedFaceTable = static_cast<_QERSelectedFaceTable *>(pAPI->mpTable); - - pSelectedFaceTable->m_pfnGetSelectedFaceCount = &QERApp_GetSelectedFaceCount; - pSelectedFaceTable->m_pfnGetFaceBrush = &QERApp_GetSelectedFaceBrush; - pSelectedFaceTable->m_pfnGetFace = &QERApp_GetSelectedFace; - pSelectedFaceTable->m_pfnGetFaceInfo = &QERApp_GetFaceInfo; - pSelectedFaceTable->m_pfnSetFaceInfo = &QERApp_SetFaceInfo; - pSelectedFaceTable->m_pfnGetTextureNumber = &QERApp_ISelectedFace_GetTextureNumber; - pSelectedFaceTable->m_pfnGetTextureSize = &QERApp_GetTextureSize; - pSelectedFaceTable->m_pfnSelect_SetTexture = &Select_SetTexture; - return true; - } - if (!strcmp(pAPI->major_name, APPSURFACEDIALOG_MAJOR)) - { - _QERAppSurfaceTable *pSurfDialogTable = static_cast<_QERAppSurfaceTable *>(pAPI->mpTable); - pSurfDialogTable->m_pfnOnlyPatchesSelected = &OnlyPatchesSelected; - pSurfDialogTable->m_pfnAnyPatchesSelected = &AnyPatchesSelected; - pSurfDialogTable->m_pfnGetSelectedPatch = &QERApp_GetSelectedPatch; - pSurfDialogTable->m_pfnGetTwoSelectedPatch = &QERApp_GetTwoSelectedPatch; - pSurfDialogTable->m_pfnTexMatToFakeTexCoords = &TexMatToFakeTexCoords; - pSurfDialogTable->m_pfnConvertTexMatWithQTexture = &ConvertTexMatWithQTexture; - pSurfDialogTable->m_pfnFakeTexCoordsToTexMat = &FakeTexCoordsToTexMat; - pSurfDialogTable->m_pfnPatch_ResetTexturing = &Patch_ResetTexturing; - pSurfDialogTable->m_pfnPatch_FitTexturing = &Patch_FitTexturing; - pSurfDialogTable->m_pfnPatch_NaturalizeSelected = &Patch_NaturalizeSelected; - pSurfDialogTable->m_pfnPatch_GetTextureName = &Patch_GetTextureName; - pSurfDialogTable->m_pfnQE_SingleBrush = &QE_SingleBrush; - pSurfDialogTable->m_pfnIsBrushPrimitMode = &IsBrushPrimitMode; - pSurfDialogTable->m_pfnComputeAxisBase = &ComputeAxisBase; - pSurfDialogTable->m_pfnBPMatMul = &BPMatMul; - pSurfDialogTable->m_pfnEmitBrushPrimitTextureCoordinates = &EmitBrushPrimitTextureCoordinates; - pSurfDialogTable->m_pfnQeglobalsTexturewin = &QERApp_QeglobalsTexturewin; - pSurfDialogTable->m_pfnSelect_FitTexture = &Select_FitTexture; - pSurfDialogTable->m_pfnQERApp_QeglobalsSavedinfo_SIInc = &QERApp_QeglobalsSavedinfo_SIInc; - pSurfDialogTable->m_pfnQeglobalsGetGridSize = &QERApp_QeglobalsGetGridSize; - pSurfDialogTable->m_pfnFaceList_FitTexture = &SI_FaceList_FitTexture; - pSurfDialogTable->m_pfnGetMainWindow = &SI_GetMainWindow; - pSurfDialogTable->m_pfnSetWinPos_From_Prefs = &SI_SetWinPos_from_Prefs; - pSurfDialogTable->m_pfnGetSelectedFaceCountfromBrushes = &SI_GetSelectedFaceCountfromBrushes; - pSurfDialogTable->m_pfnGetSelFacesTexdef = &SI_GetSelFacesTexdef; - pSurfDialogTable->m_pfnSetTexdef_FaceList = &SI_SetTexdef_FaceList; - - return true; - } - if (!strcmp(pAPI->major_name, UNDO_MAJOR)) - { - _QERUndoTable *pUndoTable = static_cast<_QERUndoTable *>(pAPI->mpTable); - - pUndoTable->m_pfnUndo_Start = &Undo_Start; - pUndoTable->m_pfnUndo_End = &Undo_End; - pUndoTable->m_pfnUndo_AddBrush = &Undo_AddBrush; - pUndoTable->m_pfnUndo_EndBrush = &Undo_EndBrush; - pUndoTable->m_pfnUndo_AddBrushList = &Undo_AddBrushList; - pUndoTable->m_pfnUndo_EndBrushList = &Undo_EndBrushList; - pUndoTable->m_pfnUndo_AddEntity = &Undo_AddEntity; - pUndoTable->m_pfnUndo_EndEntity = &Undo_EndEntity; - pUndoTable->m_pfnUndo_Undo = &Undo_Undo; // Nurail - pUndoTable->m_pfnUndo_Redo = &Undo_Redo; // Nurail - pUndoTable->m_pfnUndo_GetUndoId = &Undo_GetUndoId; // Nurail - pUndoTable->m_pfnUndo_UndoAvailable = &Undo_UndoAvailable; // Nurail - pUndoTable->m_pfnUndo_RedoAvailable = &Undo_RedoAvailable; // Nurail - - return true; - } - if (!strcmp(pAPI->major_name, CAMERA_MAJOR)) - { - _QERCameraTable *pCameraTable = static_cast<_QERCameraTable *>(pAPI->mpTable); - - pCameraTable->m_pfnGetCamera = &QERApp_GetCamera; - pCameraTable->m_pfnSetCamera = &QERApp_SetCamera; - pCameraTable->m_pfnGetCamWindowExtents = &QERApp_GetCamWindowExtents; - - return true; - } - if (!strcmp(pAPI->major_name, UI_MAJOR)) - { - _QERUITable *pUITable = static_cast<_QERUITable *>(pAPI->mpTable); - - pUITable->m_pfnCreateGLWindow = QERApp_CreateGLWindow; - pUITable->m_pfnHookWindow = QERApp_HookWindow; - pUITable->m_pfnUnHookWindow = QERApp_UnHookWindow; - pUITable->m_pfnGetXYWndWrapper = QERApp_GetXYWndWrapper; - pUITable->m_pfnHookListener = QERApp_HookListener; - pUITable->m_pfnUnHookListener = QERApp_UnHookListener; - - return true; - } - if (!strcmp(pAPI->major_name, UIGTK_MAJOR)) - { - _QERUIGtkTable *pUIGtkTable = static_cast<_QERUIGtkTable *>(pAPI->mpTable); - - pUIGtkTable->m_pfn_GetQeglobalsGLWidget = &QERApp_GetQeGlobalsGLWidget; - pUIGtkTable->m_pfn_glwidget_new = >k_glwidget_new; - pUIGtkTable-> m_pfn_glwidget_swap_buffers = >k_glwidget_swap_buffers; - pUIGtkTable->m_pfn_glwidget_make_current = >k_glwidget_make_current; - pUIGtkTable->m_pfn_glwidget_destroy_context = >k_glwidget_destroy_context; - pUIGtkTable->m_pfn_glwidget_create_context = >k_glwidget_create_context; -#if 0 - pUIGtkTable->m_pfn_glwidget_get_context = >k_glwidget_get_context; -#endif - - return true; - } - - return false; -} - -const char* CSynapseClientRadiant::GetInfo() -{ - return "Radiant - synapse core built " __DATE__ " " RADIANT_VERSION; -} - -const char* CSynapseClientRadiant::GetName() -{ - return "core"; -} +/* +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 +*/ + +// PlugInManager.cpp: implementation of the CPlugInManager class. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#if defined (__linux__) || defined (__APPLE__) + #include + #include +#endif +#ifdef __APPLE__ + #ifdef __cplusplus + extern "C" { + #endif + #include + #ifdef __cplusplus + } + #endif +#endif +#ifdef _WIN32 + #include "objbase.h" +#endif +#include "pluginmanager.h" +#include "plugin.h" +#include "missing.h" + +#include "version.h" + +CRadiantImageManager g_ImageManager; +CRadiantPluginManager g_PluginsManager; + +_QERPlugSurfaceTable g_SurfaceTable; +_QERFileSystemTable g_FileSystemTable; +_QERShadersTable g_ShadersTable; +_QERPlugMapTable g_MapTable; +_QERPlugMapTable g_MapTable2; +_QEREntityTable g_EntityTable; +_EClassTable g_EClassDefTable; + +/*! + extending entity class formats + this approach only allows a single additional format, but it is enough for now +*/ +bool g_bHaveEClassExt = false; +_EClassTable g_EClassExtTable; + + +filetype_t g_pattern_all("all files", "*.*"); +filetype_t g_pattern_projqe4v2("qe4 v2 project files", "*.qe4"); +filetype_t g_pattern_projxml("xml project files", "*.proj"); +filetype_t g_pattern_mapq3("quake3 maps", "*.map"); +filetype_t g_pattern_mapxml("xml quake3 maps", "*.xmap"); +filetype_t g_pattern_modelmd3("md3 models", "*.md3"); +filetype_t g_pattern_modelmdc("mdc models", "*.mdc"); +filetype_t g_pattern_modelmd2("md2 models", "*.md2"); +filetype_t g_pattern_modelmdl("mdl models", "*.mdl"); +//filetype_t g_pattern_modelea3("EA3 models", "*.ea3"); +filetype_t g_pattern_soundwav("PCM sound files", "*.wav"); +filetype_t g_pattern_regq3("quake3 region", "*.reg"); + +#include + +class RadiantFileTypeRegistry : public IFileTypeRegistry +{ +public: + virtual ~RadiantFileTypeRegistry() {} + virtual void addType(const char* key, filetype_t type) + { + m_typelists[key].push_back(type); + } + virtual void getTypeList(const char* key, IFileTypeList* typelist) + { + filetype_list_t& list_ref = m_typelists[key]; + for(unsigned int i=0; iaddType(list_ref[i].getType()); + } +private: + struct filetype_copy_t + { + inline filetype_copy_t(const filetype_t other) + : m_name(other.name), m_pattern(other.pattern) + {} + inline filetype_t getType() const + { + return filetype_t(m_name.c_str(), m_pattern.c_str()); + } + private: + string_t m_name; + string_t m_pattern; + }; + typedef vector filetype_list_t; + map m_typelists; +}; + +static RadiantFileTypeRegistry g_patterns; + +IFileTypeRegistry* GetFileTypeRegistry() +{ + return &g_patterns; +} + +void InitFileTypes() +{ + //GetFileTypeRegistry()->addType("project", g_pattern_projqe4v2); + GetFileTypeRegistry()->addType("project", g_pattern_projxml); + + GetFileTypeRegistry()->addType(MAP_MAJOR, g_pattern_mapq3); + GetFileTypeRegistry()->addType(MAP_MAJOR, g_pattern_mapxml); + + GetFileTypeRegistry()->addType("region", g_pattern_regq3); +/* + GetFileTypeRegistry()->addType(MODEL_MAJOR, g_pattern_modelmd3); + GetFileTypeRegistry()->addType(MODEL_MAJOR, g_pattern_modelmd2); + GetFileTypeRegistry()->addType(MODEL_MAJOR, g_pattern_modelmdl); + GetFileTypeRegistry()->addType(MODEL_MAJOR, g_pattern_modelmdc); + //GetFileTypeRegistry()->addType(MODEL_MAJOR, g_pattern_modelea3); + */ + + GetFileTypeRegistry()->addType("sound", g_pattern_soundwav); +} + + +class CRadiantModelModuleManager : public CSynapseAPIManager +{ + typedef list APIDescriptorList; + + APIDescriptorList mAPIs; +public: + CRadiantModelModuleManager() + { + SetMatchAPI(MODEL_MAJOR, "*"); + } + virtual ~CRadiantModelModuleManager() + { + APIDescriptorList::iterator i; + for(i=mAPIs.begin(); i!=mAPIs.end(); i++) + { + delete (_QERPlugModelTable*)(*i)->mpTable; + delete *i; + *i = NULL; + } + mAPIs.clear(); + } + + // CSynapseAPIManager interface ------------------- + APIDescriptor_t* BuildRequireAPI(APIDescriptor_t* pAPI) + { + APIDescriptor_t* pRequireAPI = CSynapseAPIManager::PrepareRequireAPI(pAPI); + pRequireAPI->mpTable = new _QERPlugModelTable; + ((_QERPlugModelTable*)pRequireAPI->mpTable)->m_nSize = sizeof(_QERPlugModelTable); + pRequireAPI->mSize = sizeof(_QERPlugModelTable); + mAPIs.push_front(pRequireAPI); + return pRequireAPI; + } + + // Model Manager specific + const _QERPlugModelTable* GetModelTable(const char* version) + { + APIDescriptorList::iterator i; + for(i=mAPIs.begin(); i!=mAPIs.end(); i++) + if(strcmp(version, (*i)->minor_name) == 0) + return ((_QERPlugModelTable*)(*i)->mpTable); + return NULL; + } +}; + +CRadiantModelModuleManager g_ModelManager; + +/*! One of these exists for each unique model ID in use */ +class CModelWrapper +{ + friend class CModelManager; +public: + CModelWrapper (const char *id, const char* version) : refcount(1) + { + copy(id, version); + construct(); + } + void Refresh() + { + destroy(); + construct(); + } + ~CModelWrapper () + { + destroy(); + } +private: + void copy(const char* id, const char* version) + { + m_id = id; + m_version = version; + } + void construct() + { + m_model.pRender = NULL; + m_model.pSelect = NULL; + m_model.pEdit = NULL; + + const _QERPlugModelTable* pTable = g_ModelManager.GetModelTable(m_version.c_str()); + + if(pTable != NULL) + pTable->m_pfnLoadModel(&m_model, m_id.c_str()); + } + void destroy() + { + if (m_model.pRender) m_model.pRender->DecRef(); + if (m_model.pSelect) m_model.pSelect->DecRef(); + if (m_model.pEdit) m_model.pEdit->DecRef(); + } + string_t m_id; + string_t m_version; + entity_interfaces_t m_model; + int refcount; +}; + +/*! Creates and tracks CModelWrapper instances. +Creates a new instance for each unique ID requested, keeps count of the number of +times an ID is being referenced, and destroys any instance that is no longer in use */ +class CModelManager : public IModelCache +{ +public: + CModelManager() + { + m_ptrs = g_ptr_array_new (); + } + virtual ~CModelManager() + { + g_ptr_array_free(m_ptrs, FALSE); + } + + virtual void DeleteByID(const char *id, const char* version) + { + unsigned int i; + CModelWrapper *elem; + for(i=0; ilen; i++) + { + elem = (CModelWrapper*)m_ptrs->pdata[i]; + if(strcmp(elem->m_version.c_str(), version) == 0 + && strcmp(elem->m_id.c_str(), id) == 0 + && --elem->refcount == 0) + { + g_ptr_array_remove_index_fast(m_ptrs, i); + delete elem; + return; + } + } + } + + virtual entity_interfaces_t *GetByID(const char *id, const char* version) + { + unsigned int i; + CModelWrapper *elem; + for(i=0; ilen; i++) + { + elem = (CModelWrapper*)m_ptrs->pdata[i]; + if(strcmp(elem->m_version.c_str(), version) == 0 + && strcmp(elem->m_id.c_str(), id) == 0) + { + elem->refcount++; + return &elem->m_model; + } + } + + elem = new CModelWrapper(id, version); + g_ptr_array_add(m_ptrs, elem); + + return &elem->m_model; + } + + virtual void RefreshAll() + { + for(unsigned int i=0; ilen; ++i) + ((CModelWrapper*)m_ptrs->pdata[i])->Refresh(); + } +private: + GPtrArray *m_ptrs; // array of CModelWrapper* +}; + +CModelManager g_model_cache; + +IModelCache* GetModelCache() +{ + return &g_model_cache; +} + +// toolbar manager +class CRadiantToolbarModuleManager : public CSynapseAPIManager +{ + typedef list APIDescriptorList; + + APIDescriptorList mAPIs; +public: + CRadiantToolbarModuleManager() + { + SetMatchAPI(TOOLBAR_MAJOR, "*"); + } + virtual ~CRadiantToolbarModuleManager() + { + APIDescriptorList::iterator i; + for(i=mAPIs.begin(); i!=mAPIs.end(); i++) + { + delete (_QERPlugToolbarTable*)(*i)->mpTable; + delete *i; + *i = NULL; + } + mAPIs.clear(); + } + + // CSynapseAPIManager interface ------------------- + APIDescriptor_t* BuildRequireAPI(APIDescriptor_t* pAPI) + { + APIDescriptor_t* pRequireAPI = CSynapseAPIManager::PrepareRequireAPI(pAPI); + pRequireAPI->mpTable = new _QERPlugToolbarTable; + ((_QERPlugToolbarTable*)pRequireAPI->mpTable)->m_nSize = sizeof(_QERPlugToolbarTable); + pRequireAPI->mSize = sizeof(_QERPlugToolbarTable); + mAPIs.push_front(pRequireAPI); + return pRequireAPI; + } + + // Toolbar Manager specific + void ConstructToolbar() + { + APIDescriptorList::iterator i; + for(i=mAPIs.begin(); i!=mAPIs.end(); i++) + AddItem((_QERPlugToolbarTable*)(*i)->mpTable); + } + +private: + + void AddItem(_QERPlugToolbarTable* pTable) + { + const unsigned int count = pTable->m_pfnToolbarButtonCount(); + for(unsigned int i=0; im_pfnGetToolbarButton(i); + g_pParentWnd->AddPlugInToolbarButton(button); + } + } +}; + +CRadiantToolbarModuleManager g_ToolbarModuleManager; + + +/* image manager ---------------------------------------- */ + +CRadiantImageManager::~CRadiantImageManager() +{ + list::iterator iSlot; + for(iSlot = mSlots.begin(); iSlot != mSlots.end(); iSlot++) + { + delete *iSlot; + *iSlot = NULL; + } +} + +void CImageTableSlot::InitForFillAPITable(APIDescriptor_t *pAPI) +{ + mpAPI = pAPI; + mpTable = new _QERPlugImageTable; + mpTable->m_nSize = sizeof(_QERPlugImageTable); + mpAPI->mSize = sizeof(_QERPlugImageTable); + mpAPI->mpTable = mpTable; +} + +void CRadiantImageManager::FillAPITable(APIDescriptor_t *pAPI) +{ + CImageTableSlot *pSlot = new CImageTableSlot(); + pSlot->InitForFillAPITable(pAPI); + mSlots.push_front(pSlot); +} + +/*! + Loads an image by calling the module that handles the extension extracted from the filename + \param name The filename to load. If no extension is provided, we walk the list of supported extensions. + \param pic The returned image data + \param width The returned width of the image + \param height The returned height of the image +*/ +void CRadiantImageManager::LoadImage(const char *name, byte **pic, int *width, int *height) +{ + const char *ext = NULL; + int len; + + // extract extension + len = strlen (name); + if ((len > 5) && (name[len-4] == '.')) + ext = &name[len-3]; + + if (ext == NULL) + { + // if no extension is provided, start walking through the list + Str fullname; + list::iterator iSlot; + for(iSlot = mSlots.begin(); iSlot != mSlots.end(); iSlot++) + { + APIDescriptor_t *pAPI = (*iSlot)->GetDescriptor(); + fullname.Format("%s.%s", name, pAPI->minor_name); + (*iSlot)->GetTable()->m_pfnLoadImage(fullname.GetBuffer(), pic, width, height); + if (*pic) + return; // this was the right extension, we loaded + } + return; + } + + // start walking the interfaces + list::iterator iSlot; + for(iSlot = mSlots.begin(); iSlot != mSlots.end(); iSlot++) + { + APIDescriptor_t *pAPI = (*iSlot)->GetDescriptor(); + if (!strcmp(pAPI->minor_name, ext)) + { + (*iSlot)->GetTable()->m_pfnLoadImage(name, pic, width, height); + return; + } + } + Sys_FPrintf(SYS_WRN, "WARNING: no image table for extension '%s'\n", ext); +} + +void CRadiantImageManager::BeginExtensionsScan() +{ + mExtScanSlot = mSlots.begin(); +} + +const char* CRadiantImageManager::GetNextExtension() +{ + if (mExtScanSlot != mSlots.end()) + { + char *ext = (*mExtScanSlot)->GetDescriptor()->minor_name; + mExtScanSlot++; + return ext; + } + return NULL; +} + +/* plugin manager --------------------------------------- */ +APIDescriptor_t* CRadiantPluginManager::BuildRequireAPI(APIDescriptor_t *pAPI) +{ + CPluginSlot *pSlot = new CPluginSlot(pAPI); + mSlots.push_front(pSlot); + return pSlot->GetDescriptor(); +} + +void CRadiantPluginManager::PopulateMenu() +{ + list::iterator iPlug; + for(iPlug=mSlots.begin(); iPlug != mSlots.end(); iPlug++) + { + g_pParentWnd->AddPlugInMenuItem(*iPlug); + } +} + +void CSynapseClientRadiant::ImportMap(IDataStream *in, CPtrArray *ents, const char *type) +{ + if (strcmp(type,"map")==0) + { + g_MapTable.m_pfnMap_Read(in, ents); + } + else if (strcmp(type,"xmap")==0) + { + g_MapTable2.m_pfnMap_Read(in, ents); + } + else + Sys_FPrintf(SYS_WRN, "WARNING: no module found for map interface type '%s'\n", type); +} + +void CSynapseClientRadiant::ExportMap(CPtrArray *ents, IDataStream *out, const char *type) +{ + if (strcmp(type,"map")==0) + { + g_MapTable.m_pfnMap_Write(ents, out); + } + else if (strcmp(type,"xmap")==0) + { + g_MapTable2.m_pfnMap_Write(ents, out); + } + else + Sys_FPrintf(SYS_WRN, "WARNING: no module found for map interface type '%s'\n", type); +} + +CPluginSlot::CPluginSlot(APIDescriptor_t *pAPI) +{ + mpAPI = CSynapseAPIManager::PrepareRequireAPI(pAPI); + mpTable = new _QERPluginTable; + mpTable->m_nSize = sizeof(_QERPluginTable); + mpAPI->mSize = sizeof(_QERPluginTable); + mpAPI->mpTable = mpTable; + m_CommandStrings = NULL; + m_CommandIDs = NULL; + m_bReady = false; +} + +CPluginSlot::~CPluginSlot() +{ + delete mpAPI; + delete mpTable; + while (m_CommandStrings) + { + ::free (m_CommandStrings->data); + m_CommandStrings = g_slist_remove (m_CommandStrings, m_CommandStrings->data); + } +} + +void CPluginSlot::Init() +{ + CString str = mpTable->m_pfnQERPlug_GetCommandList(); + char cTemp[1024]; + strcpy(cTemp, str); + char* token = strtok(cTemp, ",;"); + if (token && *token == ' ') + { + while (*token == ' ') + token++; + } + while (token != NULL) + { + m_CommandStrings = g_slist_append (m_CommandStrings, strdup (token)); + token = strtok(NULL, ",;"); + } + mpTable->m_pfnQERPlug_Init(NULL, (void*)g_pParentWnd->m_pWidget); + m_bReady = true; +} + +const char* CPluginSlot::getMenuName() +{ + return mpAPI->minor_name; +} + +int CPluginSlot::getCommandCount() +{ + if (!m_bReady) + Init(); + return g_slist_length (m_CommandStrings); +} + +const char* CPluginSlot::getCommand(int n) +{ + if (!m_bReady) + Init(); + return (char*)g_slist_nth_data (m_CommandStrings, n); +} + +void CPluginSlot::addMenuID(int n) +{ + m_CommandIDs = g_slist_append (m_CommandIDs, GINT_TO_POINTER (n)); +} + +bool CPluginSlot::ownsCommandID(int n) +{ + GSList* lst; + + for (lst = m_CommandIDs; lst != NULL; lst = g_slist_next (lst)) + { + if (GPOINTER_TO_INT (lst->data) == n) + return true; + } + return false; +} + +void CPluginSlot::Dispatch(const char *p) +{ + vec3_t vMin, vMax; + if (selected_brushes.next == &selected_brushes) + { + vMin[0] = vMin[1] = vMin[2] = 0; + VectorCopy(vMin, vMax); + } else + { + Select_GetBounds (vMin, vMax); + } + mpTable->m_pfnQERPlug_Dispatch(p, vMin, vMax, QE_SingleBrush(true)); +} + +CRadiantPluginManager::~CRadiantPluginManager() +{ + list::iterator iSlot; + for(iSlot=mSlots.begin(); iSlot!=mSlots.end(); iSlot++) + { + delete *iSlot; + *iSlot = NULL; + } +} + +bool CRadiantPluginManager::Dispatch(int n, const char* p) +{ + list::iterator iPlug; + for(iPlug=mSlots.begin(); iPlug!=mSlots.end(); iPlug++) + { + CPluginSlot *pPlug = *iPlug; + if (pPlug->ownsCommandID(n)) + { + pPlug->Dispatch(p); + return true; + } + } + return false; +} + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CPlugInManager::CPlugInManager() +{ + PatchesMode = EActivePatches; + m_PlugIns = NULL; +} + +CPlugInManager::~CPlugInManager() +{ + Cleanup(); +} + +void CPlugInManager::InitForDir(const Str &dir) +{ + Str path; + + path = dir; + path += g_strPluginsDir; + // SYNAPSE + g_pParentWnd->GetSynapseServer().AddSearchPath(path); + + if (strcmp(g_strPluginsDir.GetBuffer(), g_strModulesDir.GetBuffer()) != 0) + { + path = dir; + path += g_strModulesDir; + // SYNAPSE + g_pParentWnd->GetSynapseServer().AddSearchPath(path); + } +} + +static const XMLConfigEntry_t manager_entries[] = + { + { VFS_MAJOR, SYN_REQUIRE, sizeof(g_FileSystemTable), &g_FileSystemTable }, + { SHADERS_MAJOR, SYN_REQUIRE, sizeof(g_ShadersTable), &g_ShadersTable }, + { MAP_MAJOR, SYN_REQUIRE, sizeof(g_MapTable), &g_MapTable }, + { ECLASS_MAJOR, SYN_REQUIRE, sizeof(g_EClassDefTable), &g_EClassDefTable }, + { SURFACEDIALOG_MAJOR, SYN_REQUIRE, sizeof(g_SurfaceTable), &g_SurfaceTable }, + { NULL, SYN_UNKNOWN, 0, NULL } }; + +void CPlugInManager::Init() +{ + Str synapse_config; + + Cleanup(); + + // set some globals + g_qeglobals.bBSPFrontendPlugin = false; + + InitForDir(g_strGameToolsPath); + InitForDir(g_strAppPath); + + synapse_config = g_strGameToolsPath; + synapse_config += "synapse.config"; + if (!g_pParentWnd->GetSynapseServer().Initialize(synapse_config.GetBuffer(), &Sys_Printf_VA)) + Error("Synpase server initialization failed (see console)\n"); + + // builtin modules + g_pParentWnd->GetSynapseServer().EnumerateBuiltinModule(&eclass_def); + + // APIs we provide + g_pParentWnd->GetSynapseClient().AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1)); + g_pParentWnd->GetSynapseClient().AddAPI(SCRIPLIB_MAJOR, NULL, sizeof(_QERScripLibTable)); + g_pParentWnd->GetSynapseClient().AddAPI(BRUSH_MAJOR, NULL, sizeof(_QERBrushTable)); + g_pParentWnd->GetSynapseClient().AddAPI(APPSHADERS_MAJOR, NULL, sizeof(_QERAppShadersTable)); + g_pParentWnd->GetSynapseClient().AddAPI(QGL_MAJOR, NULL, sizeof(_QERQglTable)); + g_pParentWnd->GetSynapseClient().AddAPI(DATA_MAJOR, NULL, sizeof(_QERAppDataTable)); + g_pParentWnd->GetSynapseClient().AddAPI(PATCH_MAJOR, NULL, sizeof(_QERPatchTable)); + g_pParentWnd->GetSynapseClient().AddAPI(ECLASSMANAGER_MAJOR, NULL, sizeof(_EClassManagerTable)); + g_pParentWnd->GetSynapseClient().AddAPI(SELECTEDFACE_MAJOR, NULL, sizeof(_QERSelectedFaceTable)); + g_pParentWnd->GetSynapseClient().AddAPI(APPSURFACEDIALOG_MAJOR, NULL, sizeof(_QERAppSurfaceTable)); + g_pParentWnd->GetSynapseClient().AddAPI(UNDO_MAJOR, NULL, sizeof(_QERUndoTable)); + g_pParentWnd->GetSynapseClient().AddAPI(UI_MAJOR, NULL, sizeof(_QERUITable)); + g_pParentWnd->GetSynapseClient().AddAPI(UIGTK_MAJOR, NULL, sizeof(_QERUIGtkTable)); + g_pParentWnd->GetSynapseClient().AddAPI(CAMERA_MAJOR, NULL, sizeof(_QERCameraTable)); + + // modules configured by XML + if ( !g_pParentWnd->GetSynapseClient().ConfigXML( &g_pParentWnd->GetSynapseServer(), "core", manager_entries ) ) { + Error("Synapse server initialization failed (see console)\n"); + } + + // adding a manager is a special case that ConfigXML doesn't take care of + g_pParentWnd->GetSynapseServer().SelectClientConfig( "core" ); + char *minor; + if ( !g_pParentWnd->GetSynapseServer().GetConfigForAPI( IMAGE_MAJOR, &minor ) ) { + Syn_Printf( "GetConfigForAPI '%s' failed - invalid XML config file?\n", IMAGE_MAJOR ); + Error("Synapse server initialization failed (see console)\n"); + } + g_ImageManager.SetMatchAPI( IMAGE_MAJOR, minor ); + g_pParentWnd->GetSynapseClient().AddManager( &g_ImageManager ); + + // SYN_REQUIRE entries which are still hardcoded + g_pParentWnd->GetSynapseClient().AddAPI(MAP_MAJOR, "mapxml", sizeof(g_MapTable2), SYN_REQUIRE, &g_MapTable2); + g_pParentWnd->GetSynapseClient().AddAPI(ENTITY_MAJOR, NULL, sizeof(g_EntityTable), SYN_REQUIRE, &g_EntityTable); + + // plugins: load anything that claims to be a plugin + // minor becomes some kind of matching pattern + // g_PluginsManager is an API any class, it receives several function tables as needed + // you can't do a SYN_PROVIDE with that, has to be a SYN_REQUIRE ? + g_PluginsManager.SetMatchAPI(PLUGIN_MAJOR, "*"); + g_pParentWnd->GetSynapseClient().AddManager(&g_PluginsManager); + g_pParentWnd->GetSynapseClient().AddManager(&g_ToolbarModuleManager); + g_pParentWnd->GetSynapseClient().AddManager(&g_ModelManager); + if (!g_pParentWnd->GetSynapseServer().Resolve(&g_pParentWnd->GetSynapseClient())) + { + Error("synapse initialization fail (see console)"); + } + g_PluginsManager.PopulateMenu(); + g_ToolbarModuleManager.ConstructToolbar(); + InitFileTypes(); +} + +void CPlugInManager::Shutdown() +{ + g_pParentWnd->GetSynapseServer().Shutdown(); +} + +void CPlugInManager::Cleanup() +{ + int i; + + for (i = 0; i < m_BrushHandles.GetSize(); i++) + { + brush_t *pb = reinterpret_cast(m_BrushHandles.GetAt(i)); + Brush_Free(pb); + } + m_BrushHandles.RemoveAll(); + + for (i = 0; i < m_EntityHandles.GetSize(); i++) + { + entity_t *pe = reinterpret_cast(m_EntityHandles.GetAt(i)); + Entity_Free(pe); + } + m_EntityHandles.RemoveAll(); + + // patches + // these are linked into the map + m_PatchesHandles.RemoveAll(); + // these patches were allocated by Radiant on plugin request + // if the list is not empty, it means either the plugin asked for allocation and never commited them to the map + // in which case we are supposed to delete them + // or it commited them but never called m_pfnReleasePatchHandles, in case the patches may have already been + // erased and we are trying a second time, therefore crashing .. + //++timo FIXME: for now I leave a leak warning, we'd need a table to keep track of commited patches +#ifdef _DEBUG + if (m_PluginPatches.GetSize() != 0) + Sys_Printf("WARNING: m_PluginPatches.GetSize() != 0 in CPlugInManager::Cleanup, possible leak\n"); +#endif + +/* for (i = 0; i < m_PluginPatches.GetSize(); i++) + { + patchMesh_t *pMesh = reinterpret_cast(m_PluginPatches.GetAt(i)); + if (pMesh->pSymbiot) + delete pMesh; + } + m_PluginPatches.RemoveAll(); */ +} + +void CPlugInManager::Dispatch(int n, const char * p) +{ + g_PluginsManager.Dispatch(n, p); +} + +void WINAPI QERApp_GetDispatchParams(vec3_t vMin, vec3_t vMax, bool *bSingleBrush) +{ + if (selected_brushes.next == &selected_brushes) + { + vMin[0] = vMin[1] = vMin[2] = 0; + VectorCopy(vMin, vMax); + } else + { + Select_GetBounds (vMin, vMax); + } + + if( bSingleBrush ) + *bSingleBrush = QE_SingleBrush(true); +} + + +// creates a dummy brush in the active brushes list +// FIXME : is this one really USED ? +void WINAPI QERApp_CreateBrush(vec3_t vMin, vec3_t vMax) +{ + + brush_t* pBrush = Brush_Create(vMin, vMax, &g_qeglobals.d_texturewin.texdef); + Entity_LinkBrush (world_entity, pBrush); + Brush_Build(pBrush); + Brush_AddToList (pBrush, &active_brushes); + Select_Brush(pBrush); + Sys_UpdateWindows(W_ALL); +} + +void* CPlugInManager::CreateBrushHandle() +{ + brush_t *pb = Brush_Alloc(); + pb->numberId = g_nBrushId++; + m_BrushHandles.Add(pb); + return(void*)pb; +} + +void CPlugInManager::DeleteBrushHandle(void * vp) +{ + CPtrArray* pHandles[3]; + pHandles[0] = &m_SelectedBrushHandles; + pHandles[1] = &m_ActiveBrushHandles; + pHandles[2] = &m_BrushHandles; + + for (int j = 0; j < 3; j++) + { + for (int i = 0; i < pHandles[j]->GetSize(); i++) + { + brush_t *pb = reinterpret_cast(pHandles[j]->GetAt(i)); + if (pb == reinterpret_cast(vp)) + { + if (j == 2) + { + // only remove it from the list if it is work area + // this allows the selected and active list indexes to remain constant + // throughout a session (i.e. between an allocate and release) + pHandles[j]->RemoveAt(i); + } + Brush_Free(pb); + Sys_MarkMapModified(); // PGM + return; + } + } + } +} + +void CPlugInManager::CommitBrushHandleToMap(void * vp) +{ + g_bScreenUpdates = false; + for (int i = 0; i < m_BrushHandles.GetSize(); i++) + { + brush_t *pb = reinterpret_cast(m_BrushHandles.GetAt(i)); + if (pb == reinterpret_cast(vp)) + { + m_BrushHandles.RemoveAt(i); + Entity_LinkBrush (world_entity, pb); + Brush_Build(pb); + Brush_AddToList (pb, &active_brushes); + Select_Brush(pb); + } + } + g_bScreenUpdates = true; + Sys_UpdateWindows(W_ALL); +} + +void CPlugInManager::AddFaceToBrushHandle(void * vp, vec3_t v1, vec3_t v2, vec3_t v3) +{ + brush_t *bp = FindBrushHandle(vp); + if (bp != NULL) + { + face_t *f = Face_Alloc(); + f->texdef = g_qeglobals.d_texturewin.texdef; + f->texdef.flags &= ~SURF_KEEP; + f->texdef.contents &= ~CONTENTS_KEEP; + f->next = bp->brush_faces; + bp->brush_faces = f; + VectorCopy (v1, f->planepts[0]); + VectorCopy (v2, f->planepts[1]); + VectorCopy (v3, f->planepts[2]); + } +} + +brush_t* CPlugInManager::FindBrushHandle(void * vp) +{ + CPtrArray* pHandles[4]; + pHandles[0] = &m_SelectedBrushHandles; + pHandles[1] = &m_ActiveBrushHandles; + pHandles[2] = &m_BrushHandles; + pHandles[3] = &m_EntityBrushHandles; + + for (int j = 0; j < 4; j++) + { + for (int i = 0; i < pHandles[j]->GetSize(); i++) + { + brush_t *pb = reinterpret_cast(pHandles[j]->GetAt(i)); + if (pb == reinterpret_cast(vp)) + { + return pb; + } + } + } + return NULL; +} + +patchMesh_t* CPlugInManager::FindPatchHandle(int index) +{ + switch (PatchesMode) + { + case EActivePatches: + case ESelectedPatches: + if ( index < m_PatchesHandles.GetSize() ) + { + brush_t *pb = reinterpret_cast(m_PatchesHandles.GetAt(index)); + return pb->pPatch; + } +#ifdef _DEBUG + Sys_Printf("WARNING: out of bounds in CPlugInManager::FindPatchHandle\n"); +#endif + break; + case EAllocatedPatches: + if ( index < m_PluginPatches.GetSize() ) + { + patchMesh_t *pPatch = reinterpret_cast(m_PluginPatches.GetAt(index)); + return pPatch; + } +#ifdef _DEBUG + Sys_Printf("WARNING: out of bounds in CPlugInManager::FindPatchHandle\n"); +#endif + break; + } + return NULL; +} + +void* WINAPI QERApp_CreateBrushHandle() +{ + return g_pParentWnd->GetPlugInMgr().CreateBrushHandle(); +} + +void WINAPI QERApp_DeleteBrushHandle(void* vp) +{ + g_pParentWnd->GetPlugInMgr().DeleteBrushHandle(vp); +} + +void WINAPI QERApp_CommitBrushHandleToMap(void* vp) +{ + g_pParentWnd->GetPlugInMgr().CommitBrushHandleToMap(vp); +} + +void WINAPI QERApp_AddFace(void* vp, vec3_t v1, vec3_t v2, vec3_t v3) +{ + g_pParentWnd->GetPlugInMgr().AddFaceToBrushHandle(vp, v1, v2, v3); +} + +void WINAPI QERApp_DeleteSelection() +{ + Select_Delete(); +} + +void QERApp_GetCamera( vec3_t origin, vec3_t angles ) +{ + VectorCopy( g_pParentWnd->GetCamWnd()->Camera()->origin, origin ); + VectorCopy( g_pParentWnd->GetCamWnd()->Camera()->angles, angles ); +} + +void QERApp_SetCamera( vec3_t origin, vec3_t angles ) +{ + VectorCopy( origin, g_pParentWnd->GetCamWnd()->Camera()->origin ); + VectorCopy( angles, g_pParentWnd->GetCamWnd()->Camera()->angles ); + + Sys_UpdateWindows( W_ALL ); // specify + g_pParentWnd->OnTimer(); +} + +void QERApp_GetCamWindowExtents( int *x, int *y, int *width, int *height ) +{ + GtkWidget *widget; + + if (g_pParentWnd->CurrentStyle() == MainFrame::eFloating) + widget = g_pParentWnd->GetCamWnd()->m_pParent; + else + widget = g_pParentWnd->GetCamWnd()->GetWidget(); + + get_window_pos (widget, x, y); + + *width = g_pParentWnd->GetCamWnd()->Camera()->width; + *height = g_pParentWnd->GetCamWnd()->Camera()->height; +} + +//FIXME: this AcquirePath stuff is pretty much a mess and needs cleaned up +bool g_bPlugWait = false; +bool g_bPlugOK = false; +int g_nPlugCount = 0; + +void _PlugDone(bool b, int n) +{ + g_bPlugWait = false; + g_bPlugOK = b; + g_nPlugCount = n; +} + +void WINAPI QERApp_GetPoints(int nMax, _QERPointData *pData, char* pMsg) +{ + ShowInfoDialog(pMsg); + g_bPlugWait = true; + g_bPlugOK = false; + g_nPlugCount = 0; +// g_nPlugCount=nMax-1; + AcquirePath(nMax, &_PlugDone); + + while (g_bPlugWait) + gtk_main_iteration (); + + HideInfoDialog(); + + pData->m_nCount = 0; + pData->m_pVectors = NULL; + + if (g_bPlugOK && g_nPlugCount > 0) + { + pData->m_nCount = g_nPlugCount; + pData->m_pVectors = reinterpret_cast(qmalloc(g_nPlugCount * sizeof(vec3_t))); + vec3_t *pOut = pData->m_pVectors; + for (int i = 0; i < g_nPlugCount; i++) + { + memcpy(pOut, &g_PathPoints[i],sizeof(vec3_t)); + pOut++; + } + } +} + +//#define DBG_PAPI + +void CheckTexture(face_t *f) +{ + if (!f->d_texture) + { +#ifdef DBG_PAPI + Sys_Printf("CheckTexture: requesting %s\n", f->texdef.name); +#endif + f->pShader = QERApp_Shader_ForName (f->texdef.GetName()); + f->pShader->IncRef(); + f->d_texture = f->pShader->getTexture(); + } +} + +// expects pData->m_TextureName to be relative to "textures/" +void WINAPI QERApp_AddFaceData(void* pv, _QERFaceData *pData) +{ +#ifdef DBG_PAPI + Sys_Printf("FindBrushHandle..."); +#endif + brush_t* pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); +#ifdef DBG_PAPI + Sys_Printf("Done\n"); +#endif + if (pBrush != NULL) + { + face_t *f = Face_Alloc(); + f->texdef = g_qeglobals.d_texturewin.texdef; + f->texdef.flags = pData->m_nFlags; + f->texdef.contents = pData->m_nContents; + f->texdef.value = pData->m_nValue; + f->texdef.SetName(pData->m_TextureName); + f->next = pBrush->brush_faces; + pBrush->brush_faces = f; + VectorCopy (pData->m_v1, f->planepts[0]); + VectorCopy (pData->m_v2, f->planepts[1]); + VectorCopy (pData->m_v3, f->planepts[2]); + // we might need to convert one way or the other if the input and the brush coordinates setting don't match + if (pData->m_bBPrimit == true) + { + f->brushprimit_texdef = pData->brushprimit_texdef; + if (!g_qeglobals.m_bBrushPrimitMode) + { + // before calling into the conversion, make sure we have a texture! + CheckTexture (f); +#ifdef DBG_PAPI + Sys_Printf("BrushPrimitFaceToFace..."); +#endif + + // convert BP to regular + BrushPrimitFaceToFace (f); +#ifdef DBG_PAPI + Sys_Printf("Done\n"); +#endif + } + } else + { +#ifdef _DEBUG + if (pData->m_bBPrimit != false) + Sys_FPrintf (SYS_WRN, "non-initialized pData->m_bBPrimit in QERApp_AddFaceData\n"); +#endif + f->texdef.rotate = pData->m_fRotate; + f->texdef.shift[0] = pData->m_fShift[0]; + f->texdef.shift[1] = pData->m_fShift[1]; + f->texdef.scale[0] = pData->m_fScale[0]; + f->texdef.scale[1] = pData->m_fScale[1]; + if (g_qeglobals.m_bBrushPrimitMode) + { + CheckTexture (f); +#ifdef DBG_PAPI + Sys_Printf("FaceToBrushPrimitFace..."); +#endif + + // convert regular to BP + FaceToBrushPrimitFace (f); +#ifdef DBG_PAPI + Sys_Printf("Done\n"); +#endif + } + } + Sys_MarkMapModified(); // PGM + } +} + +int WINAPI QERApp_GetFaceCount(void* pv) +{ + int n = 0; + brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); + if (pBrush != NULL) + { + for (face_t *f = pBrush->brush_faces ; f; f = f->next) + { + n++; + } + } + return n; +} + +_QERFaceData* WINAPI QERApp_GetFaceData(void* pv, int nFaceIndex) +{ + static _QERFaceData face; + int n = 0; + brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); + + if (pBrush != NULL) + { + for (face_t *f = pBrush->brush_faces ; f; f = f->next) + { + +#ifdef _DEBUG + if (!pBrush->brush_faces) + { + Sys_Printf( "Warning : pBrush->brush_faces is NULL in QERApp_GetFaceData\n" ); + return NULL; + } +#endif + + if (n == nFaceIndex) + { + face.m_nContents = f->texdef.contents; + face.m_nFlags = f->texdef.flags; + face.m_nValue = f->texdef.value; + if (g_qeglobals.m_bBrushPrimitMode) + { + //++timo NOTE: we may want to convert back to old format for backward compatibility with some old plugins? + face.m_bBPrimit = true; + face.brushprimit_texdef = f->brushprimit_texdef; + } else + { + face.m_fRotate = f->texdef.rotate; + face.m_fScale[0] = f->texdef.scale[0]; + face.m_fScale[1] = f->texdef.scale[1]; + face.m_fShift[0] = f->texdef.shift[0]; + face.m_fShift[1] = f->texdef.shift[1]; + } + strcpy(face.m_TextureName, f->texdef.GetName()); + VectorCopy(f->planepts[0], face.m_v1); + VectorCopy(f->planepts[1], face.m_v2); + VectorCopy(f->planepts[2], face.m_v3); + return &face; + } + n++; + } + } + return NULL; +} + +void WINAPI QERApp_SetFaceData(void* pv, int nFaceIndex, _QERFaceData *pData) +{ + int n = 0; + brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); + + if (pBrush != NULL) + { + for (face_t *f = pBrush->brush_faces ; f; f = f->next) + { + if (n == nFaceIndex) + { + f->texdef.flags = pData->m_nFlags; + f->texdef.contents = pData->m_nContents; + f->texdef.value = pData->m_nValue; + f->texdef.rotate = pData->m_fRotate; + f->texdef.shift[0] = pData->m_fShift[0]; + f->texdef.shift[1] = pData->m_fShift[1]; + f->texdef.scale[0] = pData->m_fScale[0]; + f->texdef.scale[1] = pData->m_fScale[1]; + //strcpy(f->texdef.name, pData->m_TextureName); + f->texdef.SetName(pData->m_TextureName); + VectorCopy(pData->m_v1, f->planepts[0]); + VectorCopy(pData->m_v2, f->planepts[1]); + VectorCopy(pData->m_v3, f->planepts[2]); + Sys_MarkMapModified(); // PGM + return; // PGM + } + n++; + } + } +} + +void WINAPI QERApp_DeleteFace(void* pv, int nFaceIndex) +{ + int n = 0; + brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); + if (pBrush != NULL) + { + face_t *pPrev = pBrush->brush_faces; + for (face_t *f = pBrush->brush_faces; f; f = f->next) + { + if (n == nFaceIndex) + { + pPrev->next = f->next; + Face_Free (f); + Sys_MarkMapModified(); // PGM + return; + } + n++; + pPrev = f; + } + } +} + +//========== +//PGM +void WINAPI QERApp_BuildBrush (void* pv) +{ + brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); + if (pBrush != NULL) + { + Brush_Build(pBrush); + Sys_UpdateWindows(W_ALL); + } +} + +//Timo : another version with bConvert flag +//++timo since 1.7 is not compatible with earlier plugin versions, remove this one and update QERApp_BuildBrush +void WINAPI QERApp_BuildBrush2 (void* pv, int bConvert) +{ + brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); + if (pBrush != NULL) + { + Brush_Build( pBrush, true, true, bConvert ); + Sys_UpdateWindows(W_ALL); + } +} + +void WINAPI QERApp_SelectBrush (void* pv) +{ + brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); + if (pBrush != NULL) + { + Select_Brush(pBrush, false); + Sys_UpdateWindows(W_ALL); + } + +} + +void WINAPI QERApp_DeselectBrush (void* pv) +{ + // FIXME - implement this! +} + +void WINAPI QERApp_ResetPlugins() +{ + g_pParentWnd->OnPluginsRefresh(); +} + +void WINAPI QERApp_DeselectAllBrushes () +{ + Select_Deselect(); + Sys_UpdateWindows(W_ALL); +} +//PGM +//========== + +void WINAPI QERApp_TextureBrush(void* pv, char* pName) +{ + brush_t *pBrush = g_pParentWnd->GetPlugInMgr().FindBrushHandle(pv); + if (pBrush != NULL) + { + for (face_t *f = pBrush->brush_faces ; f; f = f->next) + { + //strcpy(f->texdef.name, pName); + f->texdef.SetName(pName); + } + Sys_MarkMapModified(); // PGM + } +} + +int WINAPI QERApp_SelectedBrushCount() +{ + int n = 0; + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + n++; + } + return n; +} + +int WINAPI QERApp_ActiveBrushCount() +{ + int n = 0; + for (brush_t *pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next) + { + n++; + } + return n; +} + +int WINAPI QERApp_AllocateSelectedBrushHandles() +{ + int n = 0; + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + n++; + g_pParentWnd->GetPlugInMgr().GetSelectedHandles().Add(pb); + } + return n; +} + +int WINAPI QERApp_AllocateActiveBrushHandles() +{ + int n = 0; + for (brush_t *pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next) + { + n++; + g_pParentWnd->GetPlugInMgr().GetActiveHandles().Add(pb); + } + return n; +} + +void WINAPI QERApp_ReleaseSelectedBrushHandles() +{ + g_pParentWnd->GetPlugInMgr().GetSelectedHandles().RemoveAll(); + Sys_UpdateWindows(W_ALL); +} + +void WINAPI QERApp_ReleaseActiveBrushHandles() +{ + g_pParentWnd->GetPlugInMgr().GetActiveHandles().RemoveAll(); + Sys_UpdateWindows(W_ALL); +} + +void* WINAPI QERApp_GetActiveBrushHandle(int nIndex) +{ + if (nIndex < g_pParentWnd->GetPlugInMgr().GetActiveHandles().GetSize()) + { + return reinterpret_cast(g_pParentWnd->GetPlugInMgr().GetActiveHandles().GetAt(nIndex)); + } + return NULL; +} + +void* WINAPI QERApp_GetSelectedBrushHandle(int nIndex) +{ + if (nIndex < g_pParentWnd->GetPlugInMgr().GetSelectedHandles().GetSize()) + { + return reinterpret_cast(g_pParentWnd->GetPlugInMgr().GetSelectedHandles().GetAt(nIndex)); + } + return NULL; +} + +int WINAPI QERApp_TextureCount() +{ + //++timo TODO: replace by QERApp_GetActiveShaderCount and verify + Texture_StartPos (); + int x, y; + int n = 0; + while (1) + { + IShader *pShader = Texture_NextPos (&x, &y); + if (!pShader) + break; + n++; + } + return n; +} + +char* WINAPI QERApp_GetTexture(int nIndex) +{ + //++timo TODO: replace by QERApp_ActiveShader_ForIndex + // these funcs would end up being provided for backward compatibility + static char name[QER_MAX_NAMELEN]; + Texture_StartPos (); + int x, y; + int n = 0; + while (1) + { + IShader *pShader = Texture_NextPos (&x, &y); + if (!pShader) + break; + if (n == nIndex) + { + strcpy(name, pShader->getName()); + return name; + } + n++; + } + return NULL; +} + +char* WINAPI QERApp_GetCurrentTexture() +{ + static char current_tex[1024]; + strcpy(current_tex,g_qeglobals.d_texturewin.texdef.GetName()); + return current_tex; +} + +void WINAPI QERApp_SetCurrentTexture(char* strName) +{ + //++timo hu ?? tex is not initialized ?? can be any value .. + texdef_t tex; + //++timo added a brushprimit_texdef .. + // smthg to be done here + brushprimit_texdef_t brushprimit_tex; + //strcpy(tex.name, strName); + tex.SetName(strName); + Texture_SetTexture(&tex,&brushprimit_tex); +} + +int WINAPI QERApp_GetEClassCount() +{ + int n = 0; + for (eclass_t *e = eclass ; e ; e = e->next) + { + n++; + } + return n; +} + +char* WINAPI QERApp_GetEClass(int nIndex) +{ + int n = 0; + for (eclass_t *e = eclass ; e ; e = e->next) + { + if (n == nIndex) + { + return e->name; + } + } + return NULL; +} + +// v1.70 code +// world_entity holds the worldspawn and is indexed as 0 +// other entities are in the entities doubly linked list +// QERApp_GetEntityCount counts the entities like in any C array: [0..length-1] +int WINAPI QERApp_GetEntityCount() +{ + int n = 1; + for (entity_t *pe = entities.next ; pe != &entities ; pe = pe->next) + { + n++; + } + return n; +} + +// We don't store entities in CPtrArray, we need to walk the list +void* WINAPI QERApp_GetEntityHandle(int nIndex) +{ + if (nIndex==0) + // looks for the worldspawn + return static_cast(world_entity); + entity_t *pe = &entities; + int n = 0; + while ( n < nIndex ) + { + pe = pe->next; + n++; + } + return static_cast(pe); +} + +epair_t* WINAPI QERApp_AllocateEpair( char *key, char *val ) +{ + epair_t *e = (epair_t*)qmalloc (sizeof(*e)); + e->key = (char*)qmalloc(strlen(key)+1); + strcpy (e->key, key); + e->value = (char*)qmalloc(strlen(val)+1); + strcpy (e->value, val); + return e; +} + +/* +IEpair* WINAPI QERApp_IEpairForEntityHandle(void *vp) +{ + entity_t *pe = static_cast(vp); + CEpairsWrapper *pEp = new CEpairsWrapper(pe); + pEp->IncRef(); + return pEp; +} + +IEpair* WINAPI QERApp_IEpairForProjectKeys() +{ + CEpairsWrapper *pEp = new CEpairsWrapper(g_qeglobals.d_project_entity); + pEp->IncRef(); + return pEp; +} +*/ + +int WINAPI QERApp_AllocateEntityBrushHandles(void* vp) +{ + entity_t *pe = static_cast(vp); + int n = 0; + if (!pe->brushes.onext) + return 0; + g_pParentWnd->GetPlugInMgr().GetEntityBrushHandles().RemoveAll(); + for (brush_t *pb = pe->brushes.onext ; pb != &pe->brushes ; pb=pb->onext) + { + n++; + g_pParentWnd->GetPlugInMgr().GetEntityBrushHandles().Add(pb); + } + return n; +} + +void WINAPI QERApp_ReleaseEntityBrushHandles() +{ + g_pParentWnd->GetPlugInMgr().GetEntityBrushHandles().RemoveAll(); +} + +void* WINAPI QERApp_GetEntityBrushHandle(int nIndex) +{ + if (nIndex < g_pParentWnd->GetPlugInMgr().GetEntityBrushHandles().GetSize()) + return g_pParentWnd->GetPlugInMgr().GetEntityBrushHandles().GetAt(nIndex); + return NULL; +} + +// FIXME TTimo that entity handles thing sucks .. we should get rid of it .. + +void* WINAPI QERApp_CreateEntityHandle() +{ + entity_t *pe = reinterpret_cast(qmalloc(sizeof(entity_t))); + pe->brushes.onext = pe->brushes.oprev = &pe->brushes; + g_pParentWnd->GetPlugInMgr().GetEntityHandles().Add(static_cast(pe)); + return static_cast(pe); +} + +// the vpBrush needs to be in m_BrushHandles +//++timo we don't have allocation nor storage for vpEntity, no checks for this one +void WINAPI QERApp_CommitBrushHandleToEntity(void* vpBrush, void* vpEntity) +{ + g_pParentWnd->GetPlugInMgr().CommitBrushHandleToEntity(vpBrush, vpEntity); + return; +} + +const char* QERApp_ReadProjectKey(const char* key) +{ + return ValueForKey(g_qeglobals.d_project_entity, key); +} + +#ifdef USEPLUGINENTITIES + +int WINAPI QERApp_ScanFileForEClass(char *filename ) +{ + // set single class parsing + parsing_single = true; + Eclass_ScanFile(filename); + if (eclass_found) + { + eclass_e->nShowFlags |= ECLASS_PLUGINENTITY; + return 1; + } + return 0; +} +#endif // USEPLUGINENTITIES + +// the vpBrush needs to be in m_BrushHandles +//++timo add a debug check to see if we found the brush handle +// NOTE : seems there's no way to check vpEntity is valid .. this is dangerous +// links the brush to its entity, everything else is done when commiting the entity to the map +void CPlugInManager::CommitBrushHandleToEntity(void* vpBrush, void* vpEntity) +{ + brush_t* pb; + entity_t* pe; + for (int i=0 ; i < m_BrushHandles.GetSize() ; i++) + { + if (vpBrush == m_BrushHandles.GetAt(i)) + { + m_BrushHandles.RemoveAt(i); + pb = reinterpret_cast(vpBrush); + pe = reinterpret_cast(vpEntity); + Entity_LinkBrush (pe, pb); + } + } + Sys_UpdateWindows(W_ALL); +} + +// the vpEntity must be in m_EntityHandles +void WINAPI QERApp_CommitEntityHandleToMap(void* vpEntity) +{ + g_pParentWnd->GetPlugInMgr().CommitEntityHandleToMap(vpEntity); + return; +} + +int WINAPI QERApp_LoadFile( const char *pLocation, void ** buffer ) +{ + int nSize = vfsLoadFile(pLocation, buffer, 0); + return nSize; +} + +char * WINAPI QERApp_ExpandReletivePath (char *p) +{ + return ExpandReletivePath(p); +} + +qtexture_t* WINAPI QERApp_Texture_ForName (const char *name) +{ + // if the texture is not loaded yet, this call will get it loaded + // but: when we assign a GL bind number, we need to be in the g_qeglobals.d_xxxBase GL context + // the plugin may set the GL context to whatever he likes, but then load would fail + // NOTE: is context switching time-consuming? then maybe the plugin could handle the context + // switch and only add a sanity check in debug mode here + // read current context + gtk_glwidget_make_current (g_qeglobals_gui.d_glBase); + + //++timo debugging + Sys_Printf("WARNING: QERApp_Texture_ForName ... don't call that!!\n"); + qtexture_t* qtex = QERApp_Texture_ForName2( name ); + return qtex; +} + +char* QERApp_Token() +{ + return token; +} + +int QERApp_ScriptLine() +{ + return scriptline; +} + +// we save the map and return the name .. either .map or .reg to support region compiling +char* QERApp_GetMapName() +{ + static char name[PATH_MAX]; + SaveWithRegion (name); + return name; +} + +void CPlugInManager::CommitEntityHandleToMap(void* vpEntity) +{ + entity_t *pe; + eclass_t *e; + brush_t *b; + vec3_t mins,maxs; + bool has_brushes; + for (int i=0 ; i < m_EntityHandles.GetSize() ; i++ ) + { + if (vpEntity == m_EntityHandles.GetAt(i)) + { + m_EntityHandles.RemoveAt(i); + pe = reinterpret_cast(vpEntity); + // fill additional fields + // straight copy from Entity_Parse + // entity_t::origin + GetVectorForKey (pe, "origin", pe->origin); + // entity_t::eclass + if (pe->brushes.onext == &pe->brushes) + has_brushes = false; + else + has_brushes = true; + e = Eclass_ForName (ValueForKey (pe, "classname"), has_brushes); + pe->eclass = e; + // fixedsize + if (e->fixedsize) + { + if (pe->brushes.onext != &pe->brushes) + { + Sys_Printf("Warning : Fixed size entity with brushes in CPlugInManager::CommitEntityHandleToMap\n"); + } + // create a custom brush + VectorAdd(e->mins, pe->origin, mins); + VectorAdd(e->maxs, pe->origin, maxs); +/* + float a = 0; + if (e->nShowFlags & ECLASS_MISCMODEL) + { + char* p = ValueForKey(pe, "model"); + if (p != NULL && strlen(p) > 0) + { + vec3_t vMin, vMax; + a = FloatForKey (pe, "angle"); + if (GetCachedModel(pe, p, vMin, vMax)) + { + // create a custom brush + VectorAdd (pe->md3Class->mins, pe->origin, mins); + VectorAdd (pe->md3Class->maxs, pe->origin, maxs); + } + } + } +*/ + b = Brush_Create (mins, maxs, &e->texdef); +/* + if (a) + { + vec3_t vAngle; + vAngle[0] = vAngle[1] = 0; + vAngle[2] = a; + Brush_Rotate(b, vAngle, pe->origin, false); + } +*/ + b->owner = pe; + + b->onext = pe->brushes.onext; + b->oprev = &pe->brushes; + pe->brushes.onext->oprev = b; + pe->brushes.onext = b; + } else + { // brush entity + if (pe->brushes.next == &pe->brushes) + Sys_Printf ("Warning: Brush entity with no brushes in CPlugInManager::CommitEntityHandleToMap\n"); + } + + // add brushes to the active brushes list + // and build them along the way + for (b=pe->brushes.onext ; b != &pe->brushes ; b=b->onext) + { + // convert between old brushes and brush primitive + if (g_qeglobals.m_bBrushPrimitMode) + { + // we only filled the shift scale rot fields, needs conversion + Brush_Build( b, true, true, true ); + } else + { + // we are using old brushes + Brush_Build( b ); + } + b->next = active_brushes.next; + active_brushes.next->prev = b; + b->prev = &active_brushes; + active_brushes.next = b; + } + + // handle worldspawn entities + // if worldspawn has no brushes, use the new one + if (!strcmp(ValueForKey (pe, "classname"), "worldspawn")) + { + if ( world_entity && ( world_entity->brushes.onext != &world_entity->brushes ) ) + { + // worldspawn already has brushes + Sys_Printf ("Commiting worldspawn as func_group\n"); + SetKeyValue(pe, "classname", "func_group"); + // add the entity to the end of the entity list + pe->next = &entities; + pe->prev = entities.prev; + entities.prev->next = pe; + entities.prev = pe; + g_qeglobals.d_num_entities++; + } else + { + // there's a worldspawn with no brushes, we assume the map is empty + if ( world_entity ) + { + Entity_Free( world_entity ); + world_entity = pe; + } else + Sys_Printf("Warning : unexpected world_entity == NULL in CommitEntityHandleToMap\n"); + } + } else + { + // add the entity to the end of the entity list + pe->next = &entities; + pe->prev = entities.prev; + entities.prev->next = pe; + entities.prev = pe; + g_qeglobals.d_num_entities++; + } + } + } +} + +void WINAPI QERApp_SetScreenUpdate(int bScreenUpdates) +{ + g_bScreenUpdates = bScreenUpdates; +} + +texturewin_t* QERApp_QeglobalsTexturewin() +{ + return &g_qeglobals.d_texturewin; +} + +texdef_t* QERApp_QeglobalsSavedinfo_SIInc() +{ + return &g_qeglobals.d_savedinfo.m_SIIncrement; +} + +patchMesh_t* QERApp_GetSelectedPatch( ) +{ + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + return pb->pPatch; + } + } +#ifdef _DEBUG + Sys_Printf("WARNING: QERApp_GetSelectedPatchTexdef called with no patch selected\n"); +#endif + return NULL; +} + +const char* WINAPI QERApp_GetGamePath() +{ + return g_pGameDescription->mEnginePath.GetBuffer(); +} + +/*! +\todo the name of this API should prolly be changed +would also need to prompt g_strAppPath / g_strGameToolsPath independently? +*/ +// SPoG +// changed g_strGameToolsPath to g_strAppPath +const char* WINAPI QERApp_GetQERPath() +{ + return g_strAppPath.GetBuffer(); +} + +const char* WINAPI QERApp_GetGameFile() +{ + // FIXME: Arnout: temp solution, need proper 'which game is this' indicator or a different solution for plugins/modules + return g_pGameDescription->mGameFile.GetBuffer(); +} + +// patches in/out ----------------------------------- +int WINAPI QERApp_AllocateActivePatchHandles() +{ + return g_pParentWnd->GetPlugInMgr().AllocateActivePatchHandles(); +} + +// Grid Size +float QERApp_QeglobalsGetGridSize() +{ + return g_qeglobals.d_gridsize; +} + +int CPlugInManager::AllocateActivePatchHandles() +{ + int n = 0; + for (brush_t *pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + n++; + m_PatchesHandles.Add(pb); + } + } + return n; +} + +int WINAPI QERApp_AllocateSelectedPatchHandles() +{ + return g_pParentWnd->GetPlugInMgr().AllocateSelectedPatchHandles(); +} + +int CPlugInManager::AllocateSelectedPatchHandles() +{ + int n = 0; + // change mode + PatchesMode = ESelectedPatches; + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + n++; + m_PatchesHandles.Add(pb); + } + } + return n; +} + +void WINAPI QERApp_ReleasePatchHandles() +{ + g_pParentWnd->GetPlugInMgr().ReleasePatchesHandles(); +} + +patchMesh_t* WINAPI QERApp_GetPatchData(int index) +{ + static patchMesh_t patch; + patchMesh_t *pPatch = g_pParentWnd->GetPlugInMgr().FindPatchHandle(index); + if (pPatch) + { + memcpy( &patch, pPatch, sizeof(patchMesh_t) ); + return &patch; + } + return NULL; +} + +patchMesh_t* WINAPI QERApp_GetPatchHandle(int index) +{ + return g_pParentWnd->GetPlugInMgr().FindPatchHandle(index); +} + +void WINAPI QERApp_DeletePatch(int index) +{ + patchMesh_t *pPatch = g_pParentWnd->GetPlugInMgr().FindPatchHandle(index); + if (pPatch) + { + brush_t *pb = pPatch->pSymbiot; + Patch_Delete( pPatch ); + if (pb) + Brush_Free( pb ); + } +#ifdef _DEBUG + Sys_Printf("Warning: QERApp_DeletePatch: FindPatchHandle failed\n"); +#endif +} + +int WINAPI QERApp_CreatePatchHandle() +{ + return g_pParentWnd->GetPlugInMgr().CreatePatchHandle(); +} + +int CPlugInManager::CreatePatchHandle() +{ + // NOTE: we can't call the AddBrushForPatch until we have filled the patchMesh_t structure + patchMesh_t *pPatch = MakeNewPatch(); + m_PluginPatches.Add( pPatch ); + // change mode + PatchesMode = EAllocatedPatches; + return m_PluginPatches.GetSize()-1; +} + +void WINAPI QERApp_CommitPatchHandleToMap(int index, patchMesh_t *pMesh, char *texName) +{ +#ifdef DBG_PAPI + Sys_Printf ("QERApp_CommitPatchHandleToMap %i..", index); +#endif + g_pParentWnd->GetPlugInMgr().CommitPatchHandleToMap(index, pMesh, texName); +#ifdef DBG_PAPI + Sys_Printf ("Done\n"); +#endif +} + +void WINAPI QERApp_CommitPatchHandleToEntity(int index, patchMesh_t *pMesh, char *texName, void* vpEntity) +{ +#ifdef DBG_PAPI + Sys_Printf ("QERApp_CommitPatchHandleToEntity %i..", index); +#endif + g_pParentWnd->GetPlugInMgr().CommitPatchHandleToEntity(index, pMesh, texName, vpEntity); +#ifdef DBG_PAPI + Sys_Printf ("Done\n"); +#endif +} + +void CPlugInManager::CommitPatchHandleToMap(int index, patchMesh_t *pMesh, char *texName) +{ + if (PatchesMode==EAllocatedPatches) + { + patchMesh_t *pPatch = reinterpret_cast( m_PluginPatches.GetAt(index) ); + memcpy( pPatch, pMesh, sizeof( patchMesh_t ) ); + // patch texturing, if none given use current texture + if (texName) + pPatch->pShader = QERApp_Shader_ForName (texName); + else + pPatch->pShader = QERApp_Shader_ForName(g_qeglobals.d_texturewin.texdef.GetName()); + pPatch->d_texture = pPatch->pShader->getTexture(); + pPatch->pShader->IncRef(); + g_bScreenUpdates = false; + // the bLinkToWorld flag in AddBrushForPatch takes care of Brush_AddToList Entity_linkBrush and Brush_Build + brush_t *pb = AddBrushForPatch( pPatch, true ); + Select_Brush( pb ); + g_bScreenUpdates = true; + Sys_UpdateWindows(W_ALL); + } else + { + brush_t *pBrush = reinterpret_cast( m_PatchesHandles.GetAt(index) ); + patchMesh_t *pPatch = pBrush->pPatch; + pPatch->width = pMesh->width; + pPatch->height = pMesh->height; + pPatch->contents = pMesh->contents; + pPatch->flags = pMesh->flags; + pPatch->value = pMesh->value; + pPatch->type = pMesh->type; + memcpy( pPatch->ctrl, pMesh->ctrl, sizeof(drawVert_t)*MAX_PATCH_HEIGHT*MAX_PATCH_WIDTH ); + pPatch->bDirty = true; + } +} + +void CPlugInManager::CommitPatchHandleToEntity(int index, patchMesh_t *pMesh, char *texName, void *vpEntity) +{ + entity_t* pe = reinterpret_cast(vpEntity); + + if (PatchesMode==EAllocatedPatches) + { + patchMesh_t *pPatch = reinterpret_cast( m_PluginPatches.GetAt(index) ); + memcpy( pPatch, pMesh, sizeof( patchMesh_t ) ); + // patch texturing, if none given use current texture + if (texName) + pPatch->pShader = QERApp_Shader_ForName (texName); + else + pPatch->pShader = QERApp_Shader_ForName(g_qeglobals.d_texturewin.texdef.GetName()); + pPatch->d_texture = pPatch->pShader->getTexture(); + pPatch->pShader->IncRef(); + g_bScreenUpdates = false; + brush_t *pb = AddBrushForPatch( pPatch, false ); // false, sp have to do the brush building/entity linking ourself + Brush_AddToList (pb, &active_brushes); + Entity_LinkBrush (pe, pb); + Brush_Build( pb ); + g_bScreenUpdates = true; + Sys_UpdateWindows(W_ALL); + } else + { + brush_t *pBrush = reinterpret_cast( m_PatchesHandles.GetAt(index) ); + patchMesh_t *pPatch = pBrush->pPatch; + pPatch->width = pMesh->width; + pPatch->height = pMesh->height; + pPatch->contents = pMesh->contents; + pPatch->flags = pMesh->flags; + pPatch->value = pMesh->value; + pPatch->type = pMesh->type; + memcpy( pPatch->ctrl, pMesh->ctrl, sizeof(drawVert_t)*MAX_PATCH_HEIGHT*MAX_PATCH_WIDTH ); + pPatch->bDirty = true; + } +} + +#if 0 + +#if defined (__linux__) || defined (__APPLE__) + #include + +XVisualInfo* QEX_ChooseVisual (bool zbuffer) +{ + int attrlist_z[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 16, 0}; + int attrlist[] = { GLX_RGBA, GLX_DOUBLEBUFFER, 0}; + XVisualInfo *vi; + Display *dpy; + + dpy = GDK_DISPLAY(); + if (dpy == NULL) + Error ("OpenGL fatal error: Cannot get display.\n"); + vi = qglXChooseVisual(dpy, DefaultScreen(dpy), zbuffer ? attrlist_z : attrlist); + if (vi == NULL) + Error ("OpenGL fatal error: glXChooseVisual failed.\n"); + + return vi; +} +#endif + +#endif + +/*! +\todo FIXME TTimo broken most likely +actually .. that's not enough, you have to go down for the game pack specific? +*/ +const char* WINAPI QERApp_ProfileGetDirectory () +{ + return g_strTempPath; +} + +GtkWidget* WINAPI QERApp_GetQeGlobalsGLWidget () +{ + return g_qeglobals_gui.d_glBase; +} + +qboolean WINAPI BrushPrimitMode () +{ + return g_qeglobals.m_bBrushPrimitMode; +} + +brush_t* WINAPI QERApp_ActiveBrushes() +{ + return &active_brushes; +} + +brush_t* WINAPI QERApp_SelectedBrushes() +{ + return &selected_brushes; +} + +brush_t* WINAPI QERApp_FilteredBrushes() +{ + return &filtered_brushes; +} + +CPtrArray* WINAPI QERApp_LstSkinCache() +{ + return &g_lstSkinCache; +} + +qtexture_t** WINAPI QERApp_QTextures() +{ + return &g_qeglobals.d_qtextures; +} + +GHashTable* WINAPI QERApp_QTexmap() +{ + return g_qeglobals.d_qtexmap; +} + +// a simplified version of Texture_SetTexture +void WINAPI QERApp_Texture_SetTexture (texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef) +{ + Texture_SetTexture (texdef, brushprimit_texdef); +} + +void QERApp_LoadImage (const char *name, unsigned char **pic, int *width, int *height) +{ + g_ImageManager.LoadImage(name, pic, width, height); +} + +unsigned long QERApp_GetTickCount() +{ +#ifdef _WIN32 + return GetTickCount(); +#else + struct timeval tp; + struct timezone tzp; + static int basetime=0; + + gettimeofday(&tp, &tzp); + if (!basetime) + basetime = tp.tv_sec; + return (tp.tv_sec-basetime) + tp.tv_usec/1000; +#endif +} + +bool CSynapseClientRadiant::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, RADIANT_MAJOR)) + { + _QERFuncTable_1* pTable= static_cast<_QERFuncTable_1*>(pAPI->mpTable); + pTable->m_pfnCreateBrush = &QERApp_CreateBrush; + pTable->m_pfnCreateBrushHandle = &QERApp_CreateBrushHandle; + pTable->m_pfnDeleteBrushHandle = &QERApp_DeleteBrushHandle; + pTable->m_pfnCommitBrushHandle = &QERApp_CommitBrushHandleToMap; + pTable->m_pfnAddFace = &QERApp_AddFace; + pTable->m_pfnAddFaceData = &QERApp_AddFaceData; + pTable->m_pfnGetFaceData = &QERApp_GetFaceData; + pTable->m_pfnGetFaceCount = &QERApp_GetFaceCount; + pTable->m_pfnSetFaceData = &QERApp_SetFaceData; + pTable->m_pfnDeleteFace = &QERApp_DeleteFace; + pTable->m_pfnTextureBrush = &QERApp_TextureBrush; + pTable->m_pfnBuildBrush = &QERApp_BuildBrush; // PGM + pTable->m_pfnSelectBrush = &QERApp_SelectBrush; // PGM + pTable->m_pfnDeselectBrush = &QERApp_DeselectBrush; // PGM + pTable->m_pfnDeselectAllBrushes = &QERApp_DeselectAllBrushes; // PGM + pTable->m_pfnDeleteSelection = &QERApp_DeleteSelection; + pTable->m_pfnGetPoints = &QERApp_GetPoints; + pTable->m_pfnSelectedBrushCount = &QERApp_SelectedBrushCount; + pTable->m_pfnAllocateSelectedBrushHandles = &QERApp_AllocateSelectedBrushHandles; + pTable->m_pfnReleaseSelectedBrushHandles = &QERApp_ReleaseSelectedBrushHandles; + pTable->m_pfnGetSelectedBrushHandle = &QERApp_GetSelectedBrushHandle; + pTable->m_pfnActiveBrushCount = &QERApp_ActiveBrushCount; + pTable->m_pfnAllocateActiveBrushHandles = &QERApp_AllocateActiveBrushHandles; + pTable->m_pfnReleaseActiveBrushHandles = &QERApp_ReleaseActiveBrushHandles; + pTable->m_pfnGetActiveBrushHandle = &QERApp_GetActiveBrushHandle; + pTable->m_pfnTextureCount = &QERApp_TextureCount; + pTable->m_pfnGetTexture = &QERApp_GetTexture; + pTable->m_pfnGetCurrentTexture = &QERApp_GetCurrentTexture; + pTable->m_pfnSetCurrentTexture = &QERApp_SetCurrentTexture; + pTable->m_pfnGetEClassCount = &QERApp_GetEClassCount; + pTable->m_pfnGetEClass = &QERApp_GetEClass; + pTable->m_pfnResetPlugins = &QERApp_ResetPlugins; + pTable->m_pfnLoadTextureRGBA = &QERApp_LoadTextureRGBA; + pTable->m_pfnGetEntityCount = &QERApp_GetEntityCount; + pTable->m_pfnGetEntityHandle = &QERApp_GetEntityHandle; + pTable->m_pfnAllocateEpair = &QERApp_AllocateEpair; + pTable->m_pfnAllocateEntityBrushHandles = &QERApp_AllocateEntityBrushHandles; + pTable->m_pfnReleaseEntityBrushHandles = &QERApp_ReleaseEntityBrushHandles; + pTable->m_pfnGetEntityBrushHandle = &QERApp_GetEntityBrushHandle; + pTable->m_pfnCreateEntityHandle = &QERApp_CreateEntityHandle; + pTable->m_pfnCommitBrushHandleToEntity = &QERApp_CommitBrushHandleToEntity; + pTable->m_pfnCommitEntityHandleToMap = &QERApp_CommitEntityHandleToMap; + pTable->m_pfnSetScreenUpdate = &QERApp_SetScreenUpdate; + pTable->m_pfnBuildBrush2 = &QERApp_BuildBrush2; + pTable->m_pfnGetDispatchParams = &QERApp_GetDispatchParams; +// pTable->m_pfnRequestInterface = &QERApp_RequestInterface; + pTable->m_pfnError = &Error; + pTable->m_pfnLoadFile = &QERApp_LoadFile; + pTable->m_pfnExpandReletivePath = &QERApp_ExpandReletivePath; + pTable->m_pfnQE_ConvertDOSToUnixName = &QE_ConvertDOSToUnixName; + pTable->m_pfnHasShader = QERApp_HasShader; + pTable->m_pfnTexture_LoadSkin = &Texture_LoadSkin; + pTable->m_pfnGetGamePath = &QERApp_GetGamePath; + pTable->m_pfnGetQERPath = &QERApp_GetQERPath; + pTable->m_pfnGetGameFile = &QERApp_GetGameFile; + pTable->m_pfnAllocateActivePatchHandles = &QERApp_AllocateActivePatchHandles; + pTable->m_pfnAllocateSelectedPatchHandles = &QERApp_AllocateSelectedPatchHandles; + pTable->m_pfnReleasePatchHandles = &QERApp_ReleasePatchHandles; + pTable->m_pfnGetPatchData = &QERApp_GetPatchData; + pTable->m_pfnGetPatchHandle = &QERApp_GetPatchHandle; + pTable->m_pfnDeletePatch = &QERApp_DeletePatch; + pTable->m_pfnCreatePatchHandle = &QERApp_CreatePatchHandle; + pTable->m_pfnCommitPatchHandleToMap = &QERApp_CommitPatchHandleToMap; + pTable->m_pfnLoadImage = &QERApp_LoadImage; + pTable->m_pfnMessageBox = >k_MessageBox; + pTable->m_pfnFileDialog = &file_dialog; + pTable->m_pfnColorDialog = &color_dialog; + pTable->m_pfnDirDialog = &dir_dialog; + pTable->m_pfnLoadBitmap = &load_plugin_bitmap; + pTable->m_pfnProfileGetDirectory = &QERApp_ProfileGetDirectory; + pTable->m_pfnProfileSaveInt = &profile_save_int; + pTable->m_pfnProfileSaveString = &profile_save_string; + pTable->m_pfnProfileLoadInt = &profile_load_int; + pTable->m_pfnProfileLoadString = &profile_load_string; + pTable->m_pfnSysUpdateWindows = &Sys_UpdateWindows; + pTable->m_pfnSysPrintf = &Sys_Printf; + pTable->m_pfnSysFPrintf = &Sys_FPrintf; + pTable->m_pfnSysBeginWait = &Sys_BeginWait; + pTable->m_pfnSysEndWait = &Sys_EndWait; + pTable->m_pfnSys_SetTitle = &Sys_SetTitle; + pTable->m_pfnSysBeep = &Sys_Beep; + pTable->m_pfnSys_Status = &Sys_Status; + pTable->m_pfnMapFree = &Map_Free; + pTable->m_pfnMapNew = &Map_New; + pTable->m_pfnMapBuildBrushData = &Map_BuildBrushData; + pTable->m_pfnMap_IsBrushFiltered = &Map_IsBrushFiltered; + pTable->m_pfnMapStartPosition = &Map_StartPosition; + pTable->m_pfnMapRegionOff = &Map_RegionOff; + pTable->m_pfnSetBuildWindingsNoTexBuild = &Brush_SetBuildWindingsNoTexBuild; + pTable->m_pfnPointFileClear = &Pointfile_Clear; + pTable->m_pfnCSG_MakeHollow = &CSG_MakeHollow; + pTable->m_pfnRegionSpawnPoint = &Region_SpawnPoint; + pTable->m_pfnQGetTickCount = &QERApp_GetTickCount; + pTable->m_pfnGetModelCache = &GetModelCache; + pTable->m_pfnGetFileTypeRegistry = &GetFileTypeRegistry; + pTable->m_pfnReadProjectKey = &QERApp_ReadProjectKey; + pTable->m_pfnGetMapName = &QERApp_GetMapName; + + return true; + } + if (!strcmp(pAPI->major_name, SCRIPLIB_MAJOR)) + { + _QERScripLibTable *pScripLibTable = static_cast<_QERScripLibTable *>(pAPI->mpTable); + pScripLibTable->m_pfnGetToken = &GetToken; + pScripLibTable->m_pfnGetTokenExtra = &GetTokenExtra; + pScripLibTable->m_pfnToken = &QERApp_Token; + pScripLibTable->m_pfnUnGetToken = &UngetToken; + pScripLibTable->m_pfnStartTokenParsing = &StartTokenParsing; + pScripLibTable->m_pfnScriptLine = &QERApp_ScriptLine; + pScripLibTable->m_pfnTokenAvailable = &TokenAvailable; + pScripLibTable->m_pfnCOM_Parse = &COM_Parse; + pScripLibTable->m_pfnGet_COM_Token = &Get_COM_Token; + + return true; + } + if (!strcmp(pAPI->major_name, BRUSH_MAJOR)) + { + _QERBrushTable *pBrushTable = static_cast<_QERBrushTable *>(pAPI->mpTable); + pBrushTable->m_pfnBP_MessageBox = &BP_MessageBox; + pBrushTable->m_pfnBrush_AddToList = &Brush_AddToList; + pBrushTable->m_pfnBrush_Build = &Brush_Build; + pBrushTable->m_pfnBrush_Create = &Brush_Create; + pBrushTable->m_pfnBrush_Free = &Brush_Free; + pBrushTable->m_pfnBrush_Rotate = &Brush_Rotate; + pBrushTable->m_pfnBrushAlloc = &Brush_Alloc; + pBrushTable->m_pfnFace_Alloc = &Face_Alloc; + pBrushTable->m_pfnHasModel = NULL;// &HasModel; + + return true; + } + if (!strcmp(pAPI->major_name, APPSHADERS_MAJOR)) + { + _QERAppShadersTable *pShadersTable = static_cast<_QERAppShadersTable*>(pAPI->mpTable); + pShadersTable->m_pfnQTextures = QERApp_QTextures; + pShadersTable->m_pfnQTexmap = QERApp_QTexmap; + pShadersTable->m_pfnQeglobalsTexturewin = QERApp_QeglobalsTexturewin; + pShadersTable->m_pfnTexture_SetTexture = QERApp_Texture_SetTexture; + pShadersTable->m_pfnTexture_ShowInuse = Texture_ShowInuse; + pShadersTable->m_pfnBuildShaderList = &BuildShaderList; + pShadersTable->m_pfnPreloadShaders = &PreloadShaders; + + return true; + } + if (!strcmp(pAPI->major_name, QGL_MAJOR)) + { + _QERQglTable *pQglTable = static_cast<_QERQglTable *>(pAPI->mpTable); + pQglTable->m_pfn_qglAlphaFunc = qglAlphaFunc; + pQglTable->m_pfn_qglBegin = qglBegin; + pQglTable->m_pfn_qglBindTexture = qglBindTexture; + pQglTable->m_pfn_qglBlendFunc = qglBlendFunc; + pQglTable->m_pfn_qglCallList = qglCallList; + pQglTable->m_pfn_qglCallLists = qglCallLists; + pQglTable->m_pfn_qglClear = qglClear; + pQglTable->m_pfn_qglClearColor = qglClearColor; + pQglTable->m_pfn_qglClearDepth = qglClearDepth; + pQglTable->m_pfn_qglColor3f = qglColor3f; + pQglTable->m_pfn_qglColor3fv = qglColor3fv; + pQglTable->m_pfn_qglColor4f = qglColor4f; + pQglTable->m_pfn_qglColor4fv = qglColor4fv; + pQglTable->m_pfn_qglColor4ubv = qglColor4ubv; + pQglTable->m_pfn_qglColorPointer = qglColorPointer; + pQglTable->m_pfn_qglCullFace = qglCullFace; + pQglTable->m_pfn_qglDepthFunc = qglDepthFunc; + pQglTable->m_pfn_qglDepthMask = qglDepthMask; + pQglTable->m_pfn_qglDisable = qglDisable; + pQglTable->m_pfn_qglDisableClientState = qglDisableClientState; + pQglTable->m_pfn_qglDeleteLists = qglDeleteLists; + pQglTable->m_pfn_qglDeleteTextures = qglDeleteTextures; + pQglTable->m_pfn_qglDrawElements = qglDrawElements; + pQglTable->m_pfn_qglEnable = qglEnable; + pQglTable->m_pfn_qglEnableClientState = qglEnableClientState; + pQglTable->m_pfn_qglEnd = qglEnd; + pQglTable->m_pfn_qglEndList = qglEndList; + pQglTable->m_pfn_qglFogf = qglFogf; + pQglTable->m_pfn_qglFogfv = qglFogfv; + pQglTable->m_pfn_qglFogi = qglFogi; + pQglTable->m_pfn_qglGenLists = qglGenLists; + pQglTable->m_pfn_qglGenTextures = qglGenTextures; + pQglTable->m_pfn_qglGetDoublev = qglGetDoublev; + pQglTable->m_pfn_qglGetIntegerv = qglGetIntegerv; + pQglTable->m_pfn_qglHint = qglHint; + pQglTable->m_pfn_qglLightfv = qglLightfv; + pQglTable->m_pfn_qglLineStipple = qglLineStipple; + pQglTable->m_pfn_qglLineWidth = qglLineWidth; + pQglTable->m_pfn_qglListBase = qglListBase; + pQglTable->m_pfn_qglLoadIdentity = qglLoadIdentity; + pQglTable->m_pfn_qglMaterialf = qglMaterialf; + pQglTable->m_pfn_qglMaterialfv = qglMaterialfv; + pQglTable->m_pfn_qglMatrixMode = qglMatrixMode; + pQglTable->m_pfn_qglMultMatrixf = qglMultMatrixf; + pQglTable->m_pfn_qglNewList = qglNewList; + pQglTable->m_pfn_qglNormal3f = qglNormal3f; + pQglTable->m_pfn_qglNormal3fv = qglNormal3fv; + pQglTable->m_pfn_qglNormalPointer = qglNormalPointer; + pQglTable->m_pfn_qglOrtho = qglOrtho; + pQglTable->m_pfn_qglPointSize = qglPointSize; + pQglTable->m_pfn_qglPolygonMode = qglPolygonMode; + pQglTable->m_pfn_qglPopAttrib = qglPopAttrib; + pQglTable->m_pfn_qglPopMatrix = qglPopMatrix; + pQglTable->m_pfn_qglPushAttrib = qglPushAttrib; + pQglTable->m_pfn_qglPushMatrix = qglPushMatrix; + pQglTable->m_pfn_qglRasterPos3fv = qglRasterPos3fv; + pQglTable->m_pfn_qglRotated = qglRotated; + pQglTable->m_pfn_qglRotatef = qglRotatef; + pQglTable->m_pfn_qglScalef = qglScalef; + pQglTable->m_pfn_qglScissor = qglScissor; + pQglTable->m_pfn_qglShadeModel = qglShadeModel; + pQglTable->m_pfn_qglTexCoord2f = qglTexCoord2f; + pQglTable->m_pfn_qglTexCoord2fv = qglTexCoord2fv; + pQglTable->m_pfn_qglTexCoordPointer = qglTexCoordPointer; + pQglTable->m_pfn_qglTexEnvf = qglTexEnvf; + pQglTable->m_pfn_qglTexGenf = qglTexGenf; + pQglTable->m_pfn_qglTexImage1D = qglTexImage1D; + pQglTable->m_pfn_qglTexImage2D = qglTexImage2D; + pQglTable->m_pfn_qglTexParameterf = qglTexParameterf; + pQglTable->m_pfn_qglTexParameterfv = qglTexParameterfv; + pQglTable->m_pfn_qglTexParameteri = qglTexParameteri; + pQglTable->m_pfn_qglTexParameteriv = qglTexParameteriv; + pQglTable->m_pfn_qglTexSubImage1D = qglTexSubImage1D; + pQglTable->m_pfn_qglTexSubImage2D = qglTexSubImage2D; + pQglTable->m_pfn_qglTranslated = qglTranslated; + pQglTable->m_pfn_qglTranslatef = qglTranslatef; + pQglTable->m_pfn_qglVertex2f = qglVertex2f; + pQglTable->m_pfn_qglVertex3f = qglVertex3f; + pQglTable->m_pfn_qglVertex3fv = qglVertex3fv; + pQglTable->m_pfn_qglVertexPointer = qglVertexPointer; + pQglTable->m_pfn_qglViewport = qglViewport; + + pQglTable->m_pfn_QE_CheckOpenGLForErrors = &QE_CheckOpenGLForErrors; + + pQglTable->m_pfn_qgluPerspective = qgluPerspective; + pQglTable->m_pfn_qgluLookAt = qgluLookAt; + pQglTable->m_pfnHookGL2DWindow = QERApp_HookGL2DWindow; + pQglTable->m_pfnUnHookGL2DWindow = QERApp_UnHookGL2DWindow; + pQglTable->m_pfnHookGL3DWindow = QERApp_HookGL3DWindow; + pQglTable->m_pfnUnHookGL3DWindow = QERApp_UnHookGL3DWindow; + + return true; + } + if (!strcmp(pAPI->major_name, DATA_MAJOR)) + { + _QERAppDataTable *pDataTable = static_cast<_QERAppDataTable *>(pAPI->mpTable); + pDataTable->m_pfnActiveBrushes = QERApp_ActiveBrushes; + pDataTable->m_pfnSelectedBrushes = QERApp_SelectedBrushes; + pDataTable->m_pfnFilteredBrushes = QERApp_FilteredBrushes; + pDataTable->m_pfnLstSkinCache = QERApp_LstSkinCache; + + return true; + } + if (!strcmp(pAPI->major_name, PATCH_MAJOR)) + { + _QERPatchTable *pPatchTable = static_cast<_QERPatchTable *>(pAPI->mpTable); + pPatchTable->m_pfnPatch_Alloc = &Patch_Alloc; + pPatchTable->m_pfnAddBrushForPatch = &AddBrushForPatch; + pPatchTable->m_pfnMakeNewPatch = &MakeNewPatch; + + return true; + } + if (!strcmp(pAPI->major_name, ECLASSMANAGER_MAJOR)) + { + _EClassManagerTable *pEClassManTable = static_cast<_EClassManagerTable *>(pAPI->mpTable); + + pEClassManTable->m_pfnEclass_InsertAlphabetized = &Eclass_InsertAlphabetized; + pEClassManTable->m_pfnGet_Eclass_E = &Get_EClass_E; + pEClassManTable->m_pfnSet_Eclass_Found = &Set_Eclass_Found; + pEClassManTable->m_pfnGet_Parsing_Single = &Get_Parsing_Single; + pEClassManTable->m_pfnEClass_Create = &EClass_Create; + pEClassManTable->m_pfnEclass_ForName = &Eclass_ForName; + + return true; + } + if (!strcmp(pAPI->major_name, SELECTEDFACE_MAJOR)) + { + _QERSelectedFaceTable *pSelectedFaceTable = static_cast<_QERSelectedFaceTable *>(pAPI->mpTable); + + pSelectedFaceTable->m_pfnGetSelectedFaceCount = &QERApp_GetSelectedFaceCount; + pSelectedFaceTable->m_pfnGetFaceBrush = &QERApp_GetSelectedFaceBrush; + pSelectedFaceTable->m_pfnGetFace = &QERApp_GetSelectedFace; + pSelectedFaceTable->m_pfnGetFaceInfo = &QERApp_GetFaceInfo; + pSelectedFaceTable->m_pfnSetFaceInfo = &QERApp_SetFaceInfo; + pSelectedFaceTable->m_pfnGetTextureNumber = &QERApp_ISelectedFace_GetTextureNumber; + pSelectedFaceTable->m_pfnGetTextureSize = &QERApp_GetTextureSize; + pSelectedFaceTable->m_pfnSelect_SetTexture = &Select_SetTexture; + return true; + } + if (!strcmp(pAPI->major_name, APPSURFACEDIALOG_MAJOR)) + { + _QERAppSurfaceTable *pSurfDialogTable = static_cast<_QERAppSurfaceTable *>(pAPI->mpTable); + pSurfDialogTable->m_pfnOnlyPatchesSelected = &OnlyPatchesSelected; + pSurfDialogTable->m_pfnAnyPatchesSelected = &AnyPatchesSelected; + pSurfDialogTable->m_pfnGetSelectedPatch = &QERApp_GetSelectedPatch; + pSurfDialogTable->m_pfnGetTwoSelectedPatch = &QERApp_GetTwoSelectedPatch; + pSurfDialogTable->m_pfnTexMatToFakeTexCoords = &TexMatToFakeTexCoords; + pSurfDialogTable->m_pfnConvertTexMatWithQTexture = &ConvertTexMatWithQTexture; + pSurfDialogTable->m_pfnFakeTexCoordsToTexMat = &FakeTexCoordsToTexMat; + pSurfDialogTable->m_pfnPatch_ResetTexturing = &Patch_ResetTexturing; + pSurfDialogTable->m_pfnPatch_FitTexturing = &Patch_FitTexturing; + pSurfDialogTable->m_pfnPatch_NaturalizeSelected = &Patch_NaturalizeSelected; + pSurfDialogTable->m_pfnPatch_GetTextureName = &Patch_GetTextureName; + pSurfDialogTable->m_pfnQE_SingleBrush = &QE_SingleBrush; + pSurfDialogTable->m_pfnIsBrushPrimitMode = &IsBrushPrimitMode; + pSurfDialogTable->m_pfnComputeAxisBase = &ComputeAxisBase; + pSurfDialogTable->m_pfnBPMatMul = &BPMatMul; + pSurfDialogTable->m_pfnEmitBrushPrimitTextureCoordinates = &EmitBrushPrimitTextureCoordinates; + pSurfDialogTable->m_pfnQeglobalsTexturewin = &QERApp_QeglobalsTexturewin; + pSurfDialogTable->m_pfnSelect_FitTexture = &Select_FitTexture; + pSurfDialogTable->m_pfnQERApp_QeglobalsSavedinfo_SIInc = &QERApp_QeglobalsSavedinfo_SIInc; + pSurfDialogTable->m_pfnQeglobalsGetGridSize = &QERApp_QeglobalsGetGridSize; + pSurfDialogTable->m_pfnFaceList_FitTexture = &SI_FaceList_FitTexture; + pSurfDialogTable->m_pfnGetMainWindow = &SI_GetMainWindow; + pSurfDialogTable->m_pfnSetWinPos_From_Prefs = &SI_SetWinPos_from_Prefs; + pSurfDialogTable->m_pfnGetSelectedFaceCountfromBrushes = &SI_GetSelectedFaceCountfromBrushes; + pSurfDialogTable->m_pfnGetSelFacesTexdef = &SI_GetSelFacesTexdef; + pSurfDialogTable->m_pfnSetTexdef_FaceList = &SI_SetTexdef_FaceList; + + return true; + } + if (!strcmp(pAPI->major_name, UNDO_MAJOR)) + { + _QERUndoTable *pUndoTable = static_cast<_QERUndoTable *>(pAPI->mpTable); + + pUndoTable->m_pfnUndo_Start = &Undo_Start; + pUndoTable->m_pfnUndo_End = &Undo_End; + pUndoTable->m_pfnUndo_AddBrush = &Undo_AddBrush; + pUndoTable->m_pfnUndo_EndBrush = &Undo_EndBrush; + pUndoTable->m_pfnUndo_AddBrushList = &Undo_AddBrushList; + pUndoTable->m_pfnUndo_EndBrushList = &Undo_EndBrushList; + pUndoTable->m_pfnUndo_AddEntity = &Undo_AddEntity; + pUndoTable->m_pfnUndo_EndEntity = &Undo_EndEntity; + pUndoTable->m_pfnUndo_Undo = &Undo_Undo; // Nurail + pUndoTable->m_pfnUndo_Redo = &Undo_Redo; // Nurail + pUndoTable->m_pfnUndo_GetUndoId = &Undo_GetUndoId; // Nurail + pUndoTable->m_pfnUndo_UndoAvailable = &Undo_UndoAvailable; // Nurail + pUndoTable->m_pfnUndo_RedoAvailable = &Undo_RedoAvailable; // Nurail + + return true; + } + if (!strcmp(pAPI->major_name, CAMERA_MAJOR)) + { + _QERCameraTable *pCameraTable = static_cast<_QERCameraTable *>(pAPI->mpTable); + + pCameraTable->m_pfnGetCamera = &QERApp_GetCamera; + pCameraTable->m_pfnSetCamera = &QERApp_SetCamera; + pCameraTable->m_pfnGetCamWindowExtents = &QERApp_GetCamWindowExtents; + + return true; + } + if (!strcmp(pAPI->major_name, UI_MAJOR)) + { + _QERUITable *pUITable = static_cast<_QERUITable *>(pAPI->mpTable); + + pUITable->m_pfnCreateGLWindow = QERApp_CreateGLWindow; + pUITable->m_pfnHookWindow = QERApp_HookWindow; + pUITable->m_pfnUnHookWindow = QERApp_UnHookWindow; + pUITable->m_pfnGetXYWndWrapper = QERApp_GetXYWndWrapper; + pUITable->m_pfnHookListener = QERApp_HookListener; + pUITable->m_pfnUnHookListener = QERApp_UnHookListener; + + return true; + } + if (!strcmp(pAPI->major_name, UIGTK_MAJOR)) + { + _QERUIGtkTable *pUIGtkTable = static_cast<_QERUIGtkTable *>(pAPI->mpTable); + + pUIGtkTable->m_pfn_GetQeglobalsGLWidget = &QERApp_GetQeGlobalsGLWidget; + pUIGtkTable->m_pfn_glwidget_new = >k_glwidget_new; + pUIGtkTable-> m_pfn_glwidget_swap_buffers = >k_glwidget_swap_buffers; + pUIGtkTable->m_pfn_glwidget_make_current = >k_glwidget_make_current; + pUIGtkTable->m_pfn_glwidget_destroy_context = >k_glwidget_destroy_context; + pUIGtkTable->m_pfn_glwidget_create_context = >k_glwidget_create_context; +#if 0 + pUIGtkTable->m_pfn_glwidget_get_context = >k_glwidget_get_context; +#endif + + return true; + } + + return false; +} + +const char* CSynapseClientRadiant::GetInfo() +{ + return "Radiant - synapse core built " __DATE__ " " RADIANT_VERSION; +} + +const char* CSynapseClientRadiant::GetName() +{ + return "core"; +} diff --git a/radiant/pmesh.cpp b/radiant/pmesh.cpp index 1cf2067b..ca8b5297 100644 --- a/radiant/pmesh.cpp +++ b/radiant/pmesh.cpp @@ -1,6427 +1,6427 @@ -/* -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 -*/ - -// -// Preliminary patch stuff -// -// - -#include "stdafx.h" -#include "gtkmisc.h" - -#include "gtkr_list.h" - -// externs -extern void MemFile_fprintf(MemStream* pMemFile, const char* pText, ...); -extern face_t *Face_Alloc( void ); -extern void DrawAlternatePoint(vec3_t v, float scale); - -void _Write3DMatrix (FILE *f, int y, int x, int z, float *m); -void _Write3DMatrix (MemStream *f, int y, int x, int z, float *m); - -void Patch_InitialiseLODPointers(patchMesh_t *p) -{ - int i; - int rowcount = ((MAX_PATCH_WIDTH-1)/2) * MAX_PATCH_HEIGHT; - for (i=0; irowLOD[i] = NULL; - int colcount = ((MAX_PATCH_HEIGHT-1)/2) * MAX_PATCH_WIDTH; - for (i=0; icolLOD[i] = NULL; -} - -patchMesh_t* Patch_Alloc() -{ - patchMesh_t *pPatch = (patchMesh_t *)malloc(sizeof(patchMesh_t)); - pPatch->pShader = NULL; - pPatch->pSymbiot = NULL; // Hydra: added missing initialiser. - // spog - initialise patch LOD pointers - Patch_InitialiseLODPointers(pPatch); - pPatch->drawLists = NULL; - pPatch->bDirty = true; - pPatch->nListID = -1; - pPatch->bSelected = false; - pPatch->bOverlay = false; - pPatch->bDirty = true; - pPatch->LODUpdated = false; - - int i; - for (i=0; i<(((MAX_PATCH_WIDTH-1)-1)/2); i++) - pPatch->rowDirty[i] = false; - for (i=0; i<(((MAX_PATCH_HEIGHT-1)-1)/2); i++) - pPatch->colDirty[i] = false; - - return pPatch; -} - -patchMesh_t* MakeNewPatch() -{ - patchMesh_t *pm = reinterpret_cast(qmalloc(sizeof(patchMesh_t))); - - // spog - initialise patch LOD pointers - Patch_InitialiseLODPointers(pm); - pm->drawLists = NULL; - pm->bDirty = true; - - return pm; -} - -// FIXME: this needs to be dynamic -//#define MAX_PATCH_MESHES 4096 -//patchMesh_t patchMeshes[MAX_PATCH_MESHES]; -//int numPatchMeshes = 0; - -// used for a save spot -patchMesh_t patchSave; - -// Tracks the selected patch for point manipulation/update. FIXME: Need to revert back to a generalized -// brush approach -//--int g_nSelectedPatch = -1; - -// HACK: for tracking which view generated the click -// as we dont want to deselect a point on a same point -// click if it is from a different view -int g_nPatchClickedView = -1; -bool g_bSameView = false; - -//typedef enum XFormType { TRANSLATE, SCALE, ROTATE }; - - -// globals -bool g_bPatchShowBounds = true; -bool g_bPatchWireFrame = false; -bool g_bPatchWeld = true; -bool g_bPatchDrillDown = true; -//bool g_bPatchInsertMode = false; -bool g_bPatchBendMode = false; -int g_nPatchBendState = -1; -int g_nPatchInsertState = -1; -int g_nBendOriginIndex = 0; -vec3_t g_vBendOrigin; - -bool g_bPatchAxisOnRow = true; -int g_nPatchAxisIndex = 0; -bool g_bPatchLowerEdge = true; - -vec3_t g_vCycleCapNormal; -// cycles when we use Patch_CycleCapSelected -VIEWTYPE g_nCycleCapIndex = XY; - -// BEND states -enum -{ - BEND_SELECT_ROTATION = 0, - BEND_SELECT_ORIGIN, - BEND_SELECT_EDGE, - BEND_BENDIT, - BEND_STATE_COUNT -}; - -const char *g_pBendStateMsg[] = -{ - "Use TAB to cycle through available bend axis. Press ENTER when the desired one is highlighted.", - "Use TAB to cycle through available rotation axis. This will LOCK around that point. You may also use Shift + Middle Click to select an arbitrary point. Press ENTER when the desired one is highlighted", - "Use TAB to choose which side to bend. Press ENTER when the desired one is highlighted.", - "Use the MOUSE to bend the patch. It uses the same ui rules as Free Rotation. Press ENTER to accept the bend, press ESC to abandon it and exit Bend mode", - "" -}; - -// INSERT states -enum -{ - INSERT_SELECT_EDGE = 0, - INSERT_STATE_COUNT -}; - -const char* g_pInsertStateMsg[] = -{ - "Use TAB to cycle through available rows/columns for insertion/deletion. Press INS to insert at the highlight, DEL to remove the pair" -}; - - -float *g_InversePoints[1024]; - -const float fFullBright = 1.0; -const float fLowerLimit = .50; -const float fDec = .05f; -void _SetColor(face_t* f, float fColor[3]) -{ - return; - fColor[0] = f->d_color[0]; - fColor[1] = f->d_color[1]; - fColor[2] = f->d_color[2]; - qglColor3fv(fColor); -} - - -void _DecColor(float fColor[3]) -{ - return; - fColor[0] -= fDec; - fColor[1] -= fDec ; - fColor[2] -= fDec; - for (int i = 0; i < 3; i++) - { - if (fColor[i] <= fLowerLimit) - { - fColor[0] = fFullBright; - fColor[1] = fFullBright; - fColor[2] = fFullBright; - break; - } - } - qglColor3fv(fColor); -} - -vec_t __VectorNormalize (vec3_t in, vec3_t out) -{ - vec_t length, ilength; - - length = sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]); - if (length == 0) - { - VectorClear (out); - return 0; - } - - ilength = 1.0/length; - out[0] = in[0]*ilength; - out[1] = in[1]*ilength; - out[2] = in[2]*ilength; - - return length; -} - - -void Patch_SetType(patchMesh_t *p, int nType) -{ - p->type = (p->type & PATCH_STYLEMASK) | nType; -} - -void Patch_SetStyle(patchMesh_t *p, int nStyle) -{ - p->type = (p->type & PATCH_TYPEMASK) | nStyle; -} - -/* -================== -Patch_MemorySize -================== -*/ -int Patch_MemorySize(patchMesh_t *p) -{ - // return _msize(p); - return 0; -} - - -/* -=============== -InterpolateInteriorPoints -=============== -*/ -void InterpolateInteriorPoints( patchMesh_t *p ) -{ - int i, j, k; - int next, prev; - - for ( i = 0 ; i < p->width ; i += 2 ) - { - - next = ( i == p->width - 1 ) ? 1 : ( i + 1 ) % p->width; - prev = ( i == 0 ) ? p->width - 2 : i - 1; - -#if 0 - if ( i == 0 ) - { - next = ( i + 1 ) % p->width; - prev = p->width - 2; // joined wrap case - } - else if ( i == p->width - 1 ) - { - next = 1; - prev = i - 1; - } - else - { - next = ( i + 1 ) % p->width; - prev = i - 1; - } -#endif - - for ( j = 0 ; j < p->height ; j++ ) - { - for ( k = 0 ; k < 3 ; k++ ) - { - p->ctrl[i][j].xyz[k] = ( p->ctrl[next][j].xyz[k] + p->ctrl[prev][j].xyz[k] ) * 0.5; - } - } - } -} - -/* -================= -MakeMeshNormals - -================= -*/ -int neighbors[8][2] = { - {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1} -}; - -void Patch_MeshNormals(patchMesh_t *in ) -{ - int i, j, k, dist; - vec3_t normal; - vec3_t sum; - int count; - vec3_t base; - vec3_t delta; - int x, y; - drawVert_t *dv; - vec3_t around[8], temp; - qboolean good[8]; - qboolean wrapWidth, wrapHeight; - float len; - - wrapWidth = false; - for ( i = 0 ; i < in->height ; i++ ) - { - - VectorSubtract( in->ctrl[0][i].xyz, - in->ctrl[in->width-1][i].xyz, delta ); - len = VectorLength( delta ); - if ( len > 1.0 ) - { - break; - } - } - if ( i == in->height ) - { - wrapWidth = true; - } - - wrapHeight = false; - for ( i = 0 ; i < in->width ; i++ ) - { - VectorSubtract( in->ctrl[i][0].xyz, - in->ctrl[i][in->height-1].xyz, delta ); - len = VectorLength( delta ); - if ( len > 1.0 ) - { - break; - } - } - if ( i == in->width) - { - wrapHeight = true; - } - - - for ( i = 0 ; i < in->width ; i++ ) - { - for ( j = 0 ; j < in->height ; j++ ) - { - count = 0; - //--dv = reinterpret_cast(in.ctrl[j*in.width+i]); - dv = &in->ctrl[i][j]; - VectorCopy( dv->xyz, base ); - for ( k = 0 ; k < 8 ; k++ ) - { - VectorClear( around[k] ); - good[k] = false; - - for ( dist = 1 ; dist <= 3 ; dist++ ) - { - x = i + neighbors[k][0] * dist; - y = j + neighbors[k][1] * dist; - if ( wrapWidth ) - { - if ( x < 0 ) - { - x = in->width - 1 + x; - } - else if ( x >= in->width ) - { - x = 1 + x - in->width; - } - } - if ( wrapHeight ) - { - if ( y < 0 ) - { - y = in->height - 1 + y; - } - else if ( y >= in->height ) - { - y = 1 + y - in->height; - } - } - - if ( x < 0 || x >= in->width || y < 0 || y >= in->height ) - { - break; // edge of patch - } - //--VectorSubtract( in.ctrl[y*in.width+x]->xyz, base, temp ); - VectorSubtract( in->ctrl[x][y].xyz, base, temp ); - if ( __VectorNormalize( temp, temp ) == 0 ) - { - continue; // degenerate edge, get more dist - } - else - { - good[k] = true; - VectorCopy( temp, around[k] ); - break; // good edge - } - } - } - - VectorClear( sum ); - for ( k = 0 ; k < 8 ; k++ ) - { - if ( !good[k] || !good[(k+1)&7] ) - { - continue; // didn't get two points - } - CrossProduct( around[(k+1)&7], around[k], normal ); - if ( __VectorNormalize( normal, normal ) == 0 ) - { - continue; - } - VectorAdd( normal, sum, sum ); - count++; - } - if ( count == 0 ) - { - //printf("bad normal\n"); - count = 1; - //continue; - } - __VectorNormalize( sum, dv->normal ); - } - } -} - - - - -/* -================== -Patch_CalcBounds -================== -*/ -void Patch_CalcBounds(patchMesh_t *p, vec3_t& vMin, vec3_t& vMax) -{ - vMin[0] = vMin[1] = vMin[2] = 99999; - vMax[0] = vMax[1] = vMax[2] = -99999; - - p->bDirty = true; - for (int w = 0; w < p->width; w++) - { - for (int h = 0; h < p->height; h++) - { - for (int j = 0; j < 3; j++) - { - float f = p->ctrl[w][h].xyz[j]; - if (f < vMin[j]) - vMin[j] = f; - if (f > vMax[j]) - vMax[j] = f; - } - } - } -} - -/* -================== -Brush_RebuildBrush -================== -*/ -void Brush_RebuildBrush(brush_t *b, vec3_t vMins, vec3_t vMaxs) -{ - // - // Total hack job - // Rebuilds a brush - int i, j; - face_t *f, *next; - vec3_t pts[4][2]; - texdef_t texdef; - // free faces - - for (j = 0; j < 3; j++) - { - if ((int)vMins[j] == (int)vMaxs[j]) - { - vMins[j] -= 4; - vMaxs[j] += 4; - } - } - - - for (f=b->brush_faces ; f ; f=next) - { - next = f->next; - if (f) - texdef = f->texdef; - Face_Free( f ); - } - - b->brush_faces = NULL; - - // left the last face so we can use its texdef - - for (i=0 ; i<3 ; i++) - if (vMaxs[i] < vMins[i]) - Error ("Brush_RebuildBrush: backwards"); - - pts[0][0][0] = vMins[0]; - pts[0][0][1] = vMins[1]; - - pts[1][0][0] = vMins[0]; - pts[1][0][1] = vMaxs[1]; - - pts[2][0][0] = vMaxs[0]; - pts[2][0][1] = vMaxs[1]; - - pts[3][0][0] = vMaxs[0]; - pts[3][0][1] = vMins[1]; - - for (i=0 ; i<4 ; i++) - { - pts[i][0][2] = vMins[2]; - pts[i][1][0] = pts[i][0][0]; - pts[i][1][1] = pts[i][0][1]; - pts[i][1][2] = vMaxs[2]; - } - - for (i=0 ; i<4 ; i++) - { - f = Face_Alloc(); - f->texdef = texdef; - f->texdef.flags &= ~SURF_KEEP; - f->texdef.contents &= ~CONTENTS_KEEP; -// f->texdef.flags |= SURF_PATCH; - f->next = b->brush_faces; - b->brush_faces = f; - j = (i+1)%4; - - VectorCopy (pts[j][1], f->planepts[0]); - VectorCopy (pts[i][1], f->planepts[1]); - VectorCopy (pts[i][0], f->planepts[2]); - } - - f = Face_Alloc(); - f->texdef = texdef; - f->texdef.flags &= ~SURF_KEEP; - f->texdef.contents &= ~CONTENTS_KEEP; -// f->texdef.flags |= SURF_PATCH; - f->next = b->brush_faces; - b->brush_faces = f; - - VectorCopy (pts[0][1], f->planepts[0]); - VectorCopy (pts[1][1], f->planepts[1]); - VectorCopy (pts[2][1], f->planepts[2]); - - f = Face_Alloc(); - f->texdef = texdef; - f->texdef.flags &= ~SURF_KEEP; - f->texdef.contents &= ~CONTENTS_KEEP; -// f->texdef.flags |= SURF_PATCH; - f->next = b->brush_faces; - b->brush_faces = f; - - VectorCopy (pts[2][0], f->planepts[0]); - VectorCopy (pts[1][0], f->planepts[1]); - VectorCopy (pts[0][0], f->planepts[2]); - - Brush_Build(b); -} - -void WINAPI Patch_Rebuild(patchMesh_t *p) -{ - vec3_t vMin, vMax; - Patch_CalcBounds(p, vMin, vMax); - Brush_RebuildBrush(p->pSymbiot, vMin, vMax); - p->bDirty = true; -} - -/* -================== -AddBrushForPatch -================== - adds a patch brush and ties it to this patch id -*/ -brush_t* AddBrushForPatch(patchMesh_t *pm, bool bLinkToWorld ) -{ - // find the farthest points in x,y,z - vec3_t vMin, vMax; - Patch_CalcBounds(pm, vMin, vMax); - - for (int j = 0; j < 3; j++) - { - if (vMin[j] == vMax[j]) - { - vMin[j] -= 4; - vMax[j] += 4; - } - } - - brush_t *b = Brush_Create(vMin, vMax, &g_qeglobals.d_texturewin.texdef); - - // FIXME: this entire type of linkage needs to be fixed - b->patchBrush = true; - b->pPatch = pm; - pm->pSymbiot = b; - pm->bSelected = false; - pm->bOverlay = false; - pm->bDirty = true; - pm->nListID = -1; - - if (bLinkToWorld) - { - Brush_AddToList (b, &active_brushes); - Entity_LinkBrush (world_entity, b); - Brush_Build(b); - } - - return b; -} - -void Patch_SetPointIntensities(int n) -{ -#if 0 - patchMesh_t *p = patchMeshes[n]; - for (int i = 0; i < p->width; i++) - { - for (int j = 0; j < p->height; j++) - { - - } - } -#endif -} - -// very approximate widths and heights - -/* -================== -Patch_Width -================== -*/ -float Patch_Width(patchMesh_t *p) -{ - float f = 0; - for (int i = 0; i < p->width-1; i++) - { - vec3_t vTemp; - VectorSubtract(p->ctrl[i][0].xyz, p->ctrl[i+1][0].xyz, vTemp); - f += VectorLength(vTemp); - } - return f; -} - -float Patch_WidthDistanceTo(patchMesh_t *p, int j) -{ - float f = 0; - for (int i = 0; i < j; i++) - { - vec3_t vTemp; - VectorSubtract(p->ctrl[i][0].xyz, p->ctrl[i+1][0].xyz, vTemp); - f += VectorLength(vTemp); - } - return f; -} - - - -/* -================== -Patch_Height -================== -*/ -float Patch_Height(patchMesh_t *p) -{ - float f = 0; - for (int i = 0; i < p->height-1; i++) - { - vec3_t vTemp; - VectorSubtract(p->ctrl[0][i].xyz, p->ctrl[0][i+1].xyz, vTemp); - f += VectorLength(vTemp); - } - return f; -} - -float Patch_HeightDistanceTo(patchMesh_t *p, int j) -{ - float f = 0; - for (int i = p->height-1; i > j; i--) - { - vec3_t vTemp; - VectorSubtract(p->ctrl[0][i].xyz, p->ctrl[0][i-1].xyz, vTemp); // reverse order for T coords - f += VectorLength(vTemp); - } - return f; -} - - - -/* -================== -Patch_Naturalize -================== -texture = TotalTexture * LengthToThisControlPoint / TotalControlPointLength - -dist( this control point to first control point ) / dist ( last control pt to first) -*/ -void WINAPI Patch_Naturalize(patchMesh_t *p) -{ - int nWidth = (int)(p->d_texture->width * g_pGameDescription->mTextureDefaultScale); - int nHeight = (int)(p->d_texture->height * g_pGameDescription->mTextureDefaultScale); - float fPWidth = Patch_Width(p); - float fPHeight = Patch_Height(p); - float xAccum = 0.0f; - - for ( int i = 0; i < p->width ; i++ ) - { - float yAccum = 0.0f; - for ( int j = p->height-1; j >= 0 ; j-- ) - { - p->ctrl[i][j].st[0] = (fPWidth / nWidth) * xAccum / fPWidth; - p->ctrl[i][j].st[1] = (fPHeight / nHeight) * yAccum / fPHeight; - yAccum = Patch_HeightDistanceTo(p,j-1); - //p->ctrl[i][j][3] = (fPWidth / nWidth) * (float)i / (p->width - 1); - //p->ctrl[i][j][4] = (fPHeight/ nHeight) * (float)j / (p->height - 1); - } - xAccum = Patch_WidthDistanceTo(p,i+1); - } - p->bDirty = true; -} - -/* - if (bIBevel) - { - VectorCopy(p->ctrl[1][0], p->ctrl[1][1]); - } - - if (bIEndcap) - { - VectorCopy(p->ctrl[3][0], p->ctrl[4][1]); - VectorCopy(p->ctrl[2][0], p->ctrl[3][1]); - VectorCopy(p->ctrl[2][0], p->ctrl[2][1]); - VectorCopy(p->ctrl[2][0], p->ctrl[1][1]); - VectorCopy(p->ctrl[1][0], p->ctrl[0][1]); - VectorCopy(p->ctrl[1][0], p->ctrl[0][2]); - VectorCopy(p->ctrl[1][0], p->ctrl[1][2]); - VectorCopy(p->ctrl[2][0], p->ctrl[2][2]); - VectorCopy(p->ctrl[3][0], p->ctrl[3][2]); - VectorCopy(p->ctrl[3][0], p->ctrl[4][2]); - } -*/ - -int Index3By[][2] = -{ - {0,0}, - {1,0}, - {2,0}, - {2,1}, - {2,2}, - {1,2}, - {0,2}, - {0,1}, - {0,0}, - {0,0}, - {0,0}, - {0,0}, - {0,0}, - {0,0}, - {0,0} -}; - -int Index5By[][2] = -{ - {0,0}, - {1,0}, - {2,0}, - {3,0}, - {4,0}, - {4,1}, - {4,2}, - {4,3}, - {4,4}, - {3,4}, - {2,4}, - {1,4}, - {0,4}, - {0,3}, - {0,2}, - {0,1} -}; - - - -int Interior3By[][2] = -{ - {1,1} -}; - -int Interior5By[][2] = -{ - {1,1}, - {2,1}, - {3,1}, - {1,2}, - {2,2}, - {3,2}, - {1,3}, - {2,3}, - {3,3} -}; - -int Interior3ByCount = sizeof(Interior3By) / sizeof(int[2]); -int Interior5ByCount = sizeof(Interior5By) / sizeof(int[2]); - -extern int Plane_FromPoints(vec3_t p1, vec3_t p2, vec3_t p3, plane_t *plane); -// the bFaceCycle only means we are going through a patch cycling loop -// then we rely on g_vCycleCapNormal to compute the cap - -void Patch_CapTexture(patchMesh_t *p, bool bFaceCycle = false) -{ - vec3_t vProjection, vX, vY; - qtexture_t *texture = p->pShader->getTexture(); - plane_t Plane1, Plane2, Plane3; - bool bThing=true; - - if (bFaceCycle) - VectorCopy (g_vCycleCapNormal, vProjection); - - else - { - VectorClear ( vProjection ); - - // find normal for plane from first 3 corner points - if (!Plane_FromPoints(p->ctrl[0][0].xyz,p->ctrl[0][p->height-1].xyz,p->ctrl[p->width-1][p->height-1].xyz,&Plane1)) - { - VectorClear ( Plane3.normal ); - bThing = false; - } - - // find normal for plane from next 3 corner points - if (!Plane_FromPoints(p->ctrl[p->width-1][p->height-1].xyz,p->ctrl[p->width-1][0].xyz,p->ctrl[0][0].xyz,&Plane2)) - { - if (bThing) - { - VectorCopy ( Plane1.normal, Plane3.normal ); - Plane3.dist = Plane1.dist; - } - } - - else - { - if (bThing) - // find average plane for all 4 corner points - { - for (int n = 0; n <= 2; n++) - { - Plane3.normal[n] = (Plane1.normal[n] + Plane2.normal[n]) / 2; - } - Plane3.dist = (Plane1.dist + Plane2.dist) / 2; - } - else - { - VectorCopy ( Plane2.normal, Plane3.normal ); - Plane3.dist = Plane2.dist; - } - } - - // get best axis for projection from average plane - //Sys_Printf("surface normal1: (%f,%f,%f)\n",Plane1.normal[0],Plane1.normal[1],Plane1.normal[0]); - //Sys_Printf("surface normal2: (%f,%f,%f)\n",Plane2.normal[0],Plane2.normal[1],Plane2.normal[0]); - //Sys_Printf("surface normal3: (%f,%f,%f)\n",Plane3.normal[0],Plane3.normal[1],Plane3.normal[0]); - TextureAxisFromPlane(&Plane3, vX, vY); - } - - for (int w = 0; w < p->width; w++) - { - for (int h = 0; h < p->height; h++) - { - if (vProjection[2] == 1.0f || (vX[0] == 1.0f && vY[1] == -1.0f)) - { - p->ctrl[w][h].st[0] = p->ctrl[w][h].xyz[0] / (texture->width * g_pGameDescription->mTextureDefaultScale); - p->ctrl[w][h].st[1] = p->ctrl[w][h].xyz[1] / (texture->height * g_pGameDescription->mTextureDefaultScale) * -1; - } - else if (vProjection[0] == 1.0f || (vX[1] == 1.0f && vY[2] == -1.0f)) - { - p->ctrl[w][h].st[0] = p->ctrl[w][h].xyz[1] / (texture->width * g_pGameDescription->mTextureDefaultScale); - p->ctrl[w][h].st[1] = p->ctrl[w][h].xyz[2] / (texture->height * g_pGameDescription->mTextureDefaultScale) * -1; - } - else if (vProjection[1] == 1.0f || (vX[0] == 1.0f && vY[2] == -1.0f)) - { - p->ctrl[w][h].st[0] = p->ctrl[w][h].xyz[0] / (texture->width * g_pGameDescription->mTextureDefaultScale); - p->ctrl[w][h].st[1] = p->ctrl[w][h].xyz[2] / (texture->height * g_pGameDescription->mTextureDefaultScale) * -1; - } - //Sys_Printf("(%i,%i) (%f,%f,%f) (%f,%f) %f\n",w,h, - // p->ctrl[w][h].xyz[0],p->ctrl[w][h].xyz[1],p->ctrl[w][h].xyz[2], - // p->ctrl[w][h].st[0],p->ctrl[w][h].st[1],p->ctrl[w][h].normal); - } - } - // make sure it will rebuild - p->bDirty = true; -} - -void FillPatch(patchMesh_t *p, vec3_t v) -{ - for (int i = 0; i < p->width; i++) - { - for (int j = 0; j < p->height; j++) - { - VectorCopy(v, p->ctrl[i][j].xyz); - } - } -} - -// temporarily moved function to allow use in Cap() and CapSpecial() -void patchInvert(patchMesh_t *p) -{ - drawVert_t vertTemp; - p->bDirty = true; - for ( int i = 0 ; i < p->width ; i++ ) - { - for (int j = 0; j < p->height / 2; j++) - { - memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t)); - memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t)); - memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t)); - } - } -} - -brush_t* Cap(patchMesh_t *pParent, bool bByColumn, bool bFirst) -{ - brush_t *b; - patchMesh_t *p; - vec3_t vMin, vMax; - int i, j; - - bool bSmall = true; - // make a generic patch - if (pParent->width <= 9) - { - b = Patch_GenericMesh(3, 3, 2, false); - } - else - { - b = Patch_GenericMesh(5, 5, 2, false); - bSmall = false; - } - - if (!b) - { - Sys_Printf("Unable to cap. You may need to ungroup the patch.\n"); - return NULL; - } - - p = b->pPatch; - p->type |= PATCH_CAP; - - vMin[0] = vMin[1] = vMin[2] = 9999; - vMax[0] = vMax[1] = vMax[2] = -9999; - - // we seam the column edge, FIXME: this might need to be able to seem either edge - // - int nSize = (bByColumn) ? pParent->width : pParent->height; - int nIndex = (bFirst) ? 0 : (bByColumn) ? pParent->height-1 : pParent->width-1; - - FillPatch(p, pParent->ctrl[0][nIndex].xyz); - - for (i = 0; i < nSize; i++) - { - if (bByColumn) - { - if (bSmall) - { - VectorCopy(pParent->ctrl[i][nIndex].xyz, p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz); - } - else - { - VectorCopy(pParent->ctrl[i][nIndex].xyz, p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz); - } - } - else - { - if (bSmall) - { - VectorCopy(pParent->ctrl[nIndex][i].xyz, p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz); - } - else - { - VectorCopy(pParent->ctrl[nIndex][i].xyz, p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz); - } - } - - for (j = 0; j < 3; j++) - { - float f = (bSmall) ? p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz[j] : p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz[j]; - if (f < vMin[j]) - vMin[j] = f; - if (f > vMax[j]) - vMax[j] = f; - } - } - - vec3_t vTemp; - for (j = 0; j < 3; j++) - { - vTemp[j] = vMin[j] + fabs((vMax[j] - vMin[j]) * 0.5); - } - int nCount = (bSmall) ? Interior3ByCount : Interior5ByCount; - for (j = 0; j < nCount; j++) - { - if (bSmall) - { - VectorCopy(vTemp, p->ctrl[Interior3By[j][0]][Interior3By[j][1]].xyz); - } - else - { - VectorCopy(vTemp, p->ctrl[Interior5By[j][0]][Interior5By[j][1]].xyz); - } - } - - if (bFirst) - patchInvert(p); - /* - { - drawVert_t vertTemp; - for (i = 0; i < p->width; i++) - { - for (j = 0; j < p->height / 2; j++) - { - memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t)); - memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t)); - memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t)); - } - } - } - */ - - Patch_Rebuild(p); - Patch_CapTexture(p); - return p->pSymbiot; -} - -brush_t* CapSpecial(patchMesh_t *pParent, int nType, bool bFirst) -{ - - brush_t *b; - patchMesh_t *p; - vec3_t vMin, vMax, vTemp; - int i, j; - - if (nType == IENDCAP) - b = Patch_GenericMesh(5, 3, 2, false); - else - b = Patch_GenericMesh(3, 3, 2, false); - - if (!b) - { - Sys_Printf("Unable to cap. Make sure you ungroup before re-capping."); - return NULL; - } - - p = b->pPatch; - p->type |= PATCH_CAP; - - vMin[0] = vMin[1] = vMin[2] = 9999; - vMax[0] = vMax[1] = vMax[2] = -9999; - - // int nSize = pParent->width; - int nIndex = (bFirst) ? 0 : pParent->height-1; - - // parent bounds are used for some things - Patch_CalcBounds(pParent, vMin, vMax); - - for (j = 0; j < 3; j++) - { - vTemp[j] = vMin[j] + fabs((vMax[j] - vMin[j]) * 0.5); - } - - if (nType == IBEVEL) - { - VectorCopy(pParent->ctrl[0][nIndex].xyz, p->ctrl[0][0].xyz); - VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[0][2].xyz); - VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[0][1].xyz); - VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[2][2].xyz); - VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][0].xyz); - VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][1].xyz); - VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][2].xyz); - VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[2][0].xyz); - VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[2][1].xyz); - } - else if (nType == BEVEL) - { - vec3_t p1, p2, p3, p4; //, temp, dir; - - VectorCopy(pParent->ctrl[0][nIndex].xyz, p3); - VectorCopy(pParent->ctrl[1][nIndex].xyz, p1); - VectorCopy(pParent->ctrl[2][nIndex].xyz, p2); - - //Sys_Printf("CapSpecial() p1: %f %f %f\n",p1[0],p1[1],p1[2]); - //Sys_Printf("CapSpecial() p2: %f %f %f\n",p2[0],p2[1],p2[2]); - //Sys_Printf("CapSpecial() p3: %f %f %f\n",p3[0],p3[1],p3[2]); - - VectorSubtract(p2, p1, p4); - VectorAdd(p3, p4, p4); - // spog - use opposite-point-on-parallelogram to find p4 - /* - VectorSubtract(p3, p2, dir); - VectorNormalize(dir); - VectorSubtract(p1, p2, temp); - vec_t dist = _DotProduct(temp, dir); - VectorScale(dir, dist, temp); - VectorAdd(p2, temp, temp); - VectorSubtract(temp, p1, temp); - VectorScale(temp, 2, temp); - VectorAdd(p1, temp, p4); - */ - - //Sys_Printf("CapSpecial() p1: %f %f %f\n",p1[0],p1[1],p1[2]); - //Sys_Printf("CapSpecial() p2: %f %f %f\n",p2[0],p2[1],p2[2]); - //Sys_Printf("CapSpecial() p3: %f %f %f\n",p3[0],p3[1],p3[2]); - //Sys_Printf("CapSpecial() p4: %f %f %f\n",p4[0],p4[1],p4[2]); - - VectorCopy(p4, p->ctrl[0][0].xyz); - VectorCopy(p4, p->ctrl[1][0].xyz); - VectorCopy(p4, p->ctrl[0][1].xyz); - VectorCopy(p4, p->ctrl[1][1].xyz); - VectorCopy(p4, p->ctrl[0][2].xyz); - VectorCopy(p4, p->ctrl[1][2].xyz); - VectorCopy(p2, p->ctrl[2][0].xyz); - VectorCopy(p1, p->ctrl[2][1].xyz); - VectorCopy(p3, p->ctrl[2][2].xyz); - - } - else if (nType == ENDCAP) - { - VectorAdd(pParent->ctrl[4][nIndex].xyz, pParent->ctrl[0][nIndex].xyz, vTemp); - VectorScale(vTemp, 0.5, vTemp); - VectorCopy(pParent->ctrl[0][nIndex].xyz, p->ctrl[0][0].xyz); - VectorCopy(vTemp, p->ctrl[1][0].xyz); - VectorCopy(pParent->ctrl[4][nIndex].xyz, p->ctrl[2][0].xyz); - - VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[0][2].xyz); - VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[1][2].xyz); - VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][2].xyz); - VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[1][1].xyz); - - VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[0][1].xyz); - VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[2][1].xyz); - } - else - { - VectorCopy(pParent->ctrl[4][nIndex].xyz, p->ctrl[0][0].xyz); - VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[1][0].xyz); - VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][0].xyz); - VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[3][0].xyz); - VectorCopy(pParent->ctrl[0][nIndex].xyz, p->ctrl[4][0].xyz); - - VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[0][1].xyz); - VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[1][1].xyz); - VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][1].xyz); - VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[3][1].xyz); - VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[4][1].xyz); - - VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[0][2].xyz); - VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[1][2].xyz); - VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][2].xyz); - VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[3][2].xyz); - VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[4][2].xyz); - } - - - if (!bFirst) - { - drawVert_t vertTemp; - for (i = 0; i < p->width; i++) - { - for (j = 0; j < p->height / 2; j++) - { - memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t)); - memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t)); - memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t)); - } - } - } - - //--Patch_CalcBounds(p, vMin, vMax); - //--Brush_RebuildBrush(p->pSymbiot, vMin, vMax); - Patch_Rebuild(p); - Patch_CapTexture(p); - return p->pSymbiot; -} - -void Patch_CapCurrent() -{ - patchMesh_t *pParent = NULL; - brush_t *b[4]; - brush_t *pCap = NULL; - b[0] = b[1] = b[2] = b[3] = NULL; - int nIndex = 0; - bool b_GroupResult = TRUE; - - if (!QE_SingleBrush(true)) - { - Sys_Printf("Patch_CapCurrent: you must have a single patch selected\n"); - return; - } - - - for (brush_t *pb = selected_brushes.next ; pb != NULL && pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - pParent = pb->pPatch; - // decide which if any ends we are going to cap - // if any of these compares hit, it is a closed patch and as such - // the generic capping will work.. if we do not find a closed edge - // then we need to ask which kind of cap to add - if (VectorCompare(pParent->ctrl[0][0].xyz, pParent->ctrl[pParent->width-1][0].xyz)) - { - pCap = Cap(pParent, true, false); - if (pCap != NULL) - { - b[nIndex++] = pCap; - } - } - if (VectorCompare(pParent->ctrl[0][pParent->height-1].xyz, pParent->ctrl[pParent->width-1][pParent->height-1].xyz)) - { - pCap = Cap(pParent, true, true); - if (pCap != NULL) - { - b[nIndex++] = pCap; - } - } - if (VectorCompare(pParent->ctrl[0][0].xyz, pParent->ctrl[0][pParent->height-1].xyz)) - { - pCap = Cap(pParent, false, false); - if (pCap != NULL) - { - b[nIndex++] = pCap; - } - } - if (VectorCompare(pParent->ctrl[pParent->width-1][0].xyz, pParent->ctrl[pParent->width-1][pParent->height-1].xyz)) - { - pCap = Cap(pParent, false, true); - if (pCap != NULL) - { - b[nIndex++] = pCap; - } - } - } - } - - if (pParent) - { - // if we did not cap anything with the above tests - if (nIndex == 0) - { - int type; - - if (DoCapDlg (&type, &b_GroupResult) == IDOK) - { - b[nIndex++] = CapSpecial(pParent, type, false); - b[nIndex++] = CapSpecial(pParent, type, true); - } - } - - if (nIndex > 0) - { - while (nIndex > 0) - { - nIndex--; - if (b[nIndex]) - { - Select_Brush(b[nIndex]); - } - } - // Gef: Added toggle for capped patch func_group - if(b_GroupResult) { - entity_t *e = Entity_Alloc(); - SetKeyValue(e, "classname", "func_group"); - SetKeyValue(e, "type", "patchCapped"); - Select_GroupEntity(e); - Entity_AddToList(e, &entities); - } - } - } -} - -/* -=============== -BrushToPatchMesh -=============== -*/ -void Patch_BrushToMesh(bool bCone, bool bBevel, bool bEndcap, bool bSquare, int nHeight) -{ - brush_t *b; - patchMesh_t *p; - int i,j; - - if (!QE_SingleBrush()) - return; - - b = selected_brushes.next; - - p = MakeNewPatch(); - - p->d_texture = b->brush_faces->d_texture; - p->pShader = b->brush_faces->pShader; - - p->height = nHeight; - - p->type = PATCH_CYLINDER; - if (bBevel & !bSquare) - { - p->type = PATCH_BEVEL; - p->width = 3; - int nStep = (int)((b->maxs[2] - b->mins[2]) / (p->height-1)); - int nStart = (int)(b->mins[2]); - for (i = 0; i < p->height; i++) - { - p->ctrl[0][i].xyz[0] = b->mins[0]; - p->ctrl[0][i].xyz[1] = b->mins[1]; - p->ctrl[0][i].xyz[2] = nStart; - - p->ctrl[1][i].xyz[0] = b->maxs[0]; - p->ctrl[1][i].xyz[1] = b->mins[1]; - p->ctrl[1][i].xyz[2] = nStart; - - p->ctrl[2][i].xyz[0] = b->maxs[0]; - p->ctrl[2][i].xyz[1] = b->maxs[1]; - p->ctrl[2][i].xyz[2] = nStart; - nStart += nStep; - } - } - else if (bEndcap & !bSquare) - { - p->type = PATCH_ENDCAP; - p->width = 5; - int nStep = (int)((b->maxs[2] - b->mins[2]) / (p->height-1)); - int nStart = (int)(b->mins[2]); - for (i = 0; i < p->height; i++) - { - p->ctrl[0][i].xyz[0] = b->mins[0]; - p->ctrl[0][i].xyz[1] = b->mins[1]; - p->ctrl[0][i].xyz[2] = nStart; - - p->ctrl[1][i].xyz[0] = b->mins[0]; - p->ctrl[1][i].xyz[1] = b->maxs[1]; - p->ctrl[1][i].xyz[2] = nStart; - - p->ctrl[2][i].xyz[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) * 0.5); - p->ctrl[2][i].xyz[1] = b->maxs[1]; - p->ctrl[2][i].xyz[2] = nStart; - - p->ctrl[3][i].xyz[0] = b->maxs[0]; - p->ctrl[3][i].xyz[1] = b->maxs[1]; - p->ctrl[3][i].xyz[2] = nStart; - - p->ctrl[4][i].xyz[0] = b->maxs[0]; - p->ctrl[4][i].xyz[1] = b->mins[1]; - p->ctrl[4][i].xyz[2] = nStart; - nStart += nStep; - } - } - else - { - p->width = 9; - p->ctrl[1][0].xyz[0] = b->mins[0]; - p->ctrl[1][0].xyz[1] = b->mins[1]; - - p->ctrl[3][0].xyz[0] = b->maxs[0]; - p->ctrl[3][0].xyz[1] = b->mins[1]; - - p->ctrl[5][0].xyz[0] = b->maxs[0]; - p->ctrl[5][0].xyz[1] = b->maxs[1]; - - p->ctrl[7][0].xyz[0] = b->mins[0]; - p->ctrl[7][0].xyz[1] = b->maxs[1]; - - for ( i = 1 ; i < p->width - 1 ; i += 2 ) - { - - p->ctrl[i][0].xyz[2] = b->mins[2]; - - VectorCopy( p->ctrl[i][0].xyz, p->ctrl[i][2].xyz ); - - p->ctrl[i][2].xyz[2] = b->maxs[2]; - - p->ctrl[i][1].xyz[0] = ( p->ctrl[i][0].xyz[0] + p->ctrl[i][2].xyz[0] ) * 0.5; - p->ctrl[i][1].xyz[1] = ( p->ctrl[i][0].xyz[1] + p->ctrl[i][2].xyz[1] ) * 0.5; - p->ctrl[i][1].xyz[2] = ( p->ctrl[i][0].xyz[2] + p->ctrl[i][2].xyz[2] ) * 0.5; - } - InterpolateInteriorPoints( p ); - - if (bSquare) - { - if (bBevel || bEndcap) - { - if (bBevel) - { - for (i = 0; i < p->height; i++) - { - VectorCopy(p->ctrl[1][i].xyz, p->ctrl[2][i].xyz); - VectorCopy(p->ctrl[7][i].xyz, p->ctrl[6][i].xyz); - } - } - else - { - for (i = 0; i < p->height; i++) - { - VectorCopy(p->ctrl[5][i].xyz, p->ctrl[4][i].xyz); - VectorCopy(p->ctrl[1][i].xyz, p->ctrl[2][i].xyz); - VectorCopy(p->ctrl[7][i].xyz, p->ctrl[6][i].xyz); - VectorCopy(p->ctrl[8][i].xyz, p->ctrl[7][i].xyz); - } - } - } - else - { - for (i = 0; i < p->width-1; i ++) - { - for (j = 0; j < p->height; j++) - { - VectorCopy(p->ctrl[i+1][j].xyz, p->ctrl[i][j].xyz); - } - } - for (j = 0; j < p->height; j++) - { - VectorCopy(p->ctrl[0][j].xyz, p->ctrl[8][j].xyz); - } - } - } - } - - - Patch_Naturalize(p); - - if (bCone) - { - p->type = PATCH_CONE; - float xc = (b->maxs[0] + b->mins[0]) * 0.5; - float yc = (b->maxs[1] + b->mins[1]) * 0.5; - - for ( i = 0 ; i < p->width ; i ++) - { - p->ctrl[i][2].xyz[0] = xc; - p->ctrl[i][2].xyz[1] = yc; - } - } - - b = AddBrushForPatch(p); - - Select_Delete(); - Select_Brush(b); - -} - -/* -================== -Patch_GenericMesh -================== -*/ -brush_t* Patch_GenericMesh(int nWidth, int nHeight, int nOrientation, bool bDeleteSource, bool bOverride) -{ - int i,j; - - if (nHeight < 3 || nHeight > 15 || nWidth < 3 || nWidth > 15) - { - Sys_Printf("Invalid patch width or height.\n"); - return NULL; - } - - if (! bOverride && !QE_SingleBrush()) - { - Sys_Printf("Error: you must have a single brush selected\n"); - return NULL; - } - - patchMesh_t* p = MakeNewPatch(); - p->pShader = g_qeglobals.d_texturewin.pShader; - p->d_texture = g_qeglobals.d_texturewin.pShader->getTexture(); - - p->width = nWidth; - p->height = nHeight; - p->type = PATCH_GENERIC; - - int nFirst = 0; - int nSecond = 1; - if (nOrientation == 0) - { - nFirst = 1; - nSecond = 2; - } - else if (nOrientation == 1) - { - nSecond = 2; - } - - brush_t *b = selected_brushes.next; - // set the workzone to this brush, use it later to create the patch points - UpdateWorkzone_ForBrush( b ); - - int xStep = (int)(b->mins[nFirst]); - float xAdj = fabs((b->maxs[nFirst] - b->mins[nFirst]) / (nWidth - 1)); - float yAdj = fabs((b->maxs[nSecond] - b->mins[nSecond]) / (nHeight - 1)); - - for (i = 0; i < nWidth; i++) - { - int yStep = (int)(b->mins[nSecond]); - for (j = 0; j < nHeight; j++) - { - p->ctrl[i][j].xyz[nFirst] = xStep; - p->ctrl[i][j].xyz[nSecond] = yStep; - // create patch based on workzone - p->ctrl[i][j].xyz[nOrientation] = g_qeglobals.d_work_max[nOrientation]; - yStep += (int)yAdj; - } - xStep += (int)xAdj; - } - - Patch_Naturalize(p); - - b = AddBrushForPatch(p); - if (bDeleteSource) - { - Select_Delete(); - Select_Brush(b); - } - - return b; - //g_qeglobals.d_select_mode = sel_curvepoint; -} - -/* -================== -PointInMoveList -================== -*/ -int PointInMoveList(float *pf) -{ - for (int i = 0; i < g_qeglobals.d_num_move_points; i++) - { - if (pf == &g_qeglobals.d_move_points[i][0]) - return i; - } - return -1; -} - -/* -================== -PointValueInMoveList -================== -*/ -int PointValueInMoveList(vec3_t v) -{ - for (int i = 0; i < g_qeglobals.d_num_move_points; i++) - { - if (VectorCompare(v, g_qeglobals.d_move_points[i])) - return i; - } - return -1; -} - - -/* -================== -RemovePointFromMoveList -================== -*/ -void RemovePointFromMoveList(vec3_t v) -{ - int n; - while ( (n = PointValueInMoveList(v)) >= 0) - { - for (int i = n; i < g_qeglobals.d_num_move_points-1; i++) - { - g_qeglobals.d_move_points[i] = g_qeglobals.d_move_points[i+1]; - } - g_qeglobals.d_num_move_points--; - } -} - -/* -================== -ColumnSelected -================== -*/ -bool ColumnSelected(patchMesh_t* p, int nCol) -{ - for (int i = 0; i < p->height; i++) - { - if (PointInMoveList(p->ctrl[nCol][i].xyz) == -1) - return false; - } - return true; -} - -/* -================== -AddPoint -================== -*/ -void AddPoint(patchMesh_t* p, vec3_t v, bool bWeldOrDrill = true) -{ - int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0; - int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2; - g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = v; - if ((g_bPatchWeld || g_bPatchDrillDown) && bWeldOrDrill) - { - for ( int i = 0 ; i < p->width ; i++ ) - { - for ( int j = 0 ; j < p->height ; j++ ) - { - if (g_bPatchWeld) - { - if ( VectorCompare(v, p->ctrl[i][j].xyz) - && PointInMoveList(p->ctrl[i][j].xyz) == -1) - { - g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz; - continue; - } - } - if (g_bPatchDrillDown && g_nPatchClickedView != W_CAMERA) - { - if ( (fabs(v[nDim1] - p->ctrl[i][j].xyz[nDim1]) <= EQUAL_EPSILON) - &&(fabs(v[nDim2] - p->ctrl[i][j].xyz[nDim2]) <= EQUAL_EPSILON)) - { - if (PointInMoveList(p->ctrl[i][j].xyz) == -1) - { - g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz; - continue; - } - } - } - } - } - } -} - -/* -================== -SelectRow -================== -*/ -void SelectRow(patchMesh_t* p, int nRow, bool bMulti) -{ - if (!bMulti) - g_qeglobals.d_num_move_points = 0; - for (int i = 0; i < p->width; i++) - { - AddPoint(p, p->ctrl[i][nRow].xyz, false); - } - //Sys_Printf("Selected Row %d\n", nRow); -} - -/* -================== -SelectColumn -================== -*/ -void SelectColumn(patchMesh_t* p, int nCol, bool bMulti) -{ - if (!bMulti) - g_qeglobals.d_num_move_points = 0; - for (int i = 0; i < p->height; i++) - { - AddPoint(p, p->ctrl[nCol][i].xyz, false); - } - //Sys_Printf("Selected Col %d\n", nCol); -} - - -/* -================== -AddPatchMovePoint -================== -*/ -void AddPatchMovePoint(vec3_t v, bool bMulti, bool bFull) -{ - if (!g_bSameView && !bMulti && !bFull) - { - g_bSameView = true; - //return; // was causing odd behaviour on patch vertex selection - } - - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - patchMesh_t* p = pb->pPatch; - for ( int i = 0 ; i < p->width ; i++ ) - { - for ( int j = 0 ; j < p->height ; j++ ) - { - if (VectorCompare(v, p->ctrl[i][j].xyz)) - { - if (PointInMoveList(p->ctrl[i][j].xyz) == -1) - { - if (bFull) // if we want the full row/col this is on - { - SelectColumn(p, i, bMulti); - } - else - { - if (!bMulti) - g_qeglobals.d_num_move_points = 0; - AddPoint(p, p->ctrl[i][j].xyz); - //Sys_Printf("Selected col:row %d:%d\n", i, j); - } - //--if (!bMulti) - return; - } - else - { - if (bFull) - { - if (ColumnSelected(p, i)) - { - SelectRow(p, j, bMulti); - } - else - { - SelectColumn(p, i, bMulti); - } - return; - } - //if (!bMulti) - //{ - // g_qeglobals.d_num_move_points = 0; - // AddPoint(p, p->ctrl[i][j].xyz); - //} - if (bMulti)// if (g_bSameView) // this is not having desired effect - { - RemovePointFromMoveList(v); - return; - } - } - } - } - } - } - } -} - -/* -================== -Patch_UpdateSelected -================== -*/ -void Patch_UpdateSelected(vec3_t vMove) -{ - int i;//, j; - for (i=0 ; i < g_qeglobals.d_num_move_points ; i++) - { - VectorAdd (g_qeglobals.d_move_points[i], vMove, g_qeglobals.d_move_points[i]); - if (g_qeglobals.d_num_move_points == 1) - { - } - } - - //--patchMesh_t* p = &patchMeshes[g_nSelectedPatch]; - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - patchMesh_t* p = pb->pPatch; - -#if 0 //moving to SelectCurvePointByRay - g_qeglobals.d_numpoints = 0; - for (i = 0 ; i < p->width ; i++ ) - { - for ( j = 0 ; j < p->height ; j++ ) - { - VectorCopy (p->ctrl[i][j].xyz, g_qeglobals.d_points[g_qeglobals.d_numpoints]); - if (g_qeglobals.d_numpoints < MAX_POINTS-1) - { - g_qeglobals.d_numpoints++; - } - } - } -#endif - vec3_t vMin, vMax; - Patch_CalcBounds(p, vMin, vMax); - Brush_RebuildBrush(p->pSymbiot, vMin, vMax); - } - } - //Brush_Free(p->pSymbiot); - //Select_Brush(AddBrushForPatch(g_nSelectedPatch)); -} - - - -/* -=============== -SampleSinglePatch -=============== -*/ -void SampleSinglePatch (float ctrl[3][3][5], float u, float v, float out[5]) { - float vCtrl[3][5]; - int vPoint; - int axis; - - // find the control points for the v coordinate - for (vPoint = 0 ; vPoint < 3 ; vPoint++) - { - for (axis = 0 ; axis < 5 ; axis++) - { - float a, b, c; - float qA, qB, qC; - - a = ctrl[0][vPoint][axis]; - b = ctrl[1][vPoint][axis]; - c = ctrl[2][vPoint][axis]; - qA = a - 2 * b + c; - qB = 2 * b - 2 * a; - qC = a; - - vCtrl[vPoint][axis] = qA * u * u + qB * u + qC; - } - } - - // interpolate the v value - for (axis = 0 ; axis < 5 ; axis++) - { - float a, b, c; - float qA, qB, qC; - - a = vCtrl[0][axis]; - b = vCtrl[1][axis]; - c = vCtrl[2][axis]; - qA = a - 2 * b + c; - qB = 2 * b - 2 * a; - qC = a; - - out[axis] = qA * v * v + qB * v + qC; - } -} - -//spog - Curve LOD stuff starts - -float ShadeForNormal(vec3_t normal) -{ - float f; - - vec3_t L; - L[0] = 1.0f; - L[1] = 1.0f; - L[2] = 1.0f; - - - // quick diffuse shading - f = DotProduct(L, normal); - - // range 0.5 to 1.0 - f = (f+1)/4.0f; - //if (f < 0.0f) f = 0.0f; - - f += 0.5f; - - return f; -} - -void ShadeVertex (drawVert_t &p) -{ - p.lightmap[0] = ShadeForNormal(p.normal); -} - - -void Patch_DrawNormals(patchMesh_t *patch) -{ - int row, col; - vec3_t vNormal; - - qglBegin (GL_LINES); - for (col=0; colwidth; col++) - { - for (row=0; rowheight; row++) - { - VectorAdd(patch->ctrl[col][row].xyz, patch->ctrl[col][row].normal, vNormal); - qglVertex3fv (patch->ctrl[col][row].xyz); - qglVertex3fv (vNormal); - } - } - qglEnd (); -} - - -// take an array of three drawVerts, and the addresses of three more drawVerts -// interpolate new XYZST values from the three drawVerts, these are: -// the left sub-control-point, the right sub-control-point and the midpoint of the curve respectively -// store these values in the drawVerts passed to the function -void Patch_CurveSplit(drawVert_t *vCurve[3], drawVert_t &pLeft, drawVert_t &pRight, drawVert_t &pMid, float u) -{ - int i; - //float u = 0.5f; -// float a, b; - drawVert_t v1, v2, v3; -// vec3_t v4; - - for (i=0; i<3; i++) - { - // xyz - v1.xyz[i] = vCurve[1]->xyz[i] - vCurve[0]->xyz[i]; - v2.xyz[i] = vCurve[2]->xyz[i] - vCurve[1]->xyz[i]; - v1.xyz[i] *= u; - v2.xyz[i] *= u; - pLeft.xyz[i] = vCurve[0]->xyz[i] + v1.xyz[i]; - pRight.xyz[i] = vCurve[1]->xyz[i] + v2.xyz[i]; - - v3.xyz[i] = pRight.xyz[i] - pLeft.xyz[i]; - v3.xyz[i] *= u; - pMid.xyz[i] = pLeft.xyz[i] + v3.xyz[i]; - - // normal (weighted average) // no, that's b0rked - //a = 1 / u; // total - //b = u * a; // component 2 - //a = u - b; // component 1 - //pMid.normal[i] = u * ((vCurve[0]->normal[i] * b) + (vCurve[2]->normal[i] * a)); - - if (i==2) continue; - - // st - v1.st[i] = vCurve[1]->st[i] - vCurve[0]->st[i]; - v2.st[i] = vCurve[2]->st[i] - vCurve[1]->st[i]; - v1.st[i] *= u; - v2.st[i] *= u; - pLeft.st[i] = vCurve[0]->st[i] + v1.st[i]; - pRight.st[i] = vCurve[1]->st[i] + v2.st[i]; - - v3.st[i] = pRight.st[i] - pLeft.st[i]; - v3.st[i] *= u; - pMid.st[i] = pLeft.st[i] + v3.st[i]; - } -} - -// take an array of three points, return an index representing the curvature of those three points -// return zero if the curve is a straight line, unless the midpoint is not between the endpoints -float Patch_CurveIndex(vec3_t vCurve[]) -{ - vec3_t vTemp, v1, v2, v3, vClear; -// int i; - float width, angle; - float index, dot; - - VectorClear(vClear); - - VectorSubtract(vCurve[2], vCurve[0], vTemp); - VectorSubtract(vCurve[1], vCurve[0], v1); - VectorSubtract(vCurve[2], vCurve[1], v2); - - if (VectorCompare(v1, vClear) || VectorCompare(vTemp, v1)) // return 0 if 1->2 == 0 or 1->2 == 1->3 - return 0.0f; - - VectorNormalize(v1, v1); - VectorNormalize(v2, v2); - if (VectorCompare(v1, v2)) - return 0.0f; - - VectorCopy(vTemp, v3); - width = VectorNormalize(v3, v3); - - if (VectorCompare(v1, v3) && VectorCompare(v2, v3)) - return 0.0f; - - dot = DotProduct(v1, v2); - - angle = acos(dot) / Q_PI; - - index = width * angle; - - return index; -} - - -// create a new tree root, give it the coordinate values of the drawVert -// return a pointer to the new tree root -BTNode_t *BTree_Create(drawVert_t info) -{ - BTNode_t *BTree = new BTNode_t; - BTree->left = BTree->right = NULL; - VectorCopy(info.xyz, BTree->info.xyz); - VectorCopy(info.xyz, BTree->vMid.xyz); - for (int i=0; i<2; i++) - { - BTree->info.st[i] = info.st[i]; - BTree->vMid.st[i] = info.st[i]; - } - return BTree; -} - -// take ownership of the subtree -// delete the entire subtree -// return a NULL pointer -BTNode_t *BTree_Delete(BTNode_t *pBT) -{ - if (pBT != NULL) - { - BTree_Delete(pBT->left); - BTree_Delete(pBT->right); - delete pBT; - } - return NULL; -} - -// NOT currently used -BTNode_t *BTree_Clear(BTNode_t *pBT, bool bFirst = true) -{ - if (pBT != NULL) - { - BTree_Clear(pBT->left, false); - BTree_Clear(pBT->right, false); - if (!bFirst) delete pBT; - } - return pBT; -} - -// take a pointer to the last item added to the list (this can also be a NULL pointer) -// take a pointer to the root of a subtree, and the patch points to the left and right of it -// add a new item to the subtree list, and add the subtree and its adjacent points to the new item -// return a pointer to the last item added to the subtree list -BTreeList_t *BTree_AddToList(BTreeList_t *pBTList, BTNode_t *pBT, drawVert_t &pLeft, drawVert_t &pRight) -{ - BTreeList_t *newBTList = new BTreeList_t; - newBTList->next = pBTList; - newBTList->pBT = pBT; - VectorCopy(pLeft.xyz, newBTList->vLeft.xyz); - VectorCopy(pRight.xyz, newBTList->vRight.xyz); - VectorCopy(pLeft.normal, newBTList->vLeft.normal); - VectorCopy(pRight.normal, newBTList->vRight.normal); - for (int i=0; i<2; i++) - { - newBTList->vLeft.st[i] = pLeft.st[i]; - newBTList->vRight.st[i] = pRight.st[i]; - } - return newBTList; -} - -// NOT currently used, subtrees are now stored on the patch -// take ownership of the subtree list -// delete the entire list and the subtrees it points to -// return a NULL pointer -BTreeList_t *BTree_DeleteList(BTreeList_t *pBTList) -{ - if (pBTList != NULL) - { - BTree_DeleteList(pBTList->next); - pBTList->pBT = BTree_Delete(pBTList->pBT); - delete pBTList; - } - return NULL; -} - -// take ownership of the subtree list -// delete the entire subtree list, but not the subtrees themselves -// return a NULL pointer -BTreeList_t *BTree_DeletePointerList(BTreeList_t *pBTList) -{ - if (pBTList != NULL) - { - BTree_DeletePointerList(pBTList->next); - delete pBTList; - } - return NULL; -} - -// take a pointer to the last item added to the list of subtree lists -// add a subtree list to the list -// return a pointer to the last item added -BTListList_t *BTree_AddListToList(BTListList_t *pBTListList, BTreeList_t *pBTList) -{ - BTListList_t *newBTListList = new BTListList_t; - newBTListList->next = pBTListList; - newBTListList->list = pBTList; - return newBTListList; -} - - -// take ownership of the list of subtree lists -// delete the entire list of lists, but not the subtrees themselves -// return a NULL pointer -BTListList_t *BTree_DeleteListFromList(BTListList_t *pBTListList) -{ - if (pBTListList != NULL) - { - BTree_DeleteListFromList(pBTListList->next); - pBTListList->list = BTree_DeletePointerList(pBTListList->list); - delete pBTListList; - } - return NULL; -} - -// take a pointer to the last item in the list -// add a NULL linker subtree to the list, setting the "flipped" flag using the left curvepoint normal .. er.. hacky? -BTreeList_t *BTree_AddLinkToList(BTreeList_t *pBTList, bool bFlipped = false) -{ - BTreeList_t *linkBTList = new BTreeList_t; - linkBTList->pBT = NULL; - linkBTList->next = pBTList; - linkBTList->vLeft.normal[0] = (bFlipped) ? 1.0f : 0.0f; - return linkBTList; -} - - -// take an array of three points and the address of a vector -// store midpoint of the bezier curve formed by the three points, in the vector -void Patch_BezierInterpolate(vec3_t vCurve[], vec3_t &pMid) -{ - vec3_t vTemp; - int i; - VectorSubtract(vCurve[2], vCurve[0], vTemp); // Start->End - for (i=0; i<3; i++) - vTemp[i] /= 2; - VectorAdd(vCurve[0], vTemp, vTemp); // midpoint of Start->End - - VectorSubtract(vTemp, vCurve[1], vTemp); // Mid->(midpoint of Start->End) - for (i=0; i<3; i++) - vTemp[i] /= 2; - VectorAdd(vCurve[1], vTemp, pMid); // midpoint of Mid->(midpoint of Start->End) -} - - -// take a pointer to the list of subtrees, and a threshold value -// generate REAL surface curvature for the subtree curves, using bezier interpolation -// if any of the real curves has an index greater than the threshold, return true -bool Patch_MostCurvedRow(BTreeList_t *pBTList, int threshold) -{ - BTreeList_t *p; - float index;//, bestindex = 0; - vec3_t vCurve[3]; - vec3_t vRow[3]; -// int i; - - for (p = pBTList; p != NULL; p = p->next->next) - { - // this row - VectorCopy(p->vLeft.xyz, vCurve[0]); - VectorCopy(p->pBT->info.xyz, vCurve[1]); - VectorCopy(p->vRight.xyz, vCurve[2]); - - index = Patch_CurveIndex(vCurve); - if (index > threshold) - return true; - - if (p->next == NULL) - break; - - if (p->next->pBT == NULL) continue; - - VectorCopy(p->vLeft.xyz, vCurve[0]); - VectorCopy(p->next->vLeft.xyz, vCurve[1]); - VectorCopy(p->next->next->vLeft.xyz, vCurve[2]); - Patch_BezierInterpolate(vCurve, vRow[0]); - - VectorCopy(p->pBT->info.xyz, vCurve[0]); - VectorCopy(p->next->pBT->info.xyz, vCurve[1]); - VectorCopy(p->next->next->pBT->info.xyz, vCurve[2]); - Patch_BezierInterpolate(vCurve, vRow[1]); - - VectorCopy(p->vRight.xyz, vCurve[0]); - VectorCopy(p->next->vRight.xyz, vCurve[1]); - VectorCopy(p->next->next->vRight.xyz, vCurve[2]); - Patch_BezierInterpolate(vCurve, vRow[2]); - - index = Patch_CurveIndex(vRow); - if (index > threshold) - return true; - } - return false; -} - - -// take a pointer to a list of subtrees.. each subtree in the list is a 3-point bezier curve formed by two endpoints owned by the list, and a midpoint subtree node owned by a patch. -// if any of the subtrees are curved above a threshold, create a left and right subsubtree for each subtree in the list. -// if a NULL linker subtree is found, check for an orientation flip - ie. an inverted LOD-match - and create a NULL subsubtree with the same orientation flip -// this effectively generates trees for multiple patches at the same time.. the subtrees are always owned by their respective patches though -void BTree_ListCurveRecurse(BTreeList_t *pBTList) -{ - BTreeList_t *p; - BTreeList_t *leftBTList, *rightBTList; - //drawVert_t pLeft, pRight, pMid; - drawVert_t *vCurve[3]; - int threshold; - //int i; - bool bFlipped = false; - - if (g_PrefsDlg.m_nSubdivisions >= 1) - threshold = g_PrefsDlg.m_nSubdivisions; - - leftBTList = rightBTList = NULL; - - if (Patch_MostCurvedRow(pBTList, threshold)) // split all subtrees in list if any subtree is above threshold - { - //Sys_Printf("| "); - // traverse nodes in list - for (p = pBTList; p != NULL; p=p->next) - { - if (p->pBT == NULL) - { - leftBTList = BTree_AddLinkToList(leftBTList, (p->vLeft.normal[0] == 1.0f)); - rightBTList = BTree_AddLinkToList(rightBTList, (p->vLeft.normal[0] == 1.0f)); - if (p->vLeft.normal[0] == 1.0f) bFlipped = (!bFlipped) ? true : false; // switch bFlipped if true - continue; - } - - // create left node for this subtree - BTNode_t *newLeft = new BTNode_t; - p->pBT->left = newLeft; - newLeft->left = newLeft->right = NULL; - - // create right node for this subtree - BTNode_t *newRight = new BTNode_t; - p->pBT->right = newRight; - newRight->left = newRight->right = NULL; - - // split this node - vCurve[0] = &p->vLeft; - vCurve[1] = &p->pBT->info; - vCurve[2] = &p->vRight; - Patch_CurveSplit(vCurve, newLeft->info, newRight->info, p->pBT->vMid, 0.5); - - memcpy(&newLeft->vMid, &newLeft->info, sizeof(drawVert_t)); - memcpy(&newRight->vMid, &newRight->info, sizeof(drawVert_t)); - - - if (!bFlipped) - { - // add new left subtree to left subtree list - leftBTList = BTree_AddToList(leftBTList, newLeft, p->vLeft, p->pBT->vMid); - - // add new right subtree to right subtree list - rightBTList = BTree_AddToList(rightBTList, newRight, p->pBT->vMid, p->vRight); - } - else - { - // add new left subtree to right subtree list - rightBTList = BTree_AddToList(rightBTList, newLeft, p->vLeft, p->pBT->vMid); - - // add new right subtree to left subtree list - leftBTList = BTree_AddToList(leftBTList, newRight, p->pBT->vMid, p->vRight); - } - } - - // continue tree left - BTree_ListCurveRecurse(leftBTList); - leftBTList = BTree_DeletePointerList(leftBTList); - - // continue tree right - BTree_ListCurveRecurse(rightBTList); - rightBTList = BTree_DeletePointerList(rightBTList); - } -} - -// take mins and maxs values from two brushes -// return true if they intersect on every axis -bool TouchingAABBs(vec3_t mins1, vec3_t maxs1, vec3_t mins2, vec3_t maxs2) -{ - //bool xyz[3]; - vec3_t v1, v2, p1, p2, T; - for (int i=0; i<3; i++) - { - v1[i] = maxs1[i] - mins1[i]; - v2[i] = maxs2[i] - mins2[i]; - v1[i] /=2; - v2[i] /=2; - p1[i] = mins1[i] + v1[i]; - p2[i] = mins2[i] + v2[i]; - // p1 == origin of aabb1 - // p2 == origin of aabb1 - // v1 == displacement of aabb1 - // v1 == displacement of aabb2 - T[i] = p2[i] - p1[i]; // T == vector from aabb1 to aabb2 - if ( fabs(T[i]) > (fabs(v1[i]) + fabs(v2[i])) ) - return false; - } - return true; -} - -// take a pointer to the last item added to pBTList, a pointer to the patch, a row index (start) and a column index -// generate a row of row-curve tree roots, owned by the patch and add the entire column of row-curves to the list, using the row index to decide the order to add -// return a pointer to the last item added to the list -BTreeList_t *Patch_CreateBTListForRows(BTreeList_t *pBTList, patchMesh_t *patch, int start, int col) -{ - int row, pos; - patch->colDirty[(col-1)/2] = true; - - if (start == 0) - { - for (row=0; rowheight; row++) - { - pos = (((col-1)/2)*patch->height)+row; - patch->rowLOD[pos] = BTree_Delete(patch->rowLOD[pos]); - patch->rowLOD[pos] = BTree_Create(patch->ctrl[col][row]); - pBTList = BTree_AddToList(pBTList, patch->rowLOD[pos], patch->ctrl[col-1][row], patch->ctrl[col+1][row]); - } - } - else - { - for (row=patch->height-1; row>=0; row--) - { - pos = (((col-1)/2)*patch->height)+row; - patch->rowLOD[pos] = BTree_Delete(patch->rowLOD[pos]); - patch->rowLOD[pos] = BTree_Create(patch->ctrl[col][row]); - pBTList = BTree_AddToList(pBTList, patch->rowLOD[pos], patch->ctrl[col-1][row], patch->ctrl[col+1][row]); - } - } - return pBTList; -} - -// take a pointer to the last item added to pBTList, a pointer to the patch, a row index and a column index (start) -// generate a row of column-curve tree roots, owned by the patch and add the entire row of column-curves to the list, using the column index to decide the order to add -// return a pointer to the last item added to the list -BTreeList_t *Patch_CreateBTListForCols(BTreeList_t *pBTList, patchMesh_t *patch, int row, int start) -{ - int col, pos; - patch->rowDirty[(row-1)/2] = true; - - if (start == 0) - { - for (col=0; colwidth; col++) - { - pos = (((row-1)/2)*patch->width)+col; - patch->colLOD[pos] = BTree_Delete(patch->colLOD[pos]); - patch->colLOD[pos] = BTree_Create(patch->ctrl[col][row]); - pBTList = BTree_AddToList(pBTList, patch->colLOD[pos], patch->ctrl[col][row-1], patch->ctrl[col][row+1]); - } - } - else - { - for (col=patch->width-1; col>=0; col--) - { - pos = (((row-1)/2)*patch->width)+col; - patch->colLOD[pos] = BTree_Delete(patch->colLOD[pos]); - patch->colLOD[pos] = BTree_Create(patch->ctrl[col][row]); - pBTList = BTree_AddToList(pBTList, patch->colLOD[pos], patch->ctrl[col][row-1], patch->ctrl[col][row+1]); - } - - } - return pBTList; -} - -bool BTree_IsInList(BTreeList_t *pBTList, BTNode_t *pBT) -{ - BTreeList_t *p; - if (pBTList == NULL) return false; - - for (p=pBTList; p != NULL; p=p->next) - { - if (p->pBT != NULL) - { - if (p->pBT == pBT) - return true; - } - } - return false; -} - -int Patch_DegenCurve(vec3_t &start, vec3_t &mid, vec3_t &end) -{ - if (VectorCompare(start, mid) || VectorCompare(end, mid)) - { - if (VectorCompare(start, end)) return 2; - else return 1; - } - else return 0; -} - -// take a pointer to the last item added to the list, and a pointer to a patch (this patch is the owner of the three drawverts) -// take the addresses of three drawVerts, and compare them with the edges of all patches that touch the patch -// if they match an edge, add the tree roots for that section of the matched patch to the list, and recurse for the opposite edge of that patch section. Also, set the matched patch Dirty, so that its drawlists will be rebuilt -// return a pointer to the last item added -BTreeList_t *Patch_FindLODMatches(patchMesh_t *patch, BTreeList_t *pBTList, drawVert_t &pMid, drawVert_t &pLeft, drawVert_t &pRight) -{ - brush_t *pb, *brushlist; - int row, col, i;//, pos; - vec3_t vTemp, v1, v2;//, vClear; - bool bAlreadyAdded; - - //Sys_Printf("Patch_FindLODMatches: called\n"); - - if (VectorCompare(pMid.xyz, pLeft.xyz) && VectorCompare(pMid.xyz, pRight.xyz)) - return pBTList; - - //VectorClear(vClear); - VectorSubtract(pRight.xyz, pLeft.xyz, vTemp); - VectorSubtract(pMid.xyz, pLeft.xyz, v1); - VectorSubtract(pRight.xyz, pMid.xyz, v2); - - //if (VectorCompare(v1, vClear) || VectorCompare(vTemp, v1)) // return null if 1->2 == 0 or 1->2 == 1->3 - // return pBTList; - - VectorNormalize(v1, v1); - VectorNormalize(v2, v2); - if (VectorCompare(v1, v2)) - return pBTList; - - VectorNormalize(vTemp, vTemp); - if (VectorCompare(v1, vTemp) && VectorCompare(v2, vTemp)) - return pBTList; - - brushlist = &active_brushes; - for (i=0; i<2; i++) - { - for (pb = brushlist->next; pb != brushlist; pb=pb->next) - { - if (!pb->patchBrush || pb->pPatch == patch) - continue; - - // ignore this patch if its AABB does not touch the subject patch - if (!TouchingAABBs(patch->pSymbiot->maxs, patch->pSymbiot->mins, pb->maxs, pb->mins)) - continue; - - // all columns of curves - for (col=1; colpPatch->width; col+=2) - { - if (pb->pPatch->colDirty[(col-1)/2]) continue; - - bAlreadyAdded = false; - - // top and bottom curves of this column - for (row=0; rowpPatch->height; row+=pb->pPatch->height-1) - { - if (bAlreadyAdded) - continue; - //if (!BTree_IsInList(pBTList, pb->pPatch->rowLOD[(((col-1)/2)*patch->height)+row])) - // continue; - // ignore this curve if it shares no mid ctrl point with the test curve - if (!VectorCompare (pb->pPatch->ctrl[col][row].xyz, pMid.xyz)) - continue; - // ignore this curve if it is degenerate - if (VectorCompare (pb->pPatch->ctrl[col][row].xyz, pb->pPatch->ctrl[col-1][row].xyz) || VectorCompare (pb->pPatch->ctrl[col][row].xyz, pb->pPatch->ctrl[col+1][row].xyz)) - continue; - // if curve matches the test curve directly - if (VectorCompare (pb->pPatch->ctrl[col-1][row].xyz, pLeft.xyz) && VectorCompare (pb->pPatch->ctrl[col+1][row].xyz, pRight.xyz)) - { - // add a blank link as separator - pBTList = BTree_AddLinkToList(pBTList); - // add this entire column, if top, top-to-bottom, else bottom to top - pBTList = Patch_CreateBTListForRows(pBTList, pb->pPatch, row, col); - // continue checking from last curve added to list - pBTList = Patch_FindLODMatches(pb->pPatch, pBTList, pBTList->pBT->info, pBTList->vLeft, pBTList->vRight); - // set flag - pb->pPatch->LODUpdated = true; - bAlreadyAdded = true; - } - // if curve matches test curve but flipped - else if (VectorCompare (pb->pPatch->ctrl[col-1][row].xyz, pRight.xyz) && VectorCompare (pb->pPatch->ctrl[col+1][row].xyz, pLeft.xyz)) - { - pBTList = BTree_AddLinkToList(pBTList, true); // flip - pBTList = Patch_CreateBTListForRows(pBTList, pb->pPatch, row, col); - pBTList = Patch_FindLODMatches(pb->pPatch, pBTList, pBTList->pBT->info, pBTList->vLeft, pBTList->vRight); - pb->pPatch->LODUpdated = true; - bAlreadyAdded = true; - } - } - } - - // all rows of curves - for (row=1; rowpPatch->height; row+=2) - { - if (pb->pPatch->rowDirty[(row-1)/2]) continue; - - bAlreadyAdded = false; - - for (col=0; colpPatch->width; col+=pb->pPatch->width-1) - { - if (bAlreadyAdded) - continue; - //if (BTree_IsInList(pBTList, pb->pPatch->colLOD[(((row-1)/2)*patch->width)+col])) - // continue; - if (!VectorCompare (pb->pPatch->ctrl[col][row].xyz, pMid.xyz)) - continue; - if (VectorCompare (pb->pPatch->ctrl[col][row].xyz, pb->pPatch->ctrl[col][row-1].xyz) || VectorCompare (pb->pPatch->ctrl[col][row].xyz, pb->pPatch->ctrl[col][row+1].xyz)) - continue; - if (VectorCompare (pb->pPatch->ctrl[col][row-1].xyz, pLeft.xyz) && VectorCompare (pb->pPatch->ctrl[col][row+1].xyz, pRight.xyz)) - { - pBTList = BTree_AddLinkToList(pBTList); - pBTList = Patch_CreateBTListForCols(pBTList, pb->pPatch, row, col); - pBTList = Patch_FindLODMatches(pb->pPatch, pBTList, pBTList->pBT->info, pBTList->vLeft, pBTList->vRight); - pb->pPatch->LODUpdated = true; - bAlreadyAdded = true; - } - else if (VectorCompare (pb->pPatch->ctrl[col][row-1].xyz, pRight.xyz) && VectorCompare (pb->pPatch->ctrl[col][row+1].xyz, pLeft.xyz)) - { - pBTList = BTree_AddLinkToList(pBTList, true); // flip - pBTList = Patch_CreateBTListForCols(pBTList, pb->pPatch, row, col); - pBTList = Patch_FindLODMatches(pb->pPatch, pBTList, pBTList->pBT->info, pBTList->vLeft, pBTList->vRight); - pb->pPatch->LODUpdated = true; - bAlreadyAdded = true; - } - } - } - } - brushlist = &selected_brushes; - } - return pBTList; -} - -// take a pointer to a patch -// create tree roots for all the rows and columns of curves in the patch, the patch takes ownership of these new tree roots -// generate lists of pointers to all the trees in all the patches in the map which need to match the LOD of trees owned by this patch -// store all the lists in a list of lists -// recursively generate the rest of every tree in each list in the list -void Patch_CreateLODTrees(patchMesh_t *patch) -{ - BTreeList_t *pBTList; - int col, row, pos;//, rowcount, colcount; - BTListList_t *pLists; - - //Sys_Printf("Patch_CreateMatchedLODTrees: called\n"); - - BTListList_t *LODLists; - LODLists = NULL; - - pBTList = NULL; - - patch->bDirty = false; - patch->LODUpdated = true; - - for(col=1; colwidth; col+=2) - { - if (patch->colDirty[(col-1)/2]) continue; - else patch->colDirty[(col-1)/2] = true; - - // create list for rows of current patch - for(row=0; rowheight; row++) - { - pos = (((col-1)/2)*patch->height)+row; - patch->rowLOD[pos] = BTree_Delete(patch->rowLOD[pos]); - patch->rowLOD[pos] = BTree_Create(patch->ctrl[col][row]); - pBTList = BTree_AddToList(pBTList, patch->rowLOD[pos], patch->ctrl[col-1][row], patch->ctrl[col+1][row]); - } - - //create connection list for first row - pBTList = Patch_FindLODMatches(patch, pBTList, patch->ctrl[col][0], patch->ctrl[col-1][0], patch->ctrl[col+1][0]); - //create connection list for last row - pBTList = Patch_FindLODMatches(patch, pBTList, patch->ctrl[col][row-1], patch->ctrl[col-1][row-1], patch->ctrl[col+1][row-1]); - - LODLists = BTree_AddListToList(LODLists, pBTList); - pBTList = NULL; - } - - pBTList = NULL; - for(row=1; rowheight; row+=2) - { - if (patch->rowDirty[(row-1)/2]) continue; - else patch->rowDirty[(row-1)/2] = true; - - // create list for cols of current patch - for(col=0; colwidth; col++) - { - pos = (((row-1)/2)*patch->width)+col; - patch->colLOD[pos] = BTree_Delete(patch->colLOD[pos]); - patch->colLOD[pos] = BTree_Create(patch->ctrl[col][row]); - pBTList = BTree_AddToList(pBTList, patch->colLOD[pos], patch->ctrl[col][row-1], patch->ctrl[col][row+1]); - } - - //create connection list for first col - pBTList = Patch_FindLODMatches(patch, pBTList, patch->ctrl[0][row], patch->ctrl[0][row-1], patch->ctrl[0][row+1]); - //create connection list for last col - pBTList = Patch_FindLODMatches(patch, pBTList, patch->ctrl[col-1][row], patch->ctrl[col-1][row-1], patch->ctrl[col-1][row+1]); - - LODLists = BTree_AddListToList(LODLists, pBTList); - pBTList = NULL; - } - - for (pLists = LODLists; pLists != NULL; pLists=pLists->next) - BTree_ListCurveRecurse(pLists->list); - LODLists = BTree_DeleteListFromList(LODLists); -} - -int Patch_GetCVTangent(vec3_t &v1, vec3_t &p1, vec3_t &p2, vec3_t &p3) -{ - if (VectorCompare(p1, p2)) - { - if (VectorCompare(p1, p3)) - { - return 2; - } - else VectorSubtract(p3, p1, v1); - return 1; - } - else VectorSubtract(p2, p1, v1); - return 0; -} - -void Patch_CVNormal(vec3_t ctrl[3][3], vec3_t &normal) -{ - vec3_t v1, v2, vTemp1, vTemp2; - int a, b; - - a = Patch_GetCVTangent(v1, ctrl[0][0], ctrl[1][0], ctrl[2][0]); - b = Patch_GetCVTangent(v2, ctrl[0][0], ctrl[0][1], ctrl[0][2]); - - //Sys_Printf("p1: (%1.1f %1.1f %1.1f) p2: (%1.1f %1.1f %1.1f) p2: (%1.1f %1.1f %1.1f)\n", - // ctrl[0][0][0], ctrl[0][0][1], ctrl[0][0][2], ctrl[0][2][0], ctrl[0][2][1], ctrl[0][2][2], ctrl[2][0][0], ctrl[2][0][1], ctrl[2][0][2]); - - if (a == 2) - { - a = Patch_GetCVTangent(v1, ctrl[0][0], ctrl[1][1], ctrl[1][2]); - } - if (b == 2) - { - b = Patch_GetCVTangent(v2, ctrl[0][0], ctrl[1][1], ctrl[2][1]); - } - - if (a == 2) - { - a = Patch_GetCVTangent(v1, ctrl[0][0], ctrl[2][1], ctrl[2][2]); - } - if (b == 2) - { - b = Patch_GetCVTangent(v2, ctrl[0][0], ctrl[1][2], ctrl[2][2]); - } - - CrossProduct(v1, v2, normal); - - - if (normal[0] == 0.0f && normal[1] == 0.0f && normal[2] == 0.0f) - { - // more degenerate cases - vec3_t pMid; - vec3_t vCurve[3]; - /* - if (VectorCompare(ctrl[0][0], ctrl[2][0])) // endcap left - { - if (VectorCompare(ctrl[0][2], ctrl[1][2])) - { - VectorSubtract(ctrl[2][2], ctrl[0][0], v2); - } - else if (VectorCompare(ctrl[1][2], ctrl[2][2])) - { - VectorSubtract(ctrl[0][2], ctrl[0][0], v2); - } - else - a = Patch_DegenCurve(ctrl[0][2], ctrl[1][2], ctrl[2][2]); - if (a == 0) - { - VectorCopy(ctrl[0][2], vCurve[0]); - VectorCopy(ctrl[1][2], vCurve[1]); - VectorCopy(ctrl[2][2], vCurve[2]); - Patch_BezierInterpolate(vCurve, pMid); - VectorSubtract(pMid, ctrl[0][0], v1); - } - - - } - else if (VectorCompare(ctrl[0][0], ctrl[0][2])) // endcap right - { - - if (VectorCompare(ctrl[2][0], ctrl[2][1])) - { - VectorSubtract(ctrl[2][2], ctrl[0][0], v2); - } - else if (VectorCompare(ctrl[2][1], ctrl[2][2])) - { - VectorSubtract(ctrl[2][0], ctrl[0][0], v2); - } - else - - b = Patch_DegenCurve(ctrl[2][0], ctrl[2][1], ctrl[2][2]); - if (b == 0) - { - VectorCopy(ctrl[2][0], vCurve[0]); - VectorCopy(ctrl[2][1], vCurve[1]); - VectorCopy(ctrl[2][2], vCurve[2]); - Patch_BezierInterpolate(vCurve, pMid); - VectorSubtract(pMid, ctrl[0][0], v2); - } - - } - */ - if (VectorCompare(ctrl[0][0], ctrl[2][0])) // bottom degen - { - Patch_GetCVTangent(v1, ctrl[0][0], ctrl[2][1], ctrl[2][2]); - } - else if (VectorCompare(ctrl[0][0], ctrl[0][2])) // left degen - { - Patch_GetCVTangent(v2, ctrl[0][0], ctrl[1][2], ctrl[2][2]); - } - else if (VectorCompare(ctrl[0][2], ctrl[2][2])) // top degen - { - VectorSubtract(ctrl[2][0], ctrl[0][0], v1); - } - else if (VectorCompare(ctrl[2][0], ctrl[2][2])) // right degen - { - VectorSubtract(ctrl[0][2], ctrl[0][0], v2); - } - else // tangents parallel - { - VectorCopy(v1, vTemp1); - VectorCopy(v2, vTemp2); - VectorNormalize(vTemp1, vTemp1); - VectorNormalize(vTemp2, vTemp2); - if (VectorCompare(vTemp1, vTemp2)) // parallel same way - { - VectorSubtract(ctrl[2][0], ctrl[0][0], vTemp1); - VectorNormalize(vTemp1, vTemp1); - if (VectorCompare(vTemp1, vTemp2)) - { - VectorSubtract(ctrl[0][2], ctrl[0][0], v2); - } - else - { - VectorCopy(vTemp1, v1); - } - } - else // parallel opposite way - { - VectorCopy(ctrl[2][0], vCurve[0]); - VectorCopy(ctrl[1][1], vCurve[1]); - VectorCopy(ctrl[0][2], vCurve[2]); - Patch_BezierInterpolate(vCurve, pMid); - VectorSubtract(pMid, ctrl[0][0], v2); - } - } - - CrossProduct(v1, v2, normal); - } -} - -void Patch_CalcCVNormals(patchMesh_t *patch) -{ - int row, col, i, j, n; - vec3_t ctrl[3][3]; - vec3_t normals[4]; - - for (col=0; colwidth; col+=2) - { - for (row=0; rowheight; row+=2) - { - n=0; - if (col+1 != patch->width && row+1 != patch->height) - { - for (i=0; i<3; i++) - for (j=0; j<3; j++) - VectorCopy (patch->ctrl[col+i][row+j].xyz, ctrl[i][j]); - - Patch_CVNormal(ctrl, normals[n]); - VectorNormalize(normals[n], normals[n]); - n++; - } - - if (col-1 >= 0 && row-1 >= 0) - { - for (i=0; i<3; i++) - for (j=0; j<3; j++) - VectorCopy (patch->ctrl[col-i][row-j].xyz, ctrl[i][j]); - - Patch_CVNormal(ctrl, normals[n]); - VectorNormalize(normals[n], normals[n]); - n++; - } - if (col-1 >= 0 && row+1 != patch->height) - { - for (i=0; i<3; i++) - for (j=0; j<3; j++) - VectorCopy (patch->ctrl[col-i][row+j].xyz, ctrl[j][i]); - - Patch_CVNormal(ctrl, normals[n]); - VectorNormalize(normals[n], normals[n]); - n++; - } - if (col+1 != patch->width && row-1 >= 0) - { - for (i=0; i<3; i++) - for (j=0; j<3; j++) - VectorCopy (patch->ctrl[col+i][row-j].xyz, ctrl[j][i]); - - Patch_CVNormal(ctrl, normals[n]); - VectorNormalize(normals[n], normals[n]); - n++; - } - - for (i=0; i<3; i++) - { - if (n == 1) patch->ctrl[col][row].normal[i] = normals[0][i]; - if (n == 2) patch->ctrl[col][row].normal[i] = (normals[0][i] + normals[1][i]) / n; - //if (n == 3) patch->ctrl[col][row].normal[i] = (normals[0][i] + normals[1][i] + normals[2][i]) / n; - if (n == 4) patch->ctrl[col][row].normal[i] = (normals[0][i] + normals[1][i] + normals[2][i] + normals[3][i]) / n; - } - VectorNormalize(patch->ctrl[col][row].normal, patch->ctrl[col][row].normal); - //if (!g_PrefsDlg.m_bGLLighting) - // ShadeVertex(patch->ctrl[col][row]); - } - } -} - - -void BTree_SetNormals(BTNode_t *pBT, vec3_t &normal) -{ - if (pBT != NULL) - { - if (pBT->left != NULL && pBT->right != NULL) - { - VectorCopy(normal, pBT->vMid.normal); - //if (!g_PrefsDlg.m_bGLLighting) - // ShadeVertex(pBT->vMid); - } - BTree_SetNormals(pBT->left, normal); - BTree_SetNormals(pBT->right, normal); - } -} - - -void NormalFromPoints(vec3_t p1, vec3_t p2, vec3_t p3, vec3_t &normal, bool flip = false) -{ - vec3_t v1, v2; - - if (flip) - { - VectorSubtract(p2, p3, v1); //p3->p2 - VectorSubtract(p1, p2, v2); //p2->p1 - } - else - { - VectorSubtract(p2, p1, v1); //p1->p2 - VectorSubtract(p3, p2, v2); //p2->p3 - } - CrossProduct(v1, v2, normal); -} - - -void BTree_GenerateNormals(BTNode_t *pBTMid, BTNode_t *pBTLeft, BTNode_t *pBTRight, bool avg, bool flat, bool nomid, bool noleft, bool noright, /*bool endcap, vec3_t &n1, vec3_t &n2,*/ bool flip) -{ - if (pBTMid != NULL) - { - if (pBTMid->left != NULL && pBTMid->right != NULL) - { - vec3_t normal; - - if (noleft) // left curve is degenerate - { - if (nomid) // mid curve is degenerate - { - NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, normal, flip); - NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip); - } - //else if (endcap) - //{ - // VectorCopy(n1, normal); - // NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip); - //} - else - { - NormalFromPoints(pBTMid->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip); - NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip); - } - } - else if (noright) // right curve is degenerate - { - if (nomid) // mid curve is degenerate - { - NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip); - NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip); - } - //else if (endcap) - //{ - // NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip); - // VectorCopy(n2, pBTRight->vMid.normal); - //} - else - { - NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip); - NormalFromPoints(pBTMid->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip); - } - } - else - { - if (flat) // all curves are semi-degenerate (flat) or degenerate - { - NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTRight->vMid.xyz, normal, flip); - NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTLeft->vMid.xyz, pBTRight->vMid.normal, flip); - } - else - { - NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip); - NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip); - } - } - - VectorNormalize(normal, normal); - if (avg) - for (int i=0; i<3; i++) - pBTLeft->vMid.normal[i] = (normal[i] + pBTLeft->vMid.normal[i]) / 2.0f; - else VectorCopy(normal, pBTLeft->vMid.normal); - - VectorNormalize(pBTLeft->vMid.normal, pBTLeft->vMid.normal); - VectorNormalize(pBTRight->vMid.normal, pBTRight->vMid.normal); - - } - BTree_GenerateNormals(pBTMid->left, pBTLeft->left, pBTRight->left, avg, flat, nomid, noleft, noright, /*endcap, n1, n2,*/ flip); - BTree_GenerateNormals(pBTMid->right, pBTLeft->right, pBTRight->right, avg, flat, nomid, noleft, noright, /*endcap, n1, n2,*/ flip); - } -} - - - -void Patch_GenerateLODNormals(patchMesh_t *patch) -{ - int col, row, rowpos, colpos, i; - BTNode_t *tree[2][3]; - int degen[2][3]; - bool rowAvg, colAvg; - - for(col=0; col+2width; col+=2) - { - for(row=0; row+2height; row+=2) - { - if (!patch->colDirty[col/2] && !patch->rowDirty[row/2]) continue; - - rowpos = ((col/2)*patch->height)+row; - colpos = ((row/2)*patch->width)+col; - - if (row==0) rowAvg = false; - else rowAvg = true; - if (col==0) colAvg = false; - else colAvg = true; - - for (i=0; i<3; i++) - { - tree[0][i] = patch->rowLOD[rowpos+i]; - tree[1][i] = patch->colLOD[colpos+i]; - - degen[0][i] = Patch_DegenCurve(patch->ctrl[col][row+i].xyz, patch->ctrl[col+1][row+i].xyz, patch->ctrl[col+2][row+i].xyz); - degen[1][i] = Patch_DegenCurve(patch->ctrl[col+i][row].xyz, patch->ctrl[col+i][row+1].xyz, patch->ctrl[col+i][row+2].xyz); - } - - BTree_GenerateNormals(tree[0][1], tree[0][0], tree[0][2], rowAvg, (degen[1][0] && degen[1][1] && degen[1][2]), degen[0][1] == 2, degen[0][0] == 2, degen[0][2] == 2, /*degen[1][1], patch->ctrl[col][row].normal, patch->ctrl[col][row+2].normal,*/ false); - BTree_GenerateNormals(tree[1][1], tree[1][0], tree[1][2], colAvg, (degen[0][0] && degen[0][1] && degen[0][2]), degen[1][1] == 2, degen[1][0] == 2, degen[1][2] == 2, /*degen[0][1], patch->ctrl[col][row].normal, patch->ctrl[col+2][row].normal,*/ true); - } - } -} - - -void Patch_ClearLODFlags(patchMesh_t *p) -{ - int i; - - for (i=0;i<(p->width-1)/2; i++) - p->colDirty[i] = false; - - for (i=0;i<(p->height-1)/2; i++) - p->rowDirty[i] = false; -} - -// reset the lodDirty flags owned by all patches in the map -// create new LOD trees for all dirty patches, matched with all other patches in the map -void Patch_LODMatchAll() -{ - brush_t *pb, *brushlist; - int i; - - // create LOD tree roots and LOD tree lists for all patches that are dirty - - brushlist = &active_brushes; - for (i=0; i<2; i++) - { - for (pb = brushlist->next; pb && (pb != brushlist); pb=pb->next) - { - // create lod for selected patches when patches are filtered - if (pb->bFiltered && (pb->patchBrush && !pb->pPatch->bSelected)) - continue; - if (!pb->patchBrush) - continue; - if (!pb->pPatch->bDirty) - continue; - - Patch_CalcCVNormals(pb->pPatch); - Patch_CreateLODTrees(pb->pPatch); - } - brushlist = &selected_brushes; - } - - brushlist = &active_brushes; - for (i=0; i<2; i++) - { - for (pb = brushlist->next; pb && (pb != brushlist); pb=pb->next) - { - if (!pb->patchBrush) - continue; - - if (pb->pPatch->LODUpdated) - Patch_GenerateLODNormals(pb->pPatch); - - Patch_ClearLODFlags(pb->pPatch); - } - brushlist = &selected_brushes; - } - -} - -void Vertex_TransformTexture(drawVert_t *pVert, float fx, float fy, transformtype xform) -{ - switch(xform) - { - case TRANSLATE: - pVert->st[0] += fx; - pVert->st[1] += fy; - break; - case SCALE: - pVert->st[0] *= fx; - pVert->st[1] *= fy; - break; - case ROTATE: - float x = pVert->st[0]; - float y = pVert->st[1]; - pVert->st[0] = x * fx - y * fy; - pVert->st[1] = y * fx + x * fy; - } -} - -void BTree_TransformTexture(BTNode_t *pBT, float fx, float fy, transformtype xform) -{ - if (pBT != NULL) - { // PreOrder traversal - Vertex_TransformTexture(&pBT->info, fx, fy, xform); - Vertex_TransformTexture(&pBT->vMid, fx, fy, xform); - BTree_TransformTexture(pBT->left, fx, fy, xform); - BTree_TransformTexture(pBT->right, fx, fy, xform); - } -} - -void Patch_TransformLODTexture(patchMesh_t *p, float fx, float fy, transformtype xform) -{ - int col, row; - - for(col=1; colwidth; col+=2) - for(row=0; rowheight; row++) - BTree_TransformTexture(p->rowLOD[(((col-1)/2)*p->height)+row], fx, fy, xform); - - for(row=1; rowheight; row+=2) - for(col=0; colwidth; col++) - BTree_TransformTexture(p->colLOD[(((row-1)/2)*p->width)+col], fx, fy, xform); -} - -void Patch_AddBTreeToDrawListInOrder(list *drawList, BTNode_t *pBT) -{ - if (pBT != NULL) //traverse InOrder - { - Patch_AddBTreeToDrawListInOrder(drawList, pBT->left); - if (pBT->left != NULL && pBT->right != NULL) - drawList->push_back(pBT->vMid); - Patch_AddBTreeToDrawListInOrder(drawList, pBT->right); - } -} - -void Patch_InterpolateListFromRowBT(list *drawList, BTNode_t *rowBT, BTNode_t *rowBTLeft, drawVert_t *vCurve[], float u, float n, float v) -{ - if (rowBT != NULL) - { - Patch_InterpolateListFromRowBT(drawList, rowBT->left, rowBTLeft->left, vCurve, u-n, n*0.5f, v); - if (rowBT->left != NULL && rowBT->right != NULL) - { - vec3_t v1, v2; - drawVert_t newVert, vTemp1, vTemp2; - Patch_CurveSplit(vCurve, vTemp1, vTemp2, newVert, u); - for (int i=0; i<3; i++) - { - v1[i] = rowBT->vMid.xyz[i] - rowBTLeft->vMid.xyz[i]; // left -> mid - v1[i] = rowBTLeft->vMid.xyz[i] + (v1[i] * v); - v1[i] = newVert.xyz[i] - v1[i]; - } - VectorSubtract(vTemp1.xyz, newVert.xyz, v2); - CrossProduct(v1, v2, newVert.normal); - VectorNormalize(newVert.normal, newVert.normal); - //if (!g_PrefsDlg.m_bGLLighting) - // ShadeVertex(newVert); - drawList->push_back(newVert); - } - Patch_InterpolateListFromRowBT(drawList, rowBT->right, rowBTLeft->right, vCurve, u+n, n*0.5f, v); - } -} - -void Patch_TraverseColBTInOrder(list*>::iterator& iter, BTNode_t *colBTLeft, BTNode_t *colBT, BTNode_t *colBTRight, BTNode_t *rowBT, BTNode_t *rowBTLeft, float v, float n) -{ - if (colBT != NULL) - { - //traverse subtree In Order - Patch_TraverseColBTInOrder(iter, colBTLeft->left, colBT->left, colBTRight->left, rowBT, rowBTLeft, v-n, n*0.5f); - if (colBT->left != NULL && colBT->right != NULL) - { - drawVert_t *vCurve[3]; - vCurve[0] = &colBTLeft->vMid; - vCurve[1] = &colBT->vMid; - vCurve[2] = &colBTRight->vMid; - Patch_InterpolateListFromRowBT((*iter), rowBT, rowBTLeft, vCurve, 0.5f, 0.25f, v); - - (*iter)->push_back(colBTRight->vMid); - iter++; - } - Patch_TraverseColBTInOrder(iter, colBTLeft->right, colBT->right, colBTRight->right, rowBT, rowBTLeft, v+n, n*0.5f); - } -} - - -void Patch_StartDrawLists(list*> *drawLists, BTNode_t *colBT) -{ - if (colBT != NULL) - { - //traverse subtree In Order - Patch_StartDrawLists(drawLists, colBT->left); - if (colBT->left != NULL && colBT->right != NULL) - { - list *newList = new list; - drawLists->push_back(newList); // add empty list to back - drawLists->back()->push_back(colBT->vMid); - } - Patch_StartDrawLists(drawLists, colBT->right); - } -} - -typedef list drawList_t; -typedef list*> drawLists_t; - -void Patch_CreateDrawLists(patchMesh_t *patch) -{ - int col, row, colpos, rowpos; - - drawLists_t *drawLists = new drawLists_t; - - drawLists_t::iterator iter1, iter2; - - for (row=0; rowheight; row+=2) - { - colpos = (row/2)*patch->width; - drawList_t *newList = new drawList_t; - drawLists->push_back(newList); // add a new empty list to back - drawLists->back()->push_back(patch->ctrl[0][row]); // fill list at back - - if (row+1 == patch->height) - continue; - Patch_StartDrawLists(drawLists, patch->colLOD[colpos]); - } - - iter1 = drawLists->begin(); - for (row=0; rowheight; row+=2) - { - iter2 = iter1; - for (col=0; col+1width; col+=2) - { - iter1 = iter2; - colpos = ((row/2)*patch->width)+col; - rowpos = ((col/2)*patch->height)+row; - - Patch_AddBTreeToDrawListInOrder((*iter1), patch->rowLOD[rowpos]); - (*iter1)->push_back(patch->ctrl[col+2][row]); - - if (row+1 == patch->height) - continue; - - iter1++; - - Patch_TraverseColBTInOrder(iter1, patch->colLOD[colpos], patch->colLOD[colpos+1], patch->colLOD[colpos+2], patch->rowLOD[rowpos+1], patch->rowLOD[rowpos], 0.5, 0.25); - } - } - - patch->drawLists = drawLists; -} - - -void Patch_DeleteDrawLists(patchMesh_t *patch) -{ - drawLists_t *drawLists; - drawLists_t::iterator iter; - - if (patch->drawLists == NULL) - return; - - drawLists = (drawLists_t *)patch->drawLists; - - for (iter=drawLists->begin(); iter != drawLists->end(); iter++) - { - delete (*iter); - } - - delete drawLists; - patch->drawLists = NULL; -} - - -void Patch_DrawLODPatchMesh(patchMesh_t *patch) -{ - drawLists_t *drawLists; - - drawLists_t::iterator iterLists, iterListsNext; - drawList_t::iterator iterList, iterListNext; - - //int nGLState = g_pParentWnd->GetCamera()->Camera()->draw_glstate; - - if (patch->drawLists == NULL) - return; - - drawLists = (drawLists_t *)patch->drawLists; - - iterListsNext=drawLists->begin(); - iterListsNext++; - for (iterLists=drawLists->begin(); iterLists != drawLists->end() && iterListsNext != drawLists->end(); iterLists++, iterListsNext++) - { - // traverse two drawlists at once to draw a strip - //if (nGLState & DRAW_GL_LINE) - qglBegin(GL_QUAD_STRIP); - //else - // qglBegin(GL_TRIANGLE_STRIP); - for (iterList=(*iterLists)->begin(), iterListNext=(*iterListsNext)->begin(); iterList != (*iterLists)->end() && iterListNext != (*iterListsNext)->end(); iterList++, iterListNext++) - { - //if (g_PrefsDlg.m_bGLLighting) - qglNormal3fv((*iterList).normal); - //else if (bShade && !g_PrefsDlg.m_bDisplayLists) - // qglColor3f((*iterList).lightmap[0], (*iterList).lightmap[0], (*iterList).lightmap[0]); - - qglTexCoord2fv((*iterList).st); - qglVertex3fv((*iterList).xyz); - - //if (g_PrefsDlg.m_bGLLighting) - qglNormal3fv((*iterListNext).normal); - //else if (bShade && !g_PrefsDlg.m_bDisplayLists) - // qglColor3f((*iterListNext).lightmap[0], (*iterListNext).lightmap[0], (*iterListNext).lightmap[0]); - - qglTexCoord2fv((*iterListNext).st); - qglVertex3fv((*iterListNext).xyz); - } - qglEnd(); - } -/* -#ifdef _DEBUG - vec3_t vNormal; - for (iterLists=drawLists->begin(); iterLists != drawLists->end(); iterLists++) - { - qglBegin (GL_LINES); // draw normals - //qglColor3f(1,1,1); - for (iterList=(*iterLists)->begin(); iterList != (*iterLists)->end(); iterList++) - { - VectorAdd((*iterList).xyz, (*iterList).normal, vNormal); - qglVertex3fv ((*iterList).xyz); - qglVertex3fv (vNormal); - } - qglEnd (); - } - - Patch_DrawNormals(patch); - -#endif - */ -} - -/* -// fast memory-efficient ray-triangle intersection - MollerTrumbore97 - -#define EPSILON 0.000001 -#define CROSS(dest,v1,v2) {dest[0]=v1[1]*v2[2]-v1[2]*v2[1];dest[1]=v1[2]*v2[0]-v1[0]*v2[2];dest[2]=v1[0]*v2[1]-v1[1]*v2[0];} -#define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]) -#define SUB(dest,v1,v2) {dest[0]=v1[0]-v2[0];dest[1]=v1[1]-v2[1];dest[2]=v1[2]-v2[2];} - -int intersect_triangle(float orig[3], float dir[3], - float vert0[3], float vert1[3], float vert2[3], - double *t, double *u, double *v) -{ - double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; - double det,inv_det; - - // find vectors for two edges sharing vert0 - SUB(edge1, vert1, vert0); - SUB(edge2, vert2, vert0); - - // begin calculating determinant - also used to calculate U parameter - CROSS(pvec, dir, edge2); - - // if determinant is near zero, ray lies in plane of triangle - det = DOT(edge1, pvec); - -#ifdef TEST_CULL // define TEST_CULL if culling is desired - if (det < EPSILON) - return 0; - - // calculate distance from vert0 to ray origin - SUB(tvec, orig, vert0); - - // calculate U parameter and test bounds - *u = DOT(tvec, pvec); - if (*u < 0.0 || *u > det) - return 0; - - // prepare to test V parameter - CROSS(qvec, tvec, edge1); - - // calculate V parameter and test bounds - *v = DOT(dir, qvec); - if (*v < 0.0 || *u + *v > det) - return 0; - - // calculate t, scale parameters, ray intersects triangle - *t = DOT(edge2, qvec); - inv_det = 1.0 / det; - *t *= inv_det; - *u *= inv_det; - *v *= inv_det; -#else // the non-culling branch - if (det > -EPSILON && det < EPSILON) - return 0; - inv_det = 1.0 / det; - - // calculate distance from vert0 to ray origin - SUB(tvec, orig, vert0); - - // calculate U parameter and test bounds - *u = DOT(tvec, pvec) * inv_det; - if (*u < 0.0 || *u > 1.0) - return 0; - - // prepare to test V parameter - CROSS(qvec, tvec, edge1); - - // calculate V parameter and test bounds - *v = DOT(dir, qvec) * inv_det; - if (*v < 0.0 || *u + *v > 1.0) - return 0; - - // calculate t, ray intersects triangle - *t = DOT(edge2, qvec) * inv_det; -#endif - return 1; -} -*/ - -int Triangle_Ray(float orig[3], float dir[3], bool bCullBack, - float vert0[3], float vert1[3], float vert2[3], - double *t, double *u, double *v) -{ - float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; - double det,inv_det; - - /* find vectors for two edges sharing vert0 */ - VectorSubtract(vert1, vert0, edge1); - VectorSubtract(vert2, vert0, edge2); - - /* begin calculating determinant - also used to calculate U parameter */ - CrossProduct(dir, edge2, pvec); - - /* if determinant is near zero, ray lies in plane of triangle */ - det = DotProduct(edge1, pvec); - - if (bCullBack) - { - if (det < 0.000001) - return 0; - - // calculate distance from vert0 to ray origin - VectorSubtract(orig, vert0, tvec); - - // calculate U parameter and test bounds - *u = DotProduct(tvec, pvec); - if (*u < 0.0 || *u > det) - return 0; - - // prepare to test V parameter - CrossProduct(tvec, edge1, qvec); - - // calculate V parameter and test bounds - *v = DotProduct(dir, qvec); - if (*v < 0.0 || *u + *v > det) - return 0; - - // calculate t, scale parameters, ray intersects triangle - *t = DotProduct(edge2, qvec); - inv_det = 1.0 / det; - *t *= inv_det; - *u *= inv_det; - *v *= inv_det; - } - else - { - /* the non-culling branch */ - if (det > -0.000001 && det < 0.000001) - return 0; - inv_det = 1.0 / det; - - /* calculate distance from vert0 to ray origin */ - VectorSubtract(orig, vert0, tvec); - - /* calculate U parameter and test bounds */ - *u = DotProduct(tvec, pvec) * inv_det; - if (*u < 0.0 || *u > 1.0) - return 0; - - /* prepare to test V parameter */ - CrossProduct(tvec, edge1, qvec); - - /* calculate V parameter and test bounds */ - *v = DotProduct(dir, qvec) * inv_det; - if (*v < 0.0 || *u + *v > 1.0) - return 0; - - /* calculate t, ray intersects triangle */ - *t = DotProduct(edge2, qvec) * inv_det; - } - return 1; -} - -bool Patch_Ray(patchMesh_t *patch, vec3_t origin, vec3_t dir, double *t, double *u, double *v) -{ - drawLists_t *drawLists; - - drawLists_t::iterator iterLists, iterListsNext; - drawList_t::iterator i1, i2, i3, i4; - -// vec3_t tris[2][3]; - bool bIntersect = false; - float tBest = FLT_MAX; - - if (patch->drawLists == NULL) - return false; - - drawLists = (drawLists_t *)patch->drawLists; - - iterListsNext=drawLists->begin(); - iterListsNext++; - for (iterLists=drawLists->begin(); iterLists != drawLists->end() && iterListsNext != drawLists->end(); iterLists++, iterListsNext++) - { - // traverse two drawlists at once with two iterators each to triangulate - i1 = i3 = (*iterLists)->begin(); - i2 = i4 = (*iterListsNext)->begin(); - i3++; - i4++; - while (i3 != (*iterLists)->end() && i4 != (*iterListsNext)->end()) - { - if (Triangle_Ray(origin, dir, false, (*i1).xyz, (*i2).xyz, (*i3).xyz, t, u, v)) - { - bIntersect = true; - if (*t < tBest) - tBest = *t; - } - if (Triangle_Ray(origin, dir, false, (*i3).xyz, (*i4).xyz, (*i2).xyz, t, u, v)) - { - bIntersect = true; - if (*t < tBest) - tBest = *t; - } - i1++; - i2++; - i3++; - i4++; - } - } - if (bIntersect) - { - *t = tBest; - return true; - } - else - { - *t = 0; - return false; - } -} - -// spog - curve LOD stuff ends - -/* -================= -DrawPatchMesh -================= -*/ -void DrawPatchMesh(patchMesh_t *pm) -{ - if (g_PrefsDlg.m_bDisplayLists) - { - if (pm->bDirty || pm->nListID <= 0 || pm->LODUpdated) - { - if (pm->nListID <= 0) - pm->nListID = qglGenLists(1); - if (pm->nListID > 0) - { - qglNewList(pm->nListID, GL_COMPILE_AND_EXECUTE); - } - - Patch_DeleteDrawLists(pm); - Patch_CreateDrawLists(pm); - - Patch_DrawLODPatchMesh(pm); - - if (pm->nListID > 0) - { - qglEndList(); - } - - pm->bDirty = false; - pm->LODUpdated = false; - } - else - { - qglCallList(pm->nListID); - } - } - else - { - if (pm->bDirty || pm->LODUpdated) - { - Patch_DeleteDrawLists(pm); - Patch_CreateDrawLists(pm); - pm->bDirty = false; - pm->LODUpdated = false; - } - Patch_DrawLODPatchMesh(pm); - } -} - -/* -================= -DrawPatchControls -================= -*/ -void DrawPatchControls(patchMesh_t *pm) -{ - int i, j; - bool bSelectedPoints[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT]; - - bool bOverlay = pm->bOverlay; - - // bending - if (g_bPatchBendMode) - { - qglPointSize(6); - if (g_bPatchAxisOnRow) - { - qglColor3f(1, 0, 1); - if(!g_PrefsDlg.m_bGlPtWorkaround) - { - qglBegin(GL_POINTS); - for (i = 0; i < pm->width; i++) - { - qglVertex3fv(pm->ctrl[i][g_nPatchAxisIndex].xyz); - } - qglEnd(); - } - else - { - qglLineWidth(2.0); - qglBegin(GL_LINES); - for(i = 0; i < pm->width; i++) - { - DrawAlternatePoint(pm->ctrl[i][g_nPatchAxisIndex].xyz, 0); - } - qglEnd(); - qglLineWidth(1.0); - } - - if (g_nPatchBendState == BEND_SELECT_EDGE || g_nPatchBendState == BEND_BENDIT || g_nPatchBendState == BEND_SELECT_ORIGIN) - { - if(!g_PrefsDlg.m_bGlPtWorkaround) - { - qglColor3f(0, 0, 1); - qglBegin(GL_POINTS); - if (g_nPatchBendState == BEND_SELECT_ORIGIN) - { - qglVertex3fv(g_vBendOrigin); - } - else - { - for (i = 0; i < pm->width; i++) - { - if (g_bPatchLowerEdge) - { - for (j = 0; j < g_nPatchAxisIndex; j++) - qglVertex3fv(pm->ctrl[i][j].xyz); - } - else - { - for (j = pm->height-1; j > g_nPatchAxisIndex; j--) - qglVertex3fv(pm->ctrl[i][j].xyz); - } - } - } - qglEnd(); - } - else { - qglColor3f(0, 0, 1); - qglLineWidth(2.0); - qglBegin(GL_LINES); - if(g_nPatchBendState == BEND_SELECT_ORIGIN) - { - DrawAlternatePoint(g_vBendOrigin, 0); - } - else - { - for(i = 0; i < pm->width; i++) - { - if(g_bPatchLowerEdge) - { - for(j = 0; j < g_nPatchAxisIndex; j++) - { - DrawAlternatePoint(pm->ctrl[i][j].xyz, 0); - } - } - else - { - for (j = pm->height-1; j > g_nPatchAxisIndex; j--) - { - DrawAlternatePoint(pm->ctrl[i][j].xyz, 0); - } - } - } - } - qglEnd(); - qglLineWidth(1.0); - } - } - } - else - { - if(!g_PrefsDlg.m_bGlPtWorkaround) - { - qglColor3f(1, 0, 1); - qglBegin(GL_POINTS); - for (i = 0; i < pm->height; i++) - { - qglVertex3fv(pm->ctrl[g_nPatchAxisIndex][i].xyz); - } - qglEnd(); - } - else { - qglColor3f(1, 0, 1); - qglLineWidth(2.0); - qglBegin(GL_LINES); - for(i = 0; i < pm->height; i++) - { - DrawAlternatePoint(pm->ctrl[g_nPatchAxisIndex][i].xyz, 0); - } - qglEnd(); - qglLineWidth(1.0); - } - - if (g_nPatchBendState == BEND_SELECT_EDGE || g_nPatchBendState == BEND_BENDIT || g_nPatchBendState == BEND_SELECT_ORIGIN) - { - if(!g_PrefsDlg.m_bGlPtWorkaround) - { - qglColor3f(0, 0, 1); - qglBegin(GL_POINTS); - for (i = 0; i < pm->height; i++) - { - if (g_nPatchBendState == BEND_SELECT_ORIGIN) - { - qglVertex3fv(pm->ctrl[g_nBendOriginIndex][i].xyz); - } - else - { - if (g_bPatchLowerEdge) - { - for (j = 0; j < g_nPatchAxisIndex; j++) - qglVertex3fv(pm->ctrl[j][i].xyz); - } - else - { - for (j = pm->width-1; j > g_nPatchAxisIndex; j--) - qglVertex3fv(pm->ctrl[j][i].xyz); - } - } - } - qglEnd(); - } - else { - qglColor3f(0, 0, 1); - qglLineWidth(2.0); - qglBegin(GL_LINES); - for(i = 0; i < pm->height; i++) - { - if(g_nPatchBendState == BEND_SELECT_ORIGIN) - { - DrawAlternatePoint(pm->ctrl[g_nBendOriginIndex][i].xyz, 0); - } - else - { - if(g_bPatchLowerEdge) - { - for(j = 0; j < g_nPatchAxisIndex; j++) - { - DrawAlternatePoint(pm->ctrl[j][i].xyz, 0); - } - } - else - { - for(j = pm->width-1; j > g_nPatchAxisIndex; j--) - { - DrawAlternatePoint(pm->ctrl[j][i].xyz, 0); - } - } - } - } - qglEnd(); - qglLineWidth(1.0); - } - } - } - } - else - { - //qglDisable(GL_TEXTURE_2D); // stops point colours being multiplied by texture colour.. - //draw CV lattice - could be made optional - //qglDisable( GL_CULL_FACE ); - // qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); - qglEnable (GL_POLYGON_OFFSET_LINE); - if (g_PrefsDlg.m_bNoStipple == FALSE) - qglDisable (GL_LINE_STIPPLE); - qglLineWidth (1); - qglColor3f(1.0f, 0.75f, 0.0f); - for ( i = 0 ; i+1 < pm->width ; i++ ) - { - qglBegin(GL_QUAD_STRIP); - for ( j = 0 ; j < pm->height ; j++ ) - { - qglVertex3fv(pm->ctrl[i][j].xyz); - qglVertex3fv(pm->ctrl[i+1][j].xyz); - } - qglEnd(); - } - qglDisable (GL_POLYGON_OFFSET_LINE); - //if (g_PrefsDlg.m_bNoStipple == FALSE) - // qglEnable (GL_LINE_STIPPLE); - - // draw selection handles - if(!g_PrefsDlg.m_bGlPtWorkaround) - { - qglPointSize(6); - qglBegin(GL_POINTS); - for ( i = 0 ; i < pm->width ; i++ ) - { - for ( j = 0 ; j < pm->height ; j++ ) - { - if (PointInMoveList(pm->ctrl[i][j].xyz) != -1) - { - bSelectedPoints[i][j] = true; - } - else - { - bSelectedPoints[i][j] = false; - if (i & 0x01 || j & 0x01) - qglColor3f(1, 0, 1); - else - qglColor3f(0, 1, 0); - - qglVertex3fv(pm->ctrl[i][j].xyz); - } - } - } - qglColor3f(0, 0, 1); - for ( i = 0 ; i < pm->width ; i++ ) - { - for ( j = 0 ; j < pm->height ; j++ ) - { - if (bSelectedPoints[i][j]) - qglVertex3fv(pm->ctrl[i][j].xyz); - } - } - qglEnd(); - } - else - { - qglLineWidth(2.0); - qglBegin(GL_LINES); - for(i = 0; i < pm->width; i++) - { - for(j = 0; j < pm->height; j++) - { - if(PointInMoveList(pm->ctrl[i][j].xyz) != -1) - { - bSelectedPoints[i][j] = true; - } - else - { - bSelectedPoints[i][j] = false; - if(i & 0x01 || j & 0x01) - qglColor3f(1, 0, 1); - else - qglColor3f(0, 1, 0); - - // draw verts - DrawAlternatePoint(pm->ctrl[i][j].xyz, 0); - } - } - } - qglColor3f(0, 0, 1); - for(i = 0; i < pm->width; i++) - { - for(j = 0; j < pm->height; j++) - { - if(bSelectedPoints[i][j]) - { - // draw verts - DrawAlternatePoint(pm->ctrl[i][j].xyz, 0); - } - } - } - qglEnd(); - qglLineWidth(1.0); - } - } - if (bOverlay) - { - if(!g_PrefsDlg.m_bGlPtWorkaround) - { - qglPointSize(6); - qglBegin(GL_POINTS); - for ( i = 0 ; i < pm->width ; i++ ) - { - for ( j = 0 ; j < pm->height ; j++ ) - { - if (i & 0x01 || j & 0x01) - qglColor3f(1, 0, 1); - else - qglColor3f(0, 1, 0); - qglVertex3fv(pm->ctrl[i][j].xyz); - } - } - qglEnd(); - } - else - { - qglLineWidth(2.0); - qglBegin(GL_LINES); - for ( i = 0 ; i < pm->width ; i++ ) - { - for ( j = 0 ; j < pm->height ; j++ ) - { - if (i & 0x01 || j & 0x01) - qglColor3f(1, 0, 1); - else - qglColor3f(0, 1, 0); - // draw verts - DrawAlternatePoint(pm->ctrl[i][j].xyz, 0); - } - } - qglEnd(); - qglLineWidth(1.0); - } - } - //qglPopAttrib(); -} - -/* -================== -Patch_DrawXY -================== -*/ -void Patch_DrawXY(patchMesh_t *pm) -{ - qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); - - if (pm->bSelected) - { - qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES]); - if (g_PrefsDlg.m_bNoStipple == FALSE) - qglEnable (GL_LINE_STIPPLE); - qglLineWidth (2); - } - - DrawPatchMesh(pm); - - if ( (pm->bSelected && (g_qeglobals.d_select_mode == sel_curvepoint - || g_qeglobals.d_select_mode == sel_area - || g_bPatchBendMode)) - || pm->bOverlay ) - DrawPatchControls(pm); -} - -/* -================== -Patch_DrawCam -================== -*/ -void Patch_DrawCam(patchMesh_t *pm) -{ - qglPushAttrib(GL_ALL_ATTRIB_BITS); // save the current state - - if (g_bPatchWireFrame) - { - qglDisable( GL_CULL_FACE ); - qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); - qglDisable(GL_TEXTURE_2D); - if (g_PrefsDlg.m_bGLLighting) - qglDisable(GL_LIGHTING); - - DrawPatchMesh(pm); - - //if (g_PrefsDlg.m_bGLLighting) - // qglEnable(GL_LIGHTING); - //qglEnable( GL_CULL_FACE ); - } - else - { - qglDisable(GL_CULL_FACE); - qglBindTexture (GL_TEXTURE_2D, pm->d_texture->texture_number); - qglPolygonMode (GL_FRONT, GL_FILL); - qglPolygonMode (GL_BACK, GL_LINE); - - if (pm->pShader->getTrans() < 1.0f) - { - qglEnable(GL_BLEND); - qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - qglColor4f(pm->d_texture->color[0], pm->d_texture->color[1], pm->d_texture->color[2], pm->pShader->getTrans()); - } - - DrawPatchMesh(pm); // both sides - } - - qglPopAttrib(); // restore saved state -} - -void ConvexHullForSection( float section[2][4][7] ) { -} - -void BrushesForSection( float section[2][4][7] ) { -} - -/* -================ -Patch_BuildPoints -================ -*/ -void Patch_BuildPoints (brush_t *b) -{ - face_t *f; - b->patchBrush = false; - for (f=b->brush_faces ; f ; f=f->next) - { - if (f->texdef.flags & SURF_PATCH) - { - b->patchBrush = true; - //vec3_t vMin, vMax; - //Patch_CalcBounds(&patchMeshes[b->nPatchID], vMin, vMax); - //VectorCopy(vMin, b->mins); - //VectorCopy(vMax, b->maxs); - break; - } - } -} - -/* -================== -Patch_Move -================== -*/ -void Patch_Move(patchMesh_t *pm, const vec3_t vMove, bool bRebuild) -{ - pm->bDirty = true; - for (int w = 0; w < pm->width; w++) - { - for (int h = 0; h < pm->height; h++) - { - VectorAdd(pm->ctrl[w][h].xyz, vMove, pm->ctrl[w][h].xyz); - } - } - // bRebuild is never true - if (bRebuild) - { - vec3_t vMin, vMax; - Patch_CalcBounds(pm, vMin, vMax); - //Brush_RebuildBrush(patchMeshes[n].pSymbiot, vMin, vMax); - } - UpdatePatchInspector(); - -} - -/* -================== -Patch_ApplyMatrix -================== -*/ -void Patch_ApplyMatrix(patchMesh_t *p, const vec3_t vOrigin, const vec3_t vMatrix[3], bool bSnap) -{ - vec3_t vTemp; - - for (int w = 0; w < p->width; w++) - { - for (int h = 0; h < p->height; h++) - { - if (((g_qeglobals.d_select_mode == sel_curvepoint && g_qeglobals.d_num_move_points != 0) || g_bPatchBendMode) - && PointInMoveList(p->ctrl[w][h].xyz) == -1) // snap selected points only, if selected - continue; - VectorSubtract (p->ctrl[w][h].xyz, vOrigin, vTemp); - for (int j = 0; j < 3; j++) - { - p->ctrl[w][h].xyz[j] = DotProduct(vTemp, vMatrix[j]) + vOrigin[j]; - if (bSnap) - { - p->ctrl[w][h].xyz[j] = floor(p->ctrl[w][h].xyz[j] + 0.5); - } - } - } - } - vec3_t vMin, vMax; - Patch_CalcBounds(p, vMin, vMax); - Brush_RebuildBrush(p->pSymbiot, vMin, vMax); -} - -/* -================== -Patch_EditPatch -================== -*/ -void Patch_EditPatch() -{ - //--patchMesh_t* p = &patchMeshes[n]; - g_qeglobals.d_numpoints = 0; - g_qeglobals.d_num_move_points = 0; - - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - patchMesh_t* p = pb->pPatch; - for ( int i = 0 ; i < p->width ; i++ ) - { - for ( int j = 0 ; j < p->height ; j++ ) - { - VectorCopy (p->ctrl[i][j].xyz, g_qeglobals.d_points[g_qeglobals.d_numpoints]); - if (g_qeglobals.d_numpoints < MAX_POINTS-1) - { - g_qeglobals.d_numpoints++; - } - } - } - } - } - g_qeglobals.d_select_mode = sel_curvepoint; - //--g_nSelectedPatch = n; -} - - - -/* -================== -Patch_Deselect -================== -*/ -//FIXME: need all sorts of asserts throughout a lot of this crap -void Patch_Deselect() -{ - //--g_nSelectedPatch = -1; - g_qeglobals.d_select_mode = sel_brush; - - for (brush_t *b = selected_brushes.next ; b != &selected_brushes ; b=b->next) - { - if (b->patchBrush) - { - b->pPatch->bSelected = false; - } - } - - //for (int i = 0; i < numPatchMeshes; i++) - // patchMeshes[i].bSelected = false; - - if (g_bPatchBendMode) - Patch_BendToggle(); -// if (g_bPatchInsertMode) -// Patch_InsDelToggle(); -} - - -/* -================== -Patch_Select -================== -*/ -void Patch_Select(patchMesh_t *p) -{ - // maintained for point manip.. which i need to fix as this - // is pf error prone - //--g_nSelectedPatch = n; - p->bSelected = true; -} - - -/* -================== -Patch_Deselect -================== -*/ -void Patch_Deselect(patchMesh_t *p) -{ - p->bSelected = false; -} - - -/* -================== -Patch_Delete -================== -*/ -extern BTNode_t *BTree_Delete(BTNode_t *pBT); -extern BTListList_t *BTree_DeleteListFromList(BTListList_t *pBTListList); - -void Patch_Delete(patchMesh_t *p) -{ - if (p->pSymbiot) // Hydra - added a check to prevent access violations. - { - p->pSymbiot->pPatch = NULL; - p->pSymbiot->patchBrush = false; - } - - // spog - free dynamically allocated memory used by LODs - int rowcount = ((MAX_PATCH_WIDTH-1)/2) * MAX_PATCH_HEIGHT; - int colcount = ((MAX_PATCH_HEIGHT-1)/2) * MAX_PATCH_WIDTH; - int i; - for (i=0; irowLOD[i] = BTree_Delete(p->rowLOD[i]); - for (i=0; icolLOD[i] = BTree_Delete(p->colLOD[i]); - - // delete display list associated with patch - if (p->nListID != -1) - qglDeleteLists (p->nListID, 1); // list#, number of lists - - // delete LOD drawLists - Patch_DeleteDrawLists(p); - - - free(p); - p = NULL; - - - UpdatePatchInspector(); -} - - -/* -================== -Patch_Scale -================== -*/ -void Patch_Scale(patchMesh_t *p, const vec3_t vOrigin, const vec3_t vAmt, bool bRebuild) -{ - - for (int w = 0; w < p->width; w++) - { - for (int h = 0; h < p->height; h++) - { - if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1) - continue; - for (int i=0 ; i<3 ; i++) - { - p->ctrl[w][h].xyz[i] -= vOrigin[i]; - p->ctrl[w][h].xyz[i] *= vAmt[i]; - p->ctrl[w][h].xyz[i] += vOrigin[i]; - } - } - } - if (bRebuild) - { - vec3_t vMin, vMax; - Patch_CalcBounds(p, vMin, vMax); - Brush_RebuildBrush(p->pSymbiot, vMin, vMax); - } - UpdatePatchInspector(); -} - - -/* -================== -Patch_SetView -================== -*/ -void Patch_SetView(int n) -{ - g_bSameView = (n == g_nPatchClickedView); - g_nPatchClickedView = n; -} - - -/* -================== -Patch_SetTexture -================== -*/ -// FIXME: need array validation throughout -void Patch_SetTexture(patchMesh_t *p, texdef_t *tex_def, IPluginTexdef* pPlugTexdef) -{ - // NOTE: I don't know for sure if this happens - if (p->pShader) - p->pShader->DecRef(); - p->pShader = QERApp_Shader_ForName(tex_def->GetName()); - p->pShader->IncRef(); - p->d_texture = p->pShader->getTexture(); - - UpdatePatchInspector(); -} - - -/* -================== -Patch_DragScale -================== -*/ -bool Patch_DragScale(patchMesh_t *p, vec3_t vAmt, vec3_t vMove) -{ - vec3_t vMin, vMax, vScale, vTemp, vMid; - int i; - - Patch_CalcBounds(p, vMin, vMax); - - VectorSubtract(vMax, vMin, vTemp); - - // if we are scaling in the same dimension the patch has no depth - for (i = 0; i < 3; i ++) - { - if (vTemp[i] == 0 && vMove[i] != 0) - { - //Patch_Move(n, vMove, true); - return false; - } - } - - for (i=0 ; i<3 ; i++) - vMid[i] = (vMin[i] + ((vMax[i] - vMin[i]) / 2)); - - for (i = 0; i < 3; i++) - { - if (vAmt[i] != 0) - { - vScale[i] = 1.0 + vAmt[i] / vTemp[i]; - } - else - { - vScale[i] = 1.0; - } - } - - Patch_Scale(p, vMid, vScale, false); - - VectorSubtract(vMax, vMin, vTemp); - - Patch_CalcBounds(p, vMin, vMax); - - VectorSubtract(vMax, vMin, vMid); - - VectorSubtract(vMid, vTemp, vTemp); - - VectorScale(vTemp, 0.5, vTemp); - - // abs of both should always be equal - if (!VectorCompare(vMove, vAmt)) - { - for (i = 0; i < 3; i++) - { - if (vMove[i] != vAmt[i]) - vTemp[i] = -(vTemp[i]); - } - } - - Patch_Move(p, vTemp); - return true; -} - -/* -================== -Patch_InsertColumn -================== -*/ -void Patch_InsertColumn(patchMesh_t *p, bool bAdd) -{ - int w, h, i, width; - vec3_t vTemp; - float stTemp[2]; - - if (p->width + 2 >= MAX_PATCH_WIDTH) - return; - - // check for selected column points - for (h = 0; h < p->height; h++) - { - for (w = 1; w < p->width; w+=2) - if (PointInMoveList(p->ctrl[w][h].xyz) != -1) - break; - if (w < p->width) - break; - for (w = 0; w < p->width; w+=2) - if (PointInMoveList(p->ctrl[w][h].xyz) != -1) - break; - if (w < p->width) - break; - } - - if (w >= p->width) - { - if (bAdd) w=p->width-1; - else w=2; - } - else if (w==0) w=2; - else if (w%2) w++; - - // add columns at w - for (h = 0; h < p->height; h++) - { - for (width = p->width-1; width > w; width--) - memcpy(&p->ctrl[width+2][h],&p->ctrl[width][h], sizeof(drawVert_t)); - - // set two new column points - memcpy(&p->ctrl[w+2][h],&p->ctrl[w][h], sizeof(drawVert_t)); - memcpy(&p->ctrl[w+1][h],&p->ctrl[w-1][h], sizeof(drawVert_t)); - - for (i=0; i<3; i++) // xyz - { - vTemp[i] = p->ctrl[w][h].xyz[i] - p->ctrl[w-1][h].xyz[i]; - p->ctrl[w+1][h].xyz[i] = p->ctrl[w+1][h].xyz[i] + (vTemp[i] / 2); - - vTemp[i] = p->ctrl[w-2][h].xyz[i] - p->ctrl[w-1][h].xyz[i]; - p->ctrl[w-1][h].xyz[i] = p->ctrl[w-1][h].xyz[i] + (vTemp[i] / 2); - - vTemp[i] = p->ctrl[w+1][h].xyz[i] - p->ctrl[w-1][h].xyz[i]; - p->ctrl[w][h].xyz[i] = p->ctrl[w-1][h].xyz[i] + (vTemp[i] / 2); - } - for (i=0; i<2; i++) // st - { - stTemp[i] = p->ctrl[w][h].st[i] - p->ctrl[w-1][h].st[i]; - p->ctrl[w+1][h].st[i] = p->ctrl[w+1][h].st[i] + (stTemp[i] / 2); - - stTemp[i] = p->ctrl[w-2][h].st[i] - p->ctrl[w-1][h].st[i]; - p->ctrl[w-1][h].st[i] = p->ctrl[w-1][h].st[i] + (stTemp[i] / 2); - - stTemp[i] = p->ctrl[w+1][h].st[i] - p->ctrl[w-1][h].st[i]; - p->ctrl[w][h].st[i] = p->ctrl[w-1][h].st[i] + (stTemp[i] / 2); - } - } - - p->width += 2; - // deselect all points to keep things neat - if (g_qeglobals.d_select_mode == sel_curvepoint) - Patch_EditPatch(); - - UpdatePatchInspector(); -} - -/* -================== -Patch_InsertRow -================== -*/ - -void Patch_InsertRow(patchMesh_t *p, bool bAdd) -{ - int h, w, i, height; - vec3_t vTemp; - float stTemp[2]; - - if (p->height + 2 >= MAX_PATCH_HEIGHT) - return; - - // check for selected row points - for (w = 0; w < p->width; w++) - { - for (h = 1; h < p->height; h+=2) - if (PointInMoveList(p->ctrl[w][h].xyz) != -1) - break; - if (h < p->height) - break; - for (h = 0; h < p->height; h+=2) - if (PointInMoveList(p->ctrl[w][h].xyz) != -1) - break; - if (h < p->height) - break; - } - if (h >= p->height) - { - if (bAdd) h=p->height-1; - else h=2; - } - else if (h==0) h=2; - else if (h%2) h++; - - // add rows at h - for (w = 0; w < p->width; w++) - { - for (height = p->height-1; height > h; height--) - memcpy(&p->ctrl[w][height+2],&p->ctrl[w][height], sizeof(drawVert_t)); - - // set two new row points - memcpy(&p->ctrl[w][h+2],&p->ctrl[w][h], sizeof(drawVert_t)); - memcpy(&p->ctrl[w][h+1],&p->ctrl[w][h-1], sizeof(drawVert_t)); - - for (i=0; i<3; i++) // xyz - { - vTemp[i] = p->ctrl[w][h].xyz[i] - p->ctrl[w][h-1].xyz[i]; - p->ctrl[w][h+1].xyz[i] = p->ctrl[w][h+1].xyz[i] + (vTemp[i] / 2); - - vTemp[i] = p->ctrl[w][h-2].xyz[i] - p->ctrl[w][h-1].xyz[i]; - p->ctrl[w][h-1].xyz[i] = p->ctrl[w][h-1].xyz[i] + (vTemp[i] / 2); - - vTemp[i] = p->ctrl[w][h+1].xyz[i] - p->ctrl[w][h-1].xyz[i]; - p->ctrl[w][h].xyz[i] = p->ctrl[w][h-1].xyz[i] + (vTemp[i] / 2); - } - for (i=0; i<2; i++) // st - { - stTemp[i] = p->ctrl[w][h].st[i] - p->ctrl[w][h-1].st[i]; - p->ctrl[w][h+1].st[i] = p->ctrl[w][h+1].st[i] + (stTemp[i] / 2); - - stTemp[i] = p->ctrl[w][h-2].st[i] - p->ctrl[w][h-1].st[i]; - p->ctrl[w][h-1].st[i] = p->ctrl[w][h-1].st[i] + (stTemp[i] / 2); - - stTemp[i] = p->ctrl[w][h+1].st[i] - p->ctrl[w][h-1].st[i]; - p->ctrl[w][h].st[i] = p->ctrl[w][h-1].st[i] + (stTemp[i] / 2); - } - } - - p->height += 2; - // deselect all points to keep things neat - if (g_qeglobals.d_select_mode == sel_curvepoint) - Patch_EditPatch(); - - UpdatePatchInspector(); -} - -/* -================== -Patch_RemoveRow -================== -*/ -void Patch_RemoveRow(patchMesh_t *p, bool bFirst) -{ - int w, h, i, height; - vec3_t vTemp; - float stTemp[2]; - bool bExtrapolate = true; - - if (p->height <= MIN_PATCH_HEIGHT) - return; - - for (w = 0; w < p->width; w++) - { - for (h = 0; h < p->height; h+=2) - if (PointInMoveList(p->ctrl[w][h].xyz) != -1) - break; - if (h < p->height) - break; - for (h = 1; h < p->height; h+=2) - if (PointInMoveList(p->ctrl[w][h].xyz) != -1) - break; - if (h < p->height) - break; - } - - if (h >= p->height) - { - bExtrapolate = false; - if (bFirst) h=p->height-3; - else h=2; - } - else if (h <= 0) h=2; - else if (h > p->height-3) h = p->height-3; - else if (h%2) h++; - - p->height -= 2; - - for (w = 0; w < p->width; w++) - { - if (bExtrapolate) - { - for (i = 0; i < 3; i++) // xyz - { - vTemp[i] = p->ctrl[w][h+2].xyz[i] - p->ctrl[w][h-2].xyz[i]; - p->ctrl[w][h-1].xyz[i] = p->ctrl[w][h-2].xyz[i] + (vTemp[i] / 2); - - vTemp[i] = p->ctrl[w][h].xyz[i] - p->ctrl[w][h-1].xyz[i]; - p->ctrl[w][h-1].xyz[i] = p->ctrl[w][h-1].xyz[i] + (vTemp[i] * 2); - } - - for (i = 0; i < 2; i++) // st - { - stTemp[i] = p->ctrl[w][h+2].st[i] - p->ctrl[w][h-2].st[i]; - p->ctrl[w][h-1].st[i] = p->ctrl[w][h-2].st[i] + (stTemp[i] / 2); - - stTemp[i] = p->ctrl[w][h].st[i] - p->ctrl[w][h-1].st[i]; - p->ctrl[w][h-1].st[i] = p->ctrl[w][h-1].st[i] + (stTemp[i] * 2); - } - } - else - { - if (!bFirst) - continue; - else h=0; - } - for (height = h; height < p->height; height++) - memcpy(&p->ctrl[w][height], &p->ctrl[w][height+2], sizeof(drawVert_t)); - } - // deselect all points to keep things neat - if (g_qeglobals.d_select_mode == sel_curvepoint) - Patch_EditPatch(); - - UpdatePatchInspector(); -} - -/* -================== -Patch_RemoveColumn -================== -*/ -void Patch_RemoveColumn(patchMesh_t *p, bool bFirst) -{ - int w, h, i, width; - vec3_t vTemp; - float stTemp[2]; - bool bExtrapolate = true; - - if (p->width <= MIN_PATCH_WIDTH) - return; - - for (h = 0; h < p->height; h++) - { - for (w = 0; w < p->width; w+=2) - if (PointInMoveList(p->ctrl[w][h].xyz) != -1) - break; - if (w < p->width) - break; - for (w = 1; w < p->width; w+=2) - if (PointInMoveList(p->ctrl[w][h].xyz) != -1) - break; - if (w < p->width) - break; - } - - if (w >= p->width) - { - bExtrapolate = false; - if (bFirst) w=p->width-3; - else w=2; - } - else if (w<=0) w=2; - else if (w > p->width-3) w = p->width-3; - else if (w%2) w++; - - p->width -= 2; - - for (h = 0; h < p->height; h++) - { - if (bExtrapolate) - { - for (i = 0; i < 3; i++) // xyz - { - vTemp[i] = p->ctrl[w+2][h].xyz[i] - p->ctrl[w-2][h].xyz[i]; - p->ctrl[w-1][h].xyz[i] = p->ctrl[w-2][h].xyz[i] + (vTemp[i] / 2); - - vTemp[i] = p->ctrl[w][h].xyz[i] - p->ctrl[w-1][h].xyz[i]; - p->ctrl[w-1][h].xyz[i] = p->ctrl[w-1][h].xyz[i] + (vTemp[i] * 2); - } - - for (i = 0; i < 2; i++) // st - { - stTemp[i] = p->ctrl[w+2][h].st[i] - p->ctrl[w-2][h].st[i]; - p->ctrl[w-1][h].st[i] = p->ctrl[w-2][h].st[i] + (stTemp[i] / 2); - - stTemp[i] = p->ctrl[w][h].st[i] - p->ctrl[w-1][h].st[i]; - p->ctrl[w-1][h].st[i] = p->ctrl[w-1][h].st[i] + (stTemp[i] * 2); - } - } - else - { - if (!bFirst) - continue; - else w=0; - } - - for (width = w; width < p->width; width++) - memcpy(&p->ctrl[width][h], &p->ctrl[width+2][h], sizeof(drawVert_t)); - } - // deselect all points to keep things neat - if (g_qeglobals.d_select_mode == sel_curvepoint) - Patch_EditPatch(); - - UpdatePatchInspector(); -} - -/* -================== -Patch_AdjustColumns -================== -*/ -/* -void Patch_AdjustColumns(patchMesh_t *p, int nCols) -{ - vec3_t vTemp, vTemp2; - int i, w, h; - - if (nCols & 0x01 || p->width + nCols < 3 || p->width + nCols > MAX_PATCH_WIDTH) - return; - - // add in column adjustment - p->width += nCols; - - for (h = 0; h < p->height; h++) - { - // for each column, we need to evenly disperse p->width number - // of points across the old bounds - - // calc total distance to interpolate - VectorSubtract(p->ctrl[p->width - 1 - nCols][h].xyz, p->ctrl[0][h].xyz, vTemp); - - // amount per cycle - for (i = 0; i < 3; i ++) - { - vTemp2[i] = vTemp[i] / (p->width - 1); - } - - // move along - for (w = 0; w < p->width-1; w++) - { - VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w+1][h].xyz); - } - - } - for ( w = 0 ; w < p->width ; w++ ) - { - for ( h = 0 ; h < p->height ; h++ ) - { - p->ctrl[w][h].st[0] = 4 * (float)w / (p->width - 1); - p->ctrl[w][h].st[1] = 4 * (float)h / (p->height - 1); - } - } - UpdatePatchInspector(); -} -*/ - -/* -================== -Patch_AdjustRows -================== -*/ -/* -void Patch_AdjustRows(patchMesh_t *p, int nRows) -{ - vec3_t vTemp, vTemp2; - int i, w, h; - - if (nRows & 0x01 || p->height + nRows < 3 || p->height + nRows > MAX_PATCH_HEIGHT) - return; - - // add in column adjustment - p->height += nRows; - - for (w = 0; w < p->width; w++) - { - // for each row, we need to evenly disperse p->height number - // of points across the old bounds - - // calc total distance to interpolate - VectorSubtract(p->ctrl[w][p->height - 1 - nRows].xyz, p->ctrl[w][0].xyz, vTemp); - - //vTemp[0] = vTemp[1] = vTemp[2] = 0; - //for (h = 0; h < p->height - nRows; h ++) - //{ - // VectorAdd(vTemp, p->ctrl[w][h], vTemp); - //} - - // amount per cycle - for (i = 0; i < 3; i ++) - { - vTemp2[i] = vTemp[i] / (p->height - 1); - } - - // move along - for (h = 0; h < p->height-1; h++) - { - VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w][h+1].xyz); - } - - } - for ( w = 0 ; w < p->width ; w++ ) - { - for ( h = 0 ; h < p->height ; h++ ) - { - p->ctrl[w][h].st[0] = 4 * (float)w / (p->width - 1); - p->ctrl[w][h].st[1] = 4 * (float)h / (p->height - 1); - } - } - UpdatePatchInspector(); -} -*/ - -/* -================== -Patch_DisperseRows -================== -*/ - -void Patch_DisperseRows() -{ - vec3_t vTemp, vTemp2; - int i, w, h; - - - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - patchMesh_t *p = pb->pPatch; - Patch_Rebuild(p); - for (w = 0; w < p->width; w++) - { - // for each row, we need to evenly disperse p->height number - // of points across the old bounds - - // calc total distance to interpolate - VectorSubtract(p->ctrl[w][p->height - 1].xyz, p->ctrl[w][0].xyz, vTemp); - - //vTemp[0] = vTemp[1] = vTemp[2] = 0; - //for (h = 0; h < p->height - nRows; h ++) - //{ - // VectorAdd(vTemp, p->ctrl[w][h], vTemp); - //} - - // amount per cycle - for (i = 0; i < 3; i ++) - { - vTemp2[i] = vTemp[i] / (p->height - 1); - } - - // move along - for (h = 0; h < p->height-1; h++) - { - VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w][h+1].xyz); - } - Patch_Naturalize(p); - - } - } - } - UpdatePatchInspector(); -} - -/* -================== -Patch_DisperseIntermediateRows -================== -*/ - -void Patch_DisperseIntermediateRows() -{ - vec3_t vTemp, vTemp2; - int i, w, h; - - - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - patchMesh_t *p = pb->pPatch; - Patch_Rebuild(p); - for (w = 0; w < p->width; w++) - { - // move along - for (h = 0; h < p->height; h+=2) - { - // calc distance to interpolate - VectorSubtract(p->ctrl[w][h+2].xyz, p->ctrl[w][h].xyz, vTemp); - - // halve distance - for (i = 0; i < 3; i ++) - { - vTemp2[i] = vTemp[i] / 2; - } - - // move control points - VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w][h+1].xyz); - } - } - } - } - UpdatePatchInspector(); -} - -/* -================== -Patch_DisperseIntermediateColumns -================== -*/ -void Patch_DisperseIntermediateColumns() -{ - vec3_t vTemp, vTemp2; - int i, w, h; - - - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - patchMesh_t *p = pb->pPatch; - Patch_Rebuild(p); - for (h = 0; h < p->height; h++) - { - // move along - for (w = 0; w < p->width; w+=2) - { - // calc distance to interpolate - VectorSubtract(p->ctrl[w+2][h].xyz, p->ctrl[w][h].xyz, vTemp); - - // halve distance - for (i = 0; i < 3; i ++) - { - vTemp2[i] = vTemp[i] / 2; - } - - // move control points - VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w+1][h].xyz); - } - } - } - } - UpdatePatchInspector(); -} - - - -/* -================== -Patch_AdjustSelected -================== -*/ -void Patch_AdjustSelected(bool bInsert, bool bColumn, bool bFlag) -{ - bool bUpdate = false; - for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - if (bInsert) - { - if (bColumn) - { - Patch_InsertColumn(pb->pPatch, bFlag); - } - else - { - Patch_InsertRow(pb->pPatch, bFlag); - } - } - else - { - if (bColumn) - { - Patch_RemoveColumn(pb->pPatch, bFlag); - } - else - { - Patch_RemoveRow(pb->pPatch, bFlag); - } - } - bUpdate = true; - vec3_t vMin, vMax; - patchMesh_t *p = pb->pPatch; - Patch_CalcBounds(p, vMin, vMax); - Brush_RebuildBrush(p->pSymbiot, vMin, vMax); - pb->pPatch->bDirty = true; // rebuild LOD trees and their normals - } - } - if (bUpdate) - { - Sys_UpdateWindows(W_ALL); - } -} - - -/* -================== -Patch_AdjustSelectedRowCols -================== -*/ -/* -void Patch_AdjustSelectedRowCols(int nRows, int nCols) -{ - for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - Patch_InsertColumn(pb->pPatch, false); - if (nRows != 0) - { - Patch_AdjustRows(pb->pPatch, nRows); - } - - if (nCols != 0) - { - Patch_AdjustColumns(pb->pPatch, nCols); - } - } - } - UpdatePatchInspector(); -} -*/ - -/* -================= -CheckName -temporary stuff, detect potential problems when saving the texture name -will correct the patch on the fly if problem detected -================= -*/ -/*! -\todo performance issue with CheckName calls -don't call this too much, only when absolutely necessary -strategies that call here too much are known to be slow -patch 84 to bug 253 adds an additionnal check for textures/ -*/ -void CheckName( patchMesh_t *p, char *pname ) -{ - if(strncmp(p->pShader->getName(), "textures/", 9) != 0) - p->pShader = QERApp_Shader_ForName(SHADER_NOT_FOUND); - - // some manage to get long filename textures (with spaces) in their maps - if (strchr( p->pShader->getName(), ' ' )) - { - char Msg1[1024]; - sprintf( Msg1, "Can't save texture with spaces in name. Rename %s\nNOTE: This message may popup several times .. once for each buggy face detected.", p->pShader->getName() ); - Sys_Printf("%s\n", Msg1 ); - gtk_MessageBox(g_pParentWnd->m_pWidget, Msg1, "Error saving map", MB_OK ); - strcpy( pname, SHADER_NOT_FOUND ); - p->pShader = QERApp_Shader_ForName(SHADER_NOT_FOUND); - p->d_texture = p->pShader->getTexture(); - return; - } - strcpy( pname, p->pShader->getName()+9 ); // remove "textures/" -} - -/* -================== -Patch_Write -================== -*/ -void Patch_Write (patchMesh_t *p, MemStream *file) -{ - char pname[1024]; - - MemFile_fprintf(file, " {\n patchDef2\n {\n"); - - CheckName( p, pname ); - MemFile_fprintf(file, " %s\n", pname ); - MemFile_fprintf(file, " ( %i %i %i %i %i ) \n", p->width, p->height, p->contents, p->flags, p->value); - - - float ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5]; - - int w, h; - for (w = 0; w < p->width; w++) - { - for (h = 0; h < p->height; h++) - { - ctrl[w][h][0] = p->ctrl[w][h].xyz[0]; - ctrl[w][h][1] = p->ctrl[w][h].xyz[1]; - ctrl[w][h][2] = p->ctrl[w][h].xyz[2]; - ctrl[w][h][3] = p->ctrl[w][h].st[0]; - ctrl[w][h][4] = p->ctrl[w][h].st[1]; - } - } - - _Write3DMatrix(file, p->width, p->height, 5, reinterpret_cast(&ctrl)); - - if (g_qeglobals.m_bBrushPrimitMode) - { - if (p->epairs) - { - for (epair_t *ep = p->epairs ; ep ; ep=ep->next) - { - MemFile_fprintf (file, "\"%s\" \"%s\"\n", ep->key, ep->value); - } - } - } - - MemFile_fprintf(file, " }\n }\n"); -} - -void Patch_Write (patchMesh_t *p, FILE *file) -{ - char pname[1024]; - - fprintf(file, " {\n patchDef2\n {\n"); - { - CheckName( p, pname ); - fprintf(file, " %s\n", pname ); - fprintf(file, " ( %i %i %i %i %i ) \n", p->width, p->height, p->contents, p->flags, p->value); - } - - float ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5]; - - int w, h; - for (w = 0; w < p->width; w++) - { - for (h = 0; h < p->height; h++) - { - ctrl[w][h][0] = p->ctrl[w][h].xyz[0]; - ctrl[w][h][1] = p->ctrl[w][h].xyz[1]; - ctrl[w][h][2] = p->ctrl[w][h].xyz[2]; - ctrl[w][h][3] = p->ctrl[w][h].st[0]; - ctrl[w][h][4] = p->ctrl[w][h].st[1]; - } - } - - _Write3DMatrix(file, p->width, p->height, 5, reinterpret_cast(&ctrl)); - - if (g_qeglobals.m_bBrushPrimitMode) - { - if (p->epairs) - { - for (epair_t *ep = p->epairs ; ep ; ep=ep->next) - { - fprintf (file, "\"%s\" \"%s\"\n", ep->key, ep->value); - } - } - } - - fprintf(file, " }\n }\n"); -} - - -/* -================== -Patch_RotateTexture -================== -*/ -void Patch_RotateTexture(patchMesh_t *p, float fAngle) -{ - p->bDirty = true; - float c = cos(fAngle * Q_PI / 180); - float s = sin(fAngle * Q_PI / 180); - - Patch_TransformLODTexture(p, c, s, ROTATE); - - for (int w = 0; w < p->width; w++) - { - for (int h = 0; h < p->height; h++) - { - //if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1) - // continue; - - float x = p->ctrl[w][h].st[0]; - float y = p->ctrl[w][h].st[1]; - p->ctrl[w][h].st[0] = x * c - y * s; - p->ctrl[w][h].st[1] = y * c + x * s; - } - } -} - - -/* -================== -Patch_ScaleTexture -================== -*/ -void Patch_ScaleTexture(patchMesh_t *p, float fx, float fy, bool bFixup) -{ - // FIXME: - // this hack turns scales into 1.1 or 0.9 - if (bFixup) - { - fx = (fx == 0) ? 1.0 : (fx > 0) ? 0.9 : 1.10; - fy = (fy == 0) ? 1.0 : (fy > 0) ? 0.9 : 1.10; - } - else - { - if (fx == 0) - fx = 1.0; - if (fy == 0) - fy = 1.0; - } - - for (int w = 0; w < p->width; w++) - { - for (int h = 0; h < p->height; h++) - { - if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1) - continue; - - p->ctrl[w][h].st[0] *= fx; - p->ctrl[w][h].st[1] *= fy; - } - } - if (g_qeglobals.d_select_mode == sel_curvepoint) - { - p->bDirty = true; - Patch_LODMatchAll(); - } - else - { - Patch_TransformLODTexture(p, fx, fy, SCALE); - p->LODUpdated = true; - } -} - - -/* -================== -Patch_ShiftTexture -shift a texture given a pixel count -================== -*/ -void Patch_ShiftTexture(patchMesh_t *p, float fx, float fy) -{ - qtexture_t *pTex; - pTex = p->pShader->getTexture(); - fx = -1 * fx / pTex->width; - fy = fy / pTex->height; - Patch_ShiftTextureST(p, fx, fy); -} - -/* -==================== -Patch_ShiftTextureST -shift a patch texture given an ST increment -==================== -*/ -void Patch_ShiftTextureST(patchMesh_t *p, float fx, float fy) -{ -#ifdef _DEBUG - // NOTE: when called by Patch_ShiftTexture this warning may be bogus - if ((ABS(fx) >= 1) || (ABS(fy) >= 1)) - Sys_Printf("WARNING: increments exceed 1 in Patch_ShiftTextureST\n"); -#endif - for (int w = 0; w < p->width; w++) - { - for (int h = 0; h < p->height; h++) - { - if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1) - continue; - - p->ctrl[w][h].st[0] += fx; - p->ctrl[w][h].st[1] += fy; - } - } - if (g_qeglobals.d_select_mode == sel_curvepoint) - { - p->bDirty = true; - Patch_LODMatchAll(); - } - else - { - Patch_TransformLODTexture(p, fx, fy, TRANSLATE); - p->LODUpdated = true; - } -} - -/* -================== -Patch_ToggleInverted -================== -*/ -void Patch_ToggleInverted() -{ - bool bUpdate = false; - - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - bUpdate = true; - patchInvert(pb->pPatch); - } - } - - if (bUpdate) - { - Sys_UpdateWindows(W_ALL); - } - UpdatePatchInspector(); -} - -/* -================== -Patch_ToggleInverted -================== -*/ -void Patch_InvertTexture(bool bY) -{ - bool bUpdate = false; - - float fTemp[2]; - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - bUpdate = true; - patchMesh_t *p = pb->pPatch; - p->bDirty = true; - if (bY) - { - for ( int i = 0 ; i < p->height ; i++ ) - { - for (int j = 0; j < p->width / 2; j++) - { - memcpy(fTemp, &p->ctrl[p->width - 1- j][i].st[0], sizeof (float[2])); - memcpy(&p->ctrl[p->width - 1- j][i].st[0], &p->ctrl[j][i].st[0], sizeof(float[2])); - memcpy(&p->ctrl[j][i].st[0], fTemp, sizeof(float[2])); - } - } - } - else - { - for ( int i = 0 ; i < p->width ; i++ ) - { - for (int j = 0; j < p->height / 2; j++) - { - memcpy(fTemp, &p->ctrl[i][p->height - 1- j].st[0], sizeof (float[2])); - memcpy(&p->ctrl[i][p->height - 1 - j].st[0], &p->ctrl[i][j].st[0], sizeof(float[2])); - memcpy(&p->ctrl[i][j].st[0], fTemp, sizeof(float[2])); - } - } - } - } - } - - if (bUpdate) - { - Sys_UpdateWindows(W_ALL); - } - UpdatePatchInspector(); -} - - - - -/* -================== -Patch_Save -================== - Saves patch ctrl info (originally to deal with a - cancel in the surface dialog -*/ -void Patch_Save(patchMesh_t *p) -{ - patchSave.width = p->width; - patchSave.height = p->height; - memcpy(patchSave.ctrl, p->ctrl, sizeof(p->ctrl)); -} - - -/* -================== -Patch_Restore -================== -*/ -void Patch_Restore(patchMesh_t *p) -{ - p->width = patchSave.width; - p->height = patchSave.height; - memcpy(p->ctrl, patchSave.ctrl, sizeof(p->ctrl)); -} - -void Patch_ResetTexturing(float fx, float fy) -{ - for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - patchMesh_t *p = pb->pPatch; - p->bDirty = true; - for ( int i = 0 ; i < p->width ; i++ ) - { - for ( int j = 0 ; j < p->height ; j++ ) - { - p->ctrl[i][j].st[0] = fx * (float)i / (p->width - 1); - p->ctrl[i][j].st[1] = 1 - fy * (float)j / (p->height - 1); - } - } - } - } -} - -// NOTE TTimo stub! -void Patch_FitTexturing() -{ - Patch_ResetTexturing(1.0f, 1.0f); -} - -void Patch_SetTextureInfo(texdef_t *pt) -{ - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - if (pt->rotate) - Patch_RotateTexture(pb->pPatch, pt->rotate); - - if (pt->shift[0] || pt->shift[1]) - Patch_ShiftTexture(pb->pPatch, pt->shift[0], pt->shift[1]); - - if (pt->scale[0] || pt->scale[1]) - Patch_ScaleTexture(pb->pPatch, pt->scale[0], pt->scale[1], false); - - patchMesh_t *p = pb->pPatch; - p->contents = pt->contents; - p->flags = pt->flags; - p->value = pt->value; - } - } -} - -bool OnlyPatchesSelected() -{ - if (g_ptrSelectedFaces.GetSize() > 0 || selected_brushes.next == &selected_brushes) - return false; - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (!pb->patchBrush) - { - return false; - } - } - return true; -} - -bool AnyPatchesSelected() -{ - if (g_ptrSelectedFaces.GetSize() > 0 || selected_brushes.next == &selected_brushes) - return false; - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - return true; - } - } - return false; -} - -patchMesh_t* SinglePatchSelected() -{ - if (selected_brushes.next->patchBrush) - { - return selected_brushes.next->pPatch; - } - return NULL; -} - -void Patch_BendToggle() -{ - if (g_bPatchBendMode) - { - g_bPatchBendMode = false; - HideInfoDialog(); - g_pParentWnd->UpdatePatchToolbarButtons() ; - return; - } - - brush_t* b = selected_brushes.next; - - if (!QE_SingleBrush(true) || !b->patchBrush) - { - Sys_Printf("Patch_BendToggle: you must have a single patch selected\n"); - return; - } - - Patch_Save(b->pPatch); - g_bPatchBendMode = true; - g_nPatchBendState = BEND_SELECT_ROTATION; - g_bPatchAxisOnRow = true; - g_nPatchAxisIndex = 1; - ShowInfoDialog(g_pBendStateMsg[BEND_SELECT_ROTATION]); -} - -void Patch_BendHandleTAB() -{ - if (!g_bPatchBendMode) - { - return; - } - - brush_t* b = selected_brushes.next; - if (!QE_SingleBrush() || !b->patchBrush) - { - Patch_BendToggle(); - Sys_Printf("No patch to bend!"); - return; - } - - patchMesh_t *p = b->pPatch; - - bool bShift = Sys_ShiftDown (); - - if (g_nPatchBendState == BEND_SELECT_ROTATION) - { - // only able to deal with odd numbered rows/cols - g_nPatchAxisIndex += (bShift) ? -2 : 2; - if (g_bPatchAxisOnRow) - { - if ((bShift) ? g_nPatchAxisIndex <= 0 : g_nPatchAxisIndex >= p->height) - { - g_bPatchAxisOnRow = false; - g_nPatchAxisIndex = (bShift) ? p->width-1 : 1; - } - } - else - { - if ((bShift) ? g_nPatchAxisIndex <= 0 : g_nPatchAxisIndex >= p->width) - { - g_bPatchAxisOnRow = true; - g_nPatchAxisIndex = (bShift) ? p->height-1 : 1; - } - } - } - else - if (g_nPatchBendState == BEND_SELECT_ORIGIN) - { - g_nBendOriginIndex += (bShift) ? -1 : 1; - if (g_bPatchAxisOnRow) - { - if (bShift) - { - if (g_nBendOriginIndex < 0) - g_nBendOriginIndex = p->width-1; - } - else - { - if (g_nBendOriginIndex > p->width-1) - g_nBendOriginIndex = 0; - } - VectorCopy(p->ctrl[g_nBendOriginIndex][g_nPatchAxisIndex].xyz, g_vBendOrigin); - } - else - { - if (bShift) - { - if (g_nBendOriginIndex < 0) - g_nBendOriginIndex = p->height-1; - } - else - { - if (g_nBendOriginIndex > p->height-1) - g_nBendOriginIndex = 0; - } - VectorCopy(p->ctrl[g_nPatchAxisIndex][g_nBendOriginIndex].xyz, g_vBendOrigin); - } - } - else - if (g_nPatchBendState == BEND_SELECT_EDGE) - { - g_bPatchLowerEdge ^= 1; - } - Sys_UpdateWindows(W_ALL); -} - -void Patch_BendHandleENTER() -{ - if (!g_bPatchBendMode) - { - return; - } - - if (g_nPatchBendState < BEND_BENDIT) - { - g_nPatchBendState++; - ShowInfoDialog(g_pBendStateMsg[g_nPatchBendState]); - if (g_nPatchBendState == BEND_SELECT_ORIGIN) - { - g_vBendOrigin[0] = g_vBendOrigin[1] = g_vBendOrigin[2] = 0; - g_nBendOriginIndex = 0; - Patch_BendHandleTAB(); - } - else - if (g_nPatchBendState == BEND_SELECT_EDGE) - { - g_bPatchLowerEdge = true; - } - else - if (g_nPatchBendState == BEND_BENDIT) - { - // basically we go into rotation mode, set the axis to the center of the - } - } - else - { - // done - Patch_BendToggle(); - } - Sys_UpdateWindows(W_ALL); - -} - - -void Patch_BendHandleESC() -{ - if (!g_bPatchBendMode) - { - return; - } - Patch_BendToggle(); - brush_t* b = selected_brushes.next; - if (QE_SingleBrush() && b->patchBrush) - { - Patch_Restore(b->pPatch); - } - Sys_UpdateWindows(W_ALL); -} - -void Patch_SetBendRotateOrigin(patchMesh_t *p) -{ -#if 1 - int nType = g_pParentWnd->ActiveXY()->GetViewType(); - int nDim3 = (nType == XY) ? 2 : (nType == YZ) ? 0 : 1; - - g_vBendOrigin[nDim3] = 0; - VectorCopy(g_vBendOrigin, g_pParentWnd->ActiveXY()->RotateOrigin()); - return; -#else - int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0; - int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2; - - float fxLo, fyLo, fxHi, fyHi; - fxLo = fyLo = 9999; - fxHi = fyHi = -9999; - - if (g_bPatchAxisOnRow) - { - for (int i = 0; i < p->width; i++) - { - if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1] < fxLo) - fxLo = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1]; - - if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1] > fxHi) - fxHi = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1]; - - if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2] < fyLo) - fyLo = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2]; - - if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2] > fyHi) - fyHi = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2]; - } - } - else - { - for (int i = 0; i < p->height; i++) - { - if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1] < fxLo) - fxLo = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1]; - - if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1] > fxHi) - fxHi = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1]; - - if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2] < fyLo) - fyLo = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2]; - - if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2] > fyHi) - fyHi = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2]; - } - } - - g_pParentWnd->ActiveXY()->RotateOrigin()[0] = g_pParentWnd->ActiveXY()->RotateOrigin()[1] = g_pParentWnd->ActiveXY()->RotateOrigin()[2] = 0.0; - g_pParentWnd->ActiveXY()->RotateOrigin()[nDim1] = (fxLo + fxHi) * 0.5; - g_pParentWnd->ActiveXY()->RotateOrigin()[nDim2] = (fyLo + fyHi) * 0.5; -#endif -} - -// also sets the rotational origin -void Patch_SelectBendAxis() -{ - brush_t* b = selected_brushes.next; - if (!QE_SingleBrush() || !b->patchBrush) - { - // should not ever happen - Patch_BendToggle(); - return; - } - - patchMesh_t *p = b->pPatch; - if (g_bPatchAxisOnRow) - { - SelectRow(p, g_nPatchAxisIndex, false); - } - else - { - SelectColumn(p, g_nPatchAxisIndex, false); - } - - //FIXME: this only needs to be set once... - Patch_SetBendRotateOrigin(p); - -} - -void Patch_SelectBendNormal() -{ - brush_t* b = selected_brushes.next; - if (!QE_SingleBrush() || !b->patchBrush) - { - // should not ever happen - Patch_BendToggle(); - return; - } - - patchMesh_t *p = b->pPatch; - - g_qeglobals.d_num_move_points = 0; - if (g_bPatchAxisOnRow) - { - if (g_bPatchLowerEdge) - { - for (int j = 0; j < g_nPatchAxisIndex; j++) - SelectRow(p, j, true); - } - else - { - for (int j = p->height-1; j > g_nPatchAxisIndex; j--) - SelectRow(p, j, true); - } - } - else - { - if (g_bPatchLowerEdge) - { - for (int j = 0; j < g_nPatchAxisIndex; j++) - SelectColumn(p, j, true); - } - else - { - for (int j = p->width-1; j > g_nPatchAxisIndex; j--) - SelectColumn(p, j, true); - } - } - Patch_SetBendRotateOrigin(p); -} - - - -/* -void Patch_InsDelToggle() -{ - if (g_bPatchInsertMode) - { - g_bPatchInsertMode = false; - HideInfoDialog(); - g_pParentWnd->UpdatePatchToolbarButtons() ; - return; - } - - brush_t* b = selected_brushes.next; - - if (!QE_SingleBrush(true) || !b->patchBrush) - { - Sys_Printf("Patch_InsDelToggle: you must have a single patch selected\n"); - return; - } - - Patch_Save(b->pPatch); - g_bPatchInsertMode = true; - g_nPatchInsertState = INSERT_SELECT_EDGE; - g_bPatchAxisOnRow = true; - g_nPatchAxisIndex = 0; - ShowInfoDialog(g_pInsertStateMsg[INSERT_SELECT_EDGE]); - -} - -void Patch_InsDelESC() -{ - if (!g_bPatchInsertMode) - { - return; - } - Patch_InsDelToggle(); - Sys_UpdateWindows(W_ALL); -} - - -void Patch_InsDelHandleENTER() -{ -} - -void Patch_InsDelHandleTAB() -{ - if (!g_bPatchInsertMode) - { - Patch_InsDelToggle(); - return; - } - - brush_t* b = selected_brushes.next; - if (!QE_SingleBrush() || !b->patchBrush) - { - Patch_BendToggle(); - Sys_Printf("No patch to bend!"); - return; - } - - patchMesh_t *p = b->pPatch; - - // only able to deal with odd numbered rows/cols - g_nPatchAxisIndex += 2; - if (g_bPatchAxisOnRow) - { - if (g_nPatchAxisIndex >= p->height-1) - { - g_bPatchAxisOnRow = false; - g_nPatchAxisIndex = 0; - } - } - else - { - if (g_nPatchAxisIndex >= p->width-1) - { - g_bPatchAxisOnRow = true; - g_nPatchAxisIndex = 0; - } - } - Sys_UpdateWindows(W_ALL); -} -*/ - - -void _Write1DMatrix (FILE *f, int x, float *m) { - int i; - - fprintf (f, "( "); - for (i = 0 ; i < x ; i++) { - if (m[i] == (int)m[i] ) { - fprintf (f, "%i ", (int)m[i]); - } else { - fprintf (f, "%f ", m[i]); - } - } - fprintf (f, ")"); -} - -void _Write2DMatrix (FILE *f, int y, int x, float *m) { - int i; - - fprintf (f, "( "); - for (i = 0 ; i < y ; i++) { - _Write1DMatrix (f, x, m + i*x); - fprintf (f, " "); - } - fprintf (f, ")\n"); -} - - -void _Write3DMatrix (FILE *f, int z, int y, int x, float *m) { - int i; - - fprintf (f, "(\n"); - for (i = 0 ; i < z ; i++) { - _Write2DMatrix (f, y, x, m + i*(x*MAX_PATCH_HEIGHT) ); - } - fprintf (f, ")\n"); -} - -void _Write1DMatrix (MemStream *f, int x, float *m) { - int i; - - MemFile_fprintf (f, "( "); - for (i = 0 ; i < x ; i++) { - if (m[i] == (int)m[i] ) { - MemFile_fprintf (f, "%i ", (int)m[i]); - } else { - MemFile_fprintf (f, "%f ", m[i]); - } - } - MemFile_fprintf (f, ")"); -} - -void _Write2DMatrix (MemStream *f, int y, int x, float *m) { - int i; - - MemFile_fprintf (f, "( "); - for (i = 0 ; i < y ; i++) { - _Write1DMatrix (f, x, m + i*x); - MemFile_fprintf (f, " "); - } - MemFile_fprintf (f, ")\n"); -} - - -void _Write3DMatrix (MemStream *f, int z, int y, int x, float *m) { - int i; - - MemFile_fprintf (f, "(\n"); - for (i = 0 ; i < z ; i++) { - _Write2DMatrix (f, y, x, m + i*(x*MAX_PATCH_HEIGHT) ); - } - MemFile_fprintf (f, ")\n"); -} - -// NOTE: why the hell is this called Naturalize? -// we dispatch either to Patch+Naturalize or Patch_CapTexture.. -void Patch_NaturalizeSelected(bool bCap) -{ - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - if (bCap) - Patch_CapTexture(pb->pPatch);//, bCycleCap); - else - Patch_Naturalize(pb->pPatch); - } - } -} - -// go through the selected patches and call Patch_CapTexture -// deal with cycling -void Patch_CycleCapSelected() -{ - // compute the g_vCycleCapNormal according to g_nCycleCapIndex - VectorClear (g_vCycleCapNormal); - g_vCycleCapNormal[g_nCycleCapIndex] = 1.0f; // cf VIEWTYPE defintion: enum VIEWTYPE {YZ, XZ, XY}; - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - Patch_CapTexture(pb->pPatch, true); - } - } - switch (g_nCycleCapIndex) - { - case YZ: - g_nCycleCapIndex = XZ; - break; - case XZ: - g_nCycleCapIndex = XY; - break; - case XY: - g_nCycleCapIndex = YZ; - break; - } -} - -bool within(vec3_t vTest, vec3_t vTL, vec3_t vBR) -{ - int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0; - int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2; - if ((vTest[nDim1] > vTL[nDim1] && vTest[nDim1] < vBR[nDim1]) || - (vTest[nDim1] < vTL[nDim1] && vTest[nDim1] > vBR[nDim1])) - { - if ((vTest[nDim2] > vTL[nDim2] && vTest[nDim2] < vBR[nDim2]) || - (vTest[nDim2] < vTL[nDim2] && vTest[nDim2] > vBR[nDim2])) - return true; - } - return false; -} - - -void Patch_SelectAreaPoints(bool bMulti) -{ - if (!bMulti) - g_qeglobals.d_num_move_points = 0; - - if( g_nPatchClickedView == W_CAMERA ) { - // Clip against a pyramid - // Create our 5 normals (that are pointing to the inside) - camera_t *m_pCamera = g_pParentWnd->GetCamWnd()->Camera(); - vec3_t norm[5]; - float r[2], u[2], hh, hw; - int idx; - vec_t corners[2][2]; - vec3_t ray[4]; - vec3_t check; - - VectorCopy( m_pCamera->vpn, norm[0] ); // only points in front of the camera - - // get our rectangle - corners[0][0] = MIN( g_qeglobals.d_vAreaTL[0], g_qeglobals.d_vAreaBR[0] ); - corners[0][1] = MAX( g_qeglobals.d_vAreaTL[1], g_qeglobals.d_vAreaBR[1] ); - corners[1][0] = MAX( g_qeglobals.d_vAreaTL[0], g_qeglobals.d_vAreaBR[0] ); - corners[1][1] = MIN( g_qeglobals.d_vAreaTL[1], g_qeglobals.d_vAreaBR[1] ); - - // calculate our four ray vectors - hh = m_pCamera->height/2; - hw = m_pCamera->width/2; - u[0] = (float)(corners[0][1] - hh) / (hw); - r[0] = (float)(corners[0][0] - hw) / (hw); - u[1] = (float)(corners[1][1] - hh) / (hw); - r[1] = (float)(corners[1][0] - hw) / (hw); - - for (idx=0 ; idx<3; idx++) - ray[0][idx] = m_pCamera->vpn[idx] + m_pCamera->vright[idx] * r[0] + m_pCamera->vup[idx] * u[0]; - for (idx=0 ; idx<3; idx++) - ray[1][idx] = m_pCamera->vpn[idx] + m_pCamera->vright[idx] * r[1] + m_pCamera->vup[idx] * u[0]; - for (idx=0 ; idx<3; idx++) - ray[2][idx] = m_pCamera->vpn[idx] + m_pCamera->vright[idx] * r[1] + m_pCamera->vup[idx] * u[1]; - for (idx=0 ; idx<3; idx++) - ray[3][idx] = m_pCamera->vpn[idx] + m_pCamera->vright[idx] * r[0] + m_pCamera->vup[idx] * u[1]; - - // Create our four other directions from these - CrossProduct( ray[0], ray[1], norm[1] ); VectorNormalize( norm[1], norm[1] ); - CrossProduct( ray[1], ray[2], norm[2] ); VectorNormalize( norm[2], norm[2] ); - CrossProduct( ray[2], ray[3], norm[3] ); VectorNormalize( norm[3], norm[3] ); - CrossProduct( ray[3], ray[0], norm[4] ); VectorNormalize( norm[4], norm[4] ); - - // 3D clipping - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - patchMesh_t *p = pb->pPatch; - for (int i = 0; i < p->width; i++) - { - for (int j = 0; j < p->height; j++) - { - VectorSubtract( m_pCamera->origin, p->ctrl[i][j].xyz, check ); - VectorNormalize( check, check ); - for (idx=0 ; idx<5; idx++) - { - if (DotProduct(check, norm[idx])>=0) - break; - } - if (idx == 5) // all test were good - { - if (bMulti && PointInMoveList(p->ctrl[i][j].xyz) != -1) - RemovePointFromMoveList(p->ctrl[i][j].xyz); - else - g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz; - } - } - } - } - } - } else - { - // Simple 2D clipping - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - patchMesh_t *p = pb->pPatch; - for (int i = 0; i < p->width; i++) - { - for (int j = 0; j < p->height; j++) - { - if (within(p->ctrl[i][j].xyz, g_qeglobals.d_vAreaTL, g_qeglobals.d_vAreaBR)) - { - if (bMulti && PointInMoveList(p->ctrl[i][j].xyz) != -1) - RemovePointFromMoveList(p->ctrl[i][j].xyz); - else - g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz; - } - } - } - } - } - } - - g_nPatchClickedView = -1; -} - -// TTimo: return the shader name for a patch -const char* Patch_GetTextureName() -{ - brush_t* b = selected_brushes.next; - if (b->patchBrush) - { - patchMesh_t *p = b->pPatch; - return p->pShader->getName(); - } - return ""; -} - -patchMesh_t* Patch_Duplicate(patchMesh_t *pFrom) -{ - patchMesh_t* p = MakeNewPatch(); - memcpy(p, pFrom , sizeof(patchMesh_t)); - - // spog - initialise patch LOD pointers (again) - Patch_InitialiseLODPointers(p); - p->drawLists = NULL; - - p->bSelected = false; - p->bDirty = true; - p->bOverlay = false; - p->nListID = -1; - AddBrushForPatch(p); - - return p; -} - - -void Patch_Thicken(int nAmount, bool bSeam, qboolean bGroupResult) -{ - int i, j, h, w; - brush_t *b; - patchMesh_t *pSeam; - vec3_t vMin, vMax; - CPtrArray brushes; - - nAmount = -nAmount; - - - if (!QE_SingleBrush()) - { - Sys_Printf("Cannot thicken multiple patches. Please select a single patch.\n"); - return; - } - - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - patchMesh_t *p = pb->pPatch; - Patch_MeshNormals(p); - patchMesh_t *pNew = Patch_Duplicate(p); - for (i = 0; i < p->width; i++) - { - for (j = 0; j < p->height; j++) - { - VectorMA (p->ctrl[i][j].xyz, nAmount, p->ctrl[i][j].normal, pNew->ctrl[i][j].xyz); - } - } - - Patch_Rebuild(pNew); - pNew->type |= PATCH_THICK; - brushes.Add(pNew->pSymbiot); - - if (bSeam) - { - - // FIXME: this should detect if any edges of the patch are closed and act appropriately - // - if (!(p->type & PATCH_CYLINDER)) - { - b = Patch_GenericMesh(3, p->height, 2, false, true); - pSeam = b->pPatch; - pSeam->type |= PATCH_SEAM; - for (i = 0; i < p->height; i++) - { - VectorCopy(p->ctrl[0][i].xyz, pSeam->ctrl[0][i].xyz); - VectorCopy(pNew->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz); - VectorAdd(pSeam->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz, pSeam->ctrl[1][i].xyz); - VectorScale(pSeam->ctrl[1][i].xyz, 0.5, pSeam->ctrl[1][i].xyz); - } - - - Patch_CalcBounds(pSeam, vMin, vMax); - Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax); - //--Patch_CapTexture(pSeam); - Patch_Naturalize(pSeam); - patchInvert(pSeam); - brushes.Add(b); - - w = p->width - 1; - b = Patch_GenericMesh(3, p->height, 2, false, true); - pSeam = b->pPatch; - pSeam->type |= PATCH_SEAM; - for (i = 0; i < p->height; i++) - { - VectorCopy(p->ctrl[w][i].xyz, pSeam->ctrl[0][i].xyz); - VectorCopy(pNew->ctrl[w][i].xyz, pSeam->ctrl[2][i].xyz); - VectorAdd(pSeam->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz, pSeam->ctrl[1][i].xyz); - VectorScale(pSeam->ctrl[1][i].xyz, 0.5, pSeam->ctrl[1][i].xyz); - } - Patch_CalcBounds(pSeam, vMin, vMax); - Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax); - //--Patch_CapTexture(pSeam); - Patch_Naturalize(pSeam); - brushes.Add(b); - } - - //--{ - // otherwise we will add one per end - b = Patch_GenericMesh(p->width, 3, 2, false, true); - pSeam = b->pPatch; - pSeam->type |= PATCH_SEAM; - for (i = 0; i < p->width; i++) - { - VectorCopy(p->ctrl[i][0].xyz, pSeam->ctrl[i][0].xyz); - VectorCopy(pNew->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz); - VectorAdd(pSeam->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz, pSeam->ctrl[i][1].xyz); - VectorScale(pSeam->ctrl[i][1].xyz, 0.5, pSeam->ctrl[i][1].xyz); - } - - - Patch_CalcBounds(pSeam, vMin, vMax); - Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax); - //--Patch_CapTexture(pSeam); - Patch_Naturalize(pSeam); - patchInvert(pSeam); - brushes.Add(b); - - h = p->height - 1; - b = Patch_GenericMesh(p->width, 3, 2, false, true); - pSeam = b->pPatch; - pSeam->type |= PATCH_SEAM; - for (i = 0; i < p->width; i++) - { - VectorCopy(p->ctrl[i][h].xyz, pSeam->ctrl[i][0].xyz); - VectorCopy(pNew->ctrl[i][h].xyz, pSeam->ctrl[i][2].xyz); - VectorAdd(pSeam->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz, pSeam->ctrl[i][1].xyz); - VectorScale(pSeam->ctrl[i][1].xyz, 0.5, pSeam->ctrl[i][1].xyz); - } - Patch_CalcBounds(pSeam, vMin, vMax); - Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax); - //--Patch_CapTexture(pSeam); - Patch_Naturalize(pSeam); - brushes.Add(b); - - } - patchInvert(pNew); - } - } - - for (i = 0; i < brushes.GetSize(); i++) - { - Select_Brush(reinterpret_cast(brushes.GetAt(i))); - } - - if(bGroupResult) - { - entity_t *e = Entity_Alloc(); - SetKeyValue(e, "classname", "func_group"); - SetKeyValue(e, "type", "patchThick"); - Select_GroupEntity(e); - Entity_AddToList(e, &entities); - } - - UpdatePatchInspector(); -} - - -/* -lets get another list together as far as necessities.. - -*snapping stuff to the grid (i will only snap movements by the mouse to the grid.. snapping the rotational bend stuff will fubar everything) - -capping bevels/endcaps - -hot keys - -texture fix for caps - -clear clipboard - -*region fix - -*surface dialog - -*/ - -void Patch_SetOverlays() -{ - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - pb->pPatch->bOverlay = true; - } - } -} - - - -void Patch_ClearOverlays() -{ - brush_t *pb; - for (pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - pb->pPatch->bOverlay = false; - } - } - - for (pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - pb->pPatch->bOverlay = false; - } - } - -} - -// FIXME: spog - er, someone forgot to finish their patch point freezing feature? -// freezes selected vertices -void Patch_Freeze() -{ - brush_t *pb; - for (pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - pb->pPatch->bOverlay = false; - } - } - - for (pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - pb->pPatch->bOverlay = false; - } - } - -} - -void Patch_UnFreeze(bool bAll) -{ -} - -void Patch_Transpose() -{ - int i, j, w; - drawVert_t dv; - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - patchMesh_t *p = pb->pPatch; - - if ( p->width > p->height ) - { - for ( i = 0 ; i < p->height ; i++ ) - { - for ( j = i + 1 ; j < p->width ; j++ ) - { - if ( j < p->height ) - { - // swap the value - memcpy(&dv,&p->ctrl[j][i],sizeof(drawVert_t)); - memcpy(&p->ctrl[j][i],&p->ctrl[i][j], sizeof(drawVert_t)); - memcpy(&p->ctrl[i][j],&dv, sizeof(drawVert_t)); - } - else - { - // just copy - memcpy(&p->ctrl[i][j],&p->ctrl[j][i], sizeof(drawVert_t)); - } - } - } - } - else - { - for ( i = 0 ; i < p->width ; i++ ) - { - for ( j = i + 1 ; j < p->height ; j++ ) - { - if ( j < p->width ) - { - // swap the value - memcpy(&dv,&p->ctrl[i][j], sizeof(drawVert_t)); - memcpy(&p->ctrl[i][j],&p->ctrl[j][i], sizeof(drawVert_t)); - memcpy(&p->ctrl[j][i],&dv, sizeof(drawVert_t)); - } - else - { - // just copy - memcpy(&p->ctrl[j][i],&p->ctrl[i][j], sizeof(drawVert_t)); - } - } - } - } - - w = p->width; - p->width = p->height; - p->height = w; - patchInvert(p); - Patch_Rebuild(p); - } - } -} - - - -void Patch_SnapToGrid(patchMesh_t *p) -{ - int i,j,k; - - // if patch points selected, snap only selected points - if (g_qeglobals.d_select_mode == sel_curvepoint && g_qeglobals.d_num_move_points != 0) - for (i=0; iwidth; i++) - for (j = 0; j < p->height; j++) - for (k = 0; k < 3; k++) - p->ctrl[i][j].xyz[k] = floor(p->ctrl[i][j].xyz[k] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; - - vec3_t vMin, vMax; - Patch_CalcBounds(p, vMin, vMax); - Brush_RebuildBrush(p->pSymbiot, vMin, vMax); -} - - -void Patch_FindReplaceTexture(brush_t *pb, const char *pFind, const char *pReplace, bool bForce) -{ - if (pb->patchBrush) - { - patchMesh_t *p = pb->pPatch; - if (bForce || strcmpi(p->pShader->getName(), pFind) == 0) - { - p->pShader->DecRef(); - p->pShader = QERApp_Shader_ForName(pReplace); - p->d_texture = p->pShader->getTexture(); - } - } -} - -/* uncomment if necessary, currently not used -void Patch_FromTriangle(vec5_t vx, vec5_t vy, vec5_t vz) -{ - patchMesh_t* p = MakeNewPatch(); - p->pShader = g_qeglobals.d_texturewin.pShader; - p->d_texture = g_qeglobals.d_texturewin.pShader->getTexture(); - p->width = 3; - p->height = 3; - p->type = PATCH_TRIANGLE; - - // 0 0 goes to x - // 0 1 goes to x - // 0 2 goes to x - - // 1 0 goes to mid of x and z - // 1 1 goes to mid of x y and z - // 1 2 goes to mid of x and y - - // 2 0 goes to z - // 2 1 goes to mid of y and z - // 2 2 goes to y - - vec5_t vMidXZ; - vec5_t vMidXY; - vec5_t vMidYZ; - int j; - - for (j = 0; j < 3; j++) - { - _Vector5Add(vx, vz, vMidXZ); - _Vector5Scale(vMidXZ, 0.5, vMidXZ); - //vMidXZ[j] = vx[j] + abs((vx[j] - vz[j]) * 0.5); - } - - for (j = 0; j < 3; j++) - { - _Vector5Add(vx, vy, vMidXY); - _Vector5Scale(vMidXY, 0.5, vMidXY); - //vMidXY[j] = vx[j] + abs((vx[j] - vy[j]) * 0.5); - } - - for (j = 0; j < 3; j++) - { - _Vector5Add(vy, vz, vMidYZ); - _Vector5Scale(vMidYZ, 0.5, vMidYZ); - //vMidYZ[j] = vy[j] + abs((vy[j] - vz[j]) * 0.5); - } - - _Vector53Copy(vx, p->ctrl[0][0].xyz); - _Vector53Copy(vx, p->ctrl[0][1].xyz); - _Vector53Copy(vx, p->ctrl[0][2].xyz); - p->ctrl[0][0].st[0] = vx[3]; - p->ctrl[0][0].st[1] = vx[4]; - p->ctrl[0][1].st[0] = vx[3]; - p->ctrl[0][1].st[1] = vx[4]; - p->ctrl[0][2].st[0] = vx[3]; - p->ctrl[0][2].st[1] = vx[4]; - - _Vector53Copy(vMidXY, p->ctrl[1][0].xyz); - _Vector53Copy(vx, p->ctrl[1][1].xyz); - _Vector53Copy(vMidXZ, p->ctrl[1][2].xyz); - p->ctrl[1][0].st[0] = vMidXY[3]; - p->ctrl[1][0].st[1] = vMidXY[4]; - p->ctrl[1][1].st[0] = vx[3]; - p->ctrl[1][1].st[1] = vx[4]; - p->ctrl[1][2].st[0] = vMidXZ[3]; - p->ctrl[1][2].st[1] = vMidXZ[4]; - - _Vector53Copy(vy, p->ctrl[2][0].xyz); - _Vector53Copy(vMidYZ, p->ctrl[2][1].xyz); - _Vector53Copy(vz, p->ctrl[2][2].xyz); - p->ctrl[2][0].st[0] = vy[3]; - p->ctrl[2][0].st[1] = vy[4]; - p->ctrl[2][1].st[0] = vMidYZ[3]; - p->ctrl[2][1].st[1] = vMidYZ[4]; - p->ctrl[2][2].st[0] = vz[3]; - p->ctrl[2][2].st[1] = vz[4]; - - - //Patch_Naturalize(p); - - // brush_t *b = - AddBrushForPatch(p); - -} -*/ - -#ifdef ENABLE_GROUPS -/* -============== -Patch_SetEpair -sets an epair for the given patch -============== -*/ -void Patch_SetEpair(patchMesh_t *p, const char *pKey, const char *pValue) -{ - if (g_qeglobals.m_bBrushPrimitMode) - { - SetKeyValue(p->epairs, pKey, pValue); - } -} - -/* -================= -Patch_GetKeyValue -================= -*/ -const char* Patch_GetKeyValue(patchMesh_t *p, const char *pKey) -{ - if (g_qeglobals.m_bBrushPrimitMode) - { - return ValueForKey(p->epairs, pKey); - } - return ""; -} -#endif - - -//Real nitpicky, but could you make CTRL-S save the current map with the current name? (ie: File/Save) -/* -Feature addition. -When reading in textures, please check for the presence of a file called "textures.link" or something, which contains one line such as; - -g:\quake3\baseq3\textures\common - - So that, when I'm reading in, lets say, my \eerie directory, it goes through and adds my textures to the palette, along with everything in common. - - Don't forget to add "Finer texture alignment" to the list. I'd like to be able to move in 0.1 increments using the Shift-Arrow Keys. - - No. Sometimes textures are drawn the wrong way on patches. We'd like the ability to flip a texture. Like the way X/Y scale -1 used to worked. - - 1) Easier way of deleting rows, columns -2) Fine tuning of textures on patches (X/Y shifts other than with the surface dialog) -2) Patch matrix transposition - - 1) Actually, bump texture flipping on patches to the top of the list of things to do. -2) When you select a patch, and hit S, it should read in the selected patch texture. Should not work if you multiselect patches and hit S -3) Brandon has a wierd anomoly. He fine-tunes a patch with caps. It looks fine when the patch is selected, but as soon as he escapes out, it reverts to it's pre-tuned state. When he selects the patch again, it looks tuned - - -*1) Flipping textures on patches -*2) When you select a patch, and hit S, it should read in the selected patch texture. Should not work if you multiselect patches and hit S -3) Easier way of deleting rows columns -*4) Thick Curves -5) Patch matrix transposition -6) Inverted cylinder capping -*7) bugs -*8) curve speed - - Have a new feature request. "Compute Bounding Box" for mapobjects (md3 files). This would be used for misc_mapobject (essentially, drop in 3DS Max models into our maps) - - Ok, Feature Request. Load and draw MD3's in the Camera view with proper bounding boxes. This should be off misc_model - - Feature Addition: View/Hide Hint Brushes -- This should be a specific case. -*/ +/* +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 +*/ + +// +// Preliminary patch stuff +// +// + +#include "stdafx.h" +#include "gtkmisc.h" + +#include "gtkr_list.h" + +// externs +extern void MemFile_fprintf(MemStream* pMemFile, const char* pText, ...); +extern face_t *Face_Alloc( void ); +extern void DrawAlternatePoint(vec3_t v, float scale); + +void _Write3DMatrix (FILE *f, int y, int x, int z, float *m); +void _Write3DMatrix (MemStream *f, int y, int x, int z, float *m); + +void Patch_InitialiseLODPointers(patchMesh_t *p) +{ + int i; + int rowcount = ((MAX_PATCH_WIDTH-1)/2) * MAX_PATCH_HEIGHT; + for (i=0; irowLOD[i] = NULL; + int colcount = ((MAX_PATCH_HEIGHT-1)/2) * MAX_PATCH_WIDTH; + for (i=0; icolLOD[i] = NULL; +} + +patchMesh_t* Patch_Alloc() +{ + patchMesh_t *pPatch = (patchMesh_t *)malloc(sizeof(patchMesh_t)); + pPatch->pShader = NULL; + pPatch->pSymbiot = NULL; // Hydra: added missing initialiser. + // spog - initialise patch LOD pointers + Patch_InitialiseLODPointers(pPatch); + pPatch->drawLists = NULL; + pPatch->bDirty = true; + pPatch->nListID = -1; + pPatch->bSelected = false; + pPatch->bOverlay = false; + pPatch->bDirty = true; + pPatch->LODUpdated = false; + + int i; + for (i=0; i<(((MAX_PATCH_WIDTH-1)-1)/2); i++) + pPatch->rowDirty[i] = false; + for (i=0; i<(((MAX_PATCH_HEIGHT-1)-1)/2); i++) + pPatch->colDirty[i] = false; + + return pPatch; +} + +patchMesh_t* MakeNewPatch() +{ + patchMesh_t *pm = reinterpret_cast(qmalloc(sizeof(patchMesh_t))); + + // spog - initialise patch LOD pointers + Patch_InitialiseLODPointers(pm); + pm->drawLists = NULL; + pm->bDirty = true; + + return pm; +} + +// FIXME: this needs to be dynamic +//#define MAX_PATCH_MESHES 4096 +//patchMesh_t patchMeshes[MAX_PATCH_MESHES]; +//int numPatchMeshes = 0; + +// used for a save spot +patchMesh_t patchSave; + +// Tracks the selected patch for point manipulation/update. FIXME: Need to revert back to a generalized +// brush approach +//--int g_nSelectedPatch = -1; + +// HACK: for tracking which view generated the click +// as we dont want to deselect a point on a same point +// click if it is from a different view +int g_nPatchClickedView = -1; +bool g_bSameView = false; + +//typedef enum XFormType { TRANSLATE, SCALE, ROTATE }; + + +// globals +bool g_bPatchShowBounds = true; +bool g_bPatchWireFrame = false; +bool g_bPatchWeld = true; +bool g_bPatchDrillDown = true; +//bool g_bPatchInsertMode = false; +bool g_bPatchBendMode = false; +int g_nPatchBendState = -1; +int g_nPatchInsertState = -1; +int g_nBendOriginIndex = 0; +vec3_t g_vBendOrigin; + +bool g_bPatchAxisOnRow = true; +int g_nPatchAxisIndex = 0; +bool g_bPatchLowerEdge = true; + +vec3_t g_vCycleCapNormal; +// cycles when we use Patch_CycleCapSelected +VIEWTYPE g_nCycleCapIndex = XY; + +// BEND states +enum +{ + BEND_SELECT_ROTATION = 0, + BEND_SELECT_ORIGIN, + BEND_SELECT_EDGE, + BEND_BENDIT, + BEND_STATE_COUNT +}; + +const char *g_pBendStateMsg[] = +{ + "Use TAB to cycle through available bend axis. Press ENTER when the desired one is highlighted.", + "Use TAB to cycle through available rotation axis. This will LOCK around that point. You may also use Shift + Middle Click to select an arbitrary point. Press ENTER when the desired one is highlighted", + "Use TAB to choose which side to bend. Press ENTER when the desired one is highlighted.", + "Use the MOUSE to bend the patch. It uses the same ui rules as Free Rotation. Press ENTER to accept the bend, press ESC to abandon it and exit Bend mode", + "" +}; + +// INSERT states +enum +{ + INSERT_SELECT_EDGE = 0, + INSERT_STATE_COUNT +}; + +const char* g_pInsertStateMsg[] = +{ + "Use TAB to cycle through available rows/columns for insertion/deletion. Press INS to insert at the highlight, DEL to remove the pair" +}; + + +float *g_InversePoints[1024]; + +const float fFullBright = 1.0; +const float fLowerLimit = .50; +const float fDec = .05f; +void _SetColor(face_t* f, float fColor[3]) +{ + return; + fColor[0] = f->d_color[0]; + fColor[1] = f->d_color[1]; + fColor[2] = f->d_color[2]; + qglColor3fv(fColor); +} + + +void _DecColor(float fColor[3]) +{ + return; + fColor[0] -= fDec; + fColor[1] -= fDec ; + fColor[2] -= fDec; + for (int i = 0; i < 3; i++) + { + if (fColor[i] <= fLowerLimit) + { + fColor[0] = fFullBright; + fColor[1] = fFullBright; + fColor[2] = fFullBright; + break; + } + } + qglColor3fv(fColor); +} + +vec_t __VectorNormalize (vec3_t in, vec3_t out) +{ + vec_t length, ilength; + + length = sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]); + if (length == 0) + { + VectorClear (out); + return 0; + } + + ilength = 1.0/length; + out[0] = in[0]*ilength; + out[1] = in[1]*ilength; + out[2] = in[2]*ilength; + + return length; +} + + +void Patch_SetType(patchMesh_t *p, int nType) +{ + p->type = (p->type & PATCH_STYLEMASK) | nType; +} + +void Patch_SetStyle(patchMesh_t *p, int nStyle) +{ + p->type = (p->type & PATCH_TYPEMASK) | nStyle; +} + +/* +================== +Patch_MemorySize +================== +*/ +int Patch_MemorySize(patchMesh_t *p) +{ + // return _msize(p); + return 0; +} + + +/* +=============== +InterpolateInteriorPoints +=============== +*/ +void InterpolateInteriorPoints( patchMesh_t *p ) +{ + int i, j, k; + int next, prev; + + for ( i = 0 ; i < p->width ; i += 2 ) + { + + next = ( i == p->width - 1 ) ? 1 : ( i + 1 ) % p->width; + prev = ( i == 0 ) ? p->width - 2 : i - 1; + +#if 0 + if ( i == 0 ) + { + next = ( i + 1 ) % p->width; + prev = p->width - 2; // joined wrap case + } + else if ( i == p->width - 1 ) + { + next = 1; + prev = i - 1; + } + else + { + next = ( i + 1 ) % p->width; + prev = i - 1; + } +#endif + + for ( j = 0 ; j < p->height ; j++ ) + { + for ( k = 0 ; k < 3 ; k++ ) + { + p->ctrl[i][j].xyz[k] = ( p->ctrl[next][j].xyz[k] + p->ctrl[prev][j].xyz[k] ) * 0.5; + } + } + } +} + +/* +================= +MakeMeshNormals + +================= +*/ +int neighbors[8][2] = { + {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1} +}; + +void Patch_MeshNormals(patchMesh_t *in ) +{ + int i, j, k, dist; + vec3_t normal; + vec3_t sum; + int count; + vec3_t base; + vec3_t delta; + int x, y; + drawVert_t *dv; + vec3_t around[8], temp; + qboolean good[8]; + qboolean wrapWidth, wrapHeight; + float len; + + wrapWidth = false; + for ( i = 0 ; i < in->height ; i++ ) + { + + VectorSubtract( in->ctrl[0][i].xyz, + in->ctrl[in->width-1][i].xyz, delta ); + len = VectorLength( delta ); + if ( len > 1.0 ) + { + break; + } + } + if ( i == in->height ) + { + wrapWidth = true; + } + + wrapHeight = false; + for ( i = 0 ; i < in->width ; i++ ) + { + VectorSubtract( in->ctrl[i][0].xyz, + in->ctrl[i][in->height-1].xyz, delta ); + len = VectorLength( delta ); + if ( len > 1.0 ) + { + break; + } + } + if ( i == in->width) + { + wrapHeight = true; + } + + + for ( i = 0 ; i < in->width ; i++ ) + { + for ( j = 0 ; j < in->height ; j++ ) + { + count = 0; + //--dv = reinterpret_cast(in.ctrl[j*in.width+i]); + dv = &in->ctrl[i][j]; + VectorCopy( dv->xyz, base ); + for ( k = 0 ; k < 8 ; k++ ) + { + VectorClear( around[k] ); + good[k] = false; + + for ( dist = 1 ; dist <= 3 ; dist++ ) + { + x = i + neighbors[k][0] * dist; + y = j + neighbors[k][1] * dist; + if ( wrapWidth ) + { + if ( x < 0 ) + { + x = in->width - 1 + x; + } + else if ( x >= in->width ) + { + x = 1 + x - in->width; + } + } + if ( wrapHeight ) + { + if ( y < 0 ) + { + y = in->height - 1 + y; + } + else if ( y >= in->height ) + { + y = 1 + y - in->height; + } + } + + if ( x < 0 || x >= in->width || y < 0 || y >= in->height ) + { + break; // edge of patch + } + //--VectorSubtract( in.ctrl[y*in.width+x]->xyz, base, temp ); + VectorSubtract( in->ctrl[x][y].xyz, base, temp ); + if ( __VectorNormalize( temp, temp ) == 0 ) + { + continue; // degenerate edge, get more dist + } + else + { + good[k] = true; + VectorCopy( temp, around[k] ); + break; // good edge + } + } + } + + VectorClear( sum ); + for ( k = 0 ; k < 8 ; k++ ) + { + if ( !good[k] || !good[(k+1)&7] ) + { + continue; // didn't get two points + } + CrossProduct( around[(k+1)&7], around[k], normal ); + if ( __VectorNormalize( normal, normal ) == 0 ) + { + continue; + } + VectorAdd( normal, sum, sum ); + count++; + } + if ( count == 0 ) + { + //printf("bad normal\n"); + count = 1; + //continue; + } + __VectorNormalize( sum, dv->normal ); + } + } +} + + + + +/* +================== +Patch_CalcBounds +================== +*/ +void Patch_CalcBounds(patchMesh_t *p, vec3_t& vMin, vec3_t& vMax) +{ + vMin[0] = vMin[1] = vMin[2] = 99999; + vMax[0] = vMax[1] = vMax[2] = -99999; + + p->bDirty = true; + for (int w = 0; w < p->width; w++) + { + for (int h = 0; h < p->height; h++) + { + for (int j = 0; j < 3; j++) + { + float f = p->ctrl[w][h].xyz[j]; + if (f < vMin[j]) + vMin[j] = f; + if (f > vMax[j]) + vMax[j] = f; + } + } + } +} + +/* +================== +Brush_RebuildBrush +================== +*/ +void Brush_RebuildBrush(brush_t *b, vec3_t vMins, vec3_t vMaxs) +{ + // + // Total hack job + // Rebuilds a brush + int i, j; + face_t *f, *next; + vec3_t pts[4][2]; + texdef_t texdef; + // free faces + + for (j = 0; j < 3; j++) + { + if ((int)vMins[j] == (int)vMaxs[j]) + { + vMins[j] -= 4; + vMaxs[j] += 4; + } + } + + + for (f=b->brush_faces ; f ; f=next) + { + next = f->next; + if (f) + texdef = f->texdef; + Face_Free( f ); + } + + b->brush_faces = NULL; + + // left the last face so we can use its texdef + + for (i=0 ; i<3 ; i++) + if (vMaxs[i] < vMins[i]) + Error ("Brush_RebuildBrush: backwards"); + + pts[0][0][0] = vMins[0]; + pts[0][0][1] = vMins[1]; + + pts[1][0][0] = vMins[0]; + pts[1][0][1] = vMaxs[1]; + + pts[2][0][0] = vMaxs[0]; + pts[2][0][1] = vMaxs[1]; + + pts[3][0][0] = vMaxs[0]; + pts[3][0][1] = vMins[1]; + + for (i=0 ; i<4 ; i++) + { + pts[i][0][2] = vMins[2]; + pts[i][1][0] = pts[i][0][0]; + pts[i][1][1] = pts[i][0][1]; + pts[i][1][2] = vMaxs[2]; + } + + for (i=0 ; i<4 ; i++) + { + f = Face_Alloc(); + f->texdef = texdef; + f->texdef.flags &= ~SURF_KEEP; + f->texdef.contents &= ~CONTENTS_KEEP; +// f->texdef.flags |= SURF_PATCH; + f->next = b->brush_faces; + b->brush_faces = f; + j = (i+1)%4; + + VectorCopy (pts[j][1], f->planepts[0]); + VectorCopy (pts[i][1], f->planepts[1]); + VectorCopy (pts[i][0], f->planepts[2]); + } + + f = Face_Alloc(); + f->texdef = texdef; + f->texdef.flags &= ~SURF_KEEP; + f->texdef.contents &= ~CONTENTS_KEEP; +// f->texdef.flags |= SURF_PATCH; + f->next = b->brush_faces; + b->brush_faces = f; + + VectorCopy (pts[0][1], f->planepts[0]); + VectorCopy (pts[1][1], f->planepts[1]); + VectorCopy (pts[2][1], f->planepts[2]); + + f = Face_Alloc(); + f->texdef = texdef; + f->texdef.flags &= ~SURF_KEEP; + f->texdef.contents &= ~CONTENTS_KEEP; +// f->texdef.flags |= SURF_PATCH; + f->next = b->brush_faces; + b->brush_faces = f; + + VectorCopy (pts[2][0], f->planepts[0]); + VectorCopy (pts[1][0], f->planepts[1]); + VectorCopy (pts[0][0], f->planepts[2]); + + Brush_Build(b); +} + +void WINAPI Patch_Rebuild(patchMesh_t *p) +{ + vec3_t vMin, vMax; + Patch_CalcBounds(p, vMin, vMax); + Brush_RebuildBrush(p->pSymbiot, vMin, vMax); + p->bDirty = true; +} + +/* +================== +AddBrushForPatch +================== + adds a patch brush and ties it to this patch id +*/ +brush_t* AddBrushForPatch(patchMesh_t *pm, bool bLinkToWorld ) +{ + // find the farthest points in x,y,z + vec3_t vMin, vMax; + Patch_CalcBounds(pm, vMin, vMax); + + for (int j = 0; j < 3; j++) + { + if (vMin[j] == vMax[j]) + { + vMin[j] -= 4; + vMax[j] += 4; + } + } + + brush_t *b = Brush_Create(vMin, vMax, &g_qeglobals.d_texturewin.texdef); + + // FIXME: this entire type of linkage needs to be fixed + b->patchBrush = true; + b->pPatch = pm; + pm->pSymbiot = b; + pm->bSelected = false; + pm->bOverlay = false; + pm->bDirty = true; + pm->nListID = -1; + + if (bLinkToWorld) + { + Brush_AddToList (b, &active_brushes); + Entity_LinkBrush (world_entity, b); + Brush_Build(b); + } + + return b; +} + +void Patch_SetPointIntensities(int n) +{ +#if 0 + patchMesh_t *p = patchMeshes[n]; + for (int i = 0; i < p->width; i++) + { + for (int j = 0; j < p->height; j++) + { + + } + } +#endif +} + +// very approximate widths and heights + +/* +================== +Patch_Width +================== +*/ +float Patch_Width(patchMesh_t *p) +{ + float f = 0; + for (int i = 0; i < p->width-1; i++) + { + vec3_t vTemp; + VectorSubtract(p->ctrl[i][0].xyz, p->ctrl[i+1][0].xyz, vTemp); + f += VectorLength(vTemp); + } + return f; +} + +float Patch_WidthDistanceTo(patchMesh_t *p, int j) +{ + float f = 0; + for (int i = 0; i < j; i++) + { + vec3_t vTemp; + VectorSubtract(p->ctrl[i][0].xyz, p->ctrl[i+1][0].xyz, vTemp); + f += VectorLength(vTemp); + } + return f; +} + + + +/* +================== +Patch_Height +================== +*/ +float Patch_Height(patchMesh_t *p) +{ + float f = 0; + for (int i = 0; i < p->height-1; i++) + { + vec3_t vTemp; + VectorSubtract(p->ctrl[0][i].xyz, p->ctrl[0][i+1].xyz, vTemp); + f += VectorLength(vTemp); + } + return f; +} + +float Patch_HeightDistanceTo(patchMesh_t *p, int j) +{ + float f = 0; + for (int i = p->height-1; i > j; i--) + { + vec3_t vTemp; + VectorSubtract(p->ctrl[0][i].xyz, p->ctrl[0][i-1].xyz, vTemp); // reverse order for T coords + f += VectorLength(vTemp); + } + return f; +} + + + +/* +================== +Patch_Naturalize +================== +texture = TotalTexture * LengthToThisControlPoint / TotalControlPointLength + +dist( this control point to first control point ) / dist ( last control pt to first) +*/ +void WINAPI Patch_Naturalize(patchMesh_t *p) +{ + int nWidth = (int)(p->d_texture->width * g_pGameDescription->mTextureDefaultScale); + int nHeight = (int)(p->d_texture->height * g_pGameDescription->mTextureDefaultScale); + float fPWidth = Patch_Width(p); + float fPHeight = Patch_Height(p); + float xAccum = 0.0f; + + for ( int i = 0; i < p->width ; i++ ) + { + float yAccum = 0.0f; + for ( int j = p->height-1; j >= 0 ; j-- ) + { + p->ctrl[i][j].st[0] = (fPWidth / nWidth) * xAccum / fPWidth; + p->ctrl[i][j].st[1] = (fPHeight / nHeight) * yAccum / fPHeight; + yAccum = Patch_HeightDistanceTo(p,j-1); + //p->ctrl[i][j][3] = (fPWidth / nWidth) * (float)i / (p->width - 1); + //p->ctrl[i][j][4] = (fPHeight/ nHeight) * (float)j / (p->height - 1); + } + xAccum = Patch_WidthDistanceTo(p,i+1); + } + p->bDirty = true; +} + +/* + if (bIBevel) + { + VectorCopy(p->ctrl[1][0], p->ctrl[1][1]); + } + + if (bIEndcap) + { + VectorCopy(p->ctrl[3][0], p->ctrl[4][1]); + VectorCopy(p->ctrl[2][0], p->ctrl[3][1]); + VectorCopy(p->ctrl[2][0], p->ctrl[2][1]); + VectorCopy(p->ctrl[2][0], p->ctrl[1][1]); + VectorCopy(p->ctrl[1][0], p->ctrl[0][1]); + VectorCopy(p->ctrl[1][0], p->ctrl[0][2]); + VectorCopy(p->ctrl[1][0], p->ctrl[1][2]); + VectorCopy(p->ctrl[2][0], p->ctrl[2][2]); + VectorCopy(p->ctrl[3][0], p->ctrl[3][2]); + VectorCopy(p->ctrl[3][0], p->ctrl[4][2]); + } +*/ + +int Index3By[][2] = +{ + {0,0}, + {1,0}, + {2,0}, + {2,1}, + {2,2}, + {1,2}, + {0,2}, + {0,1}, + {0,0}, + {0,0}, + {0,0}, + {0,0}, + {0,0}, + {0,0}, + {0,0} +}; + +int Index5By[][2] = +{ + {0,0}, + {1,0}, + {2,0}, + {3,0}, + {4,0}, + {4,1}, + {4,2}, + {4,3}, + {4,4}, + {3,4}, + {2,4}, + {1,4}, + {0,4}, + {0,3}, + {0,2}, + {0,1} +}; + + + +int Interior3By[][2] = +{ + {1,1} +}; + +int Interior5By[][2] = +{ + {1,1}, + {2,1}, + {3,1}, + {1,2}, + {2,2}, + {3,2}, + {1,3}, + {2,3}, + {3,3} +}; + +int Interior3ByCount = sizeof(Interior3By) / sizeof(int[2]); +int Interior5ByCount = sizeof(Interior5By) / sizeof(int[2]); + +extern int Plane_FromPoints(vec3_t p1, vec3_t p2, vec3_t p3, plane_t *plane); +// the bFaceCycle only means we are going through a patch cycling loop +// then we rely on g_vCycleCapNormal to compute the cap + +void Patch_CapTexture(patchMesh_t *p, bool bFaceCycle = false) +{ + vec3_t vProjection, vX, vY; + qtexture_t *texture = p->pShader->getTexture(); + plane_t Plane1, Plane2, Plane3; + bool bThing=true; + + if (bFaceCycle) + VectorCopy (g_vCycleCapNormal, vProjection); + + else + { + VectorClear ( vProjection ); + + // find normal for plane from first 3 corner points + if (!Plane_FromPoints(p->ctrl[0][0].xyz,p->ctrl[0][p->height-1].xyz,p->ctrl[p->width-1][p->height-1].xyz,&Plane1)) + { + VectorClear ( Plane3.normal ); + bThing = false; + } + + // find normal for plane from next 3 corner points + if (!Plane_FromPoints(p->ctrl[p->width-1][p->height-1].xyz,p->ctrl[p->width-1][0].xyz,p->ctrl[0][0].xyz,&Plane2)) + { + if (bThing) + { + VectorCopy ( Plane1.normal, Plane3.normal ); + Plane3.dist = Plane1.dist; + } + } + + else + { + if (bThing) + // find average plane for all 4 corner points + { + for (int n = 0; n <= 2; n++) + { + Plane3.normal[n] = (Plane1.normal[n] + Plane2.normal[n]) / 2; + } + Plane3.dist = (Plane1.dist + Plane2.dist) / 2; + } + else + { + VectorCopy ( Plane2.normal, Plane3.normal ); + Plane3.dist = Plane2.dist; + } + } + + // get best axis for projection from average plane + //Sys_Printf("surface normal1: (%f,%f,%f)\n",Plane1.normal[0],Plane1.normal[1],Plane1.normal[0]); + //Sys_Printf("surface normal2: (%f,%f,%f)\n",Plane2.normal[0],Plane2.normal[1],Plane2.normal[0]); + //Sys_Printf("surface normal3: (%f,%f,%f)\n",Plane3.normal[0],Plane3.normal[1],Plane3.normal[0]); + TextureAxisFromPlane(&Plane3, vX, vY); + } + + for (int w = 0; w < p->width; w++) + { + for (int h = 0; h < p->height; h++) + { + if (vProjection[2] == 1.0f || (vX[0] == 1.0f && vY[1] == -1.0f)) + { + p->ctrl[w][h].st[0] = p->ctrl[w][h].xyz[0] / (texture->width * g_pGameDescription->mTextureDefaultScale); + p->ctrl[w][h].st[1] = p->ctrl[w][h].xyz[1] / (texture->height * g_pGameDescription->mTextureDefaultScale) * -1; + } + else if (vProjection[0] == 1.0f || (vX[1] == 1.0f && vY[2] == -1.0f)) + { + p->ctrl[w][h].st[0] = p->ctrl[w][h].xyz[1] / (texture->width * g_pGameDescription->mTextureDefaultScale); + p->ctrl[w][h].st[1] = p->ctrl[w][h].xyz[2] / (texture->height * g_pGameDescription->mTextureDefaultScale) * -1; + } + else if (vProjection[1] == 1.0f || (vX[0] == 1.0f && vY[2] == -1.0f)) + { + p->ctrl[w][h].st[0] = p->ctrl[w][h].xyz[0] / (texture->width * g_pGameDescription->mTextureDefaultScale); + p->ctrl[w][h].st[1] = p->ctrl[w][h].xyz[2] / (texture->height * g_pGameDescription->mTextureDefaultScale) * -1; + } + //Sys_Printf("(%i,%i) (%f,%f,%f) (%f,%f) %f\n",w,h, + // p->ctrl[w][h].xyz[0],p->ctrl[w][h].xyz[1],p->ctrl[w][h].xyz[2], + // p->ctrl[w][h].st[0],p->ctrl[w][h].st[1],p->ctrl[w][h].normal); + } + } + // make sure it will rebuild + p->bDirty = true; +} + +void FillPatch(patchMesh_t *p, vec3_t v) +{ + for (int i = 0; i < p->width; i++) + { + for (int j = 0; j < p->height; j++) + { + VectorCopy(v, p->ctrl[i][j].xyz); + } + } +} + +// temporarily moved function to allow use in Cap() and CapSpecial() +void patchInvert(patchMesh_t *p) +{ + drawVert_t vertTemp; + p->bDirty = true; + for ( int i = 0 ; i < p->width ; i++ ) + { + for (int j = 0; j < p->height / 2; j++) + { + memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t)); + memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t)); + memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t)); + } + } +} + +brush_t* Cap(patchMesh_t *pParent, bool bByColumn, bool bFirst) +{ + brush_t *b; + patchMesh_t *p; + vec3_t vMin, vMax; + int i, j; + + bool bSmall = true; + // make a generic patch + if (pParent->width <= 9) + { + b = Patch_GenericMesh(3, 3, 2, false); + } + else + { + b = Patch_GenericMesh(5, 5, 2, false); + bSmall = false; + } + + if (!b) + { + Sys_Printf("Unable to cap. You may need to ungroup the patch.\n"); + return NULL; + } + + p = b->pPatch; + p->type |= PATCH_CAP; + + vMin[0] = vMin[1] = vMin[2] = 9999; + vMax[0] = vMax[1] = vMax[2] = -9999; + + // we seam the column edge, FIXME: this might need to be able to seem either edge + // + int nSize = (bByColumn) ? pParent->width : pParent->height; + int nIndex = (bFirst) ? 0 : (bByColumn) ? pParent->height-1 : pParent->width-1; + + FillPatch(p, pParent->ctrl[0][nIndex].xyz); + + for (i = 0; i < nSize; i++) + { + if (bByColumn) + { + if (bSmall) + { + VectorCopy(pParent->ctrl[i][nIndex].xyz, p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz); + } + else + { + VectorCopy(pParent->ctrl[i][nIndex].xyz, p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz); + } + } + else + { + if (bSmall) + { + VectorCopy(pParent->ctrl[nIndex][i].xyz, p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz); + } + else + { + VectorCopy(pParent->ctrl[nIndex][i].xyz, p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz); + } + } + + for (j = 0; j < 3; j++) + { + float f = (bSmall) ? p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz[j] : p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz[j]; + if (f < vMin[j]) + vMin[j] = f; + if (f > vMax[j]) + vMax[j] = f; + } + } + + vec3_t vTemp; + for (j = 0; j < 3; j++) + { + vTemp[j] = vMin[j] + fabs((vMax[j] - vMin[j]) * 0.5); + } + int nCount = (bSmall) ? Interior3ByCount : Interior5ByCount; + for (j = 0; j < nCount; j++) + { + if (bSmall) + { + VectorCopy(vTemp, p->ctrl[Interior3By[j][0]][Interior3By[j][1]].xyz); + } + else + { + VectorCopy(vTemp, p->ctrl[Interior5By[j][0]][Interior5By[j][1]].xyz); + } + } + + if (bFirst) + patchInvert(p); + /* + { + drawVert_t vertTemp; + for (i = 0; i < p->width; i++) + { + for (j = 0; j < p->height / 2; j++) + { + memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t)); + memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t)); + memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t)); + } + } + } + */ + + Patch_Rebuild(p); + Patch_CapTexture(p); + return p->pSymbiot; +} + +brush_t* CapSpecial(patchMesh_t *pParent, int nType, bool bFirst) +{ + + brush_t *b; + patchMesh_t *p; + vec3_t vMin, vMax, vTemp; + int i, j; + + if (nType == IENDCAP) + b = Patch_GenericMesh(5, 3, 2, false); + else + b = Patch_GenericMesh(3, 3, 2, false); + + if (!b) + { + Sys_Printf("Unable to cap. Make sure you ungroup before re-capping."); + return NULL; + } + + p = b->pPatch; + p->type |= PATCH_CAP; + + vMin[0] = vMin[1] = vMin[2] = 9999; + vMax[0] = vMax[1] = vMax[2] = -9999; + + // int nSize = pParent->width; + int nIndex = (bFirst) ? 0 : pParent->height-1; + + // parent bounds are used for some things + Patch_CalcBounds(pParent, vMin, vMax); + + for (j = 0; j < 3; j++) + { + vTemp[j] = vMin[j] + fabs((vMax[j] - vMin[j]) * 0.5); + } + + if (nType == IBEVEL) + { + VectorCopy(pParent->ctrl[0][nIndex].xyz, p->ctrl[0][0].xyz); + VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[0][2].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[0][1].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[2][2].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][0].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][1].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][2].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[2][0].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[2][1].xyz); + } + else if (nType == BEVEL) + { + vec3_t p1, p2, p3, p4; //, temp, dir; + + VectorCopy(pParent->ctrl[0][nIndex].xyz, p3); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p1); + VectorCopy(pParent->ctrl[2][nIndex].xyz, p2); + + //Sys_Printf("CapSpecial() p1: %f %f %f\n",p1[0],p1[1],p1[2]); + //Sys_Printf("CapSpecial() p2: %f %f %f\n",p2[0],p2[1],p2[2]); + //Sys_Printf("CapSpecial() p3: %f %f %f\n",p3[0],p3[1],p3[2]); + + VectorSubtract(p2, p1, p4); + VectorAdd(p3, p4, p4); + // spog - use opposite-point-on-parallelogram to find p4 + /* + VectorSubtract(p3, p2, dir); + VectorNormalize(dir); + VectorSubtract(p1, p2, temp); + vec_t dist = _DotProduct(temp, dir); + VectorScale(dir, dist, temp); + VectorAdd(p2, temp, temp); + VectorSubtract(temp, p1, temp); + VectorScale(temp, 2, temp); + VectorAdd(p1, temp, p4); + */ + + //Sys_Printf("CapSpecial() p1: %f %f %f\n",p1[0],p1[1],p1[2]); + //Sys_Printf("CapSpecial() p2: %f %f %f\n",p2[0],p2[1],p2[2]); + //Sys_Printf("CapSpecial() p3: %f %f %f\n",p3[0],p3[1],p3[2]); + //Sys_Printf("CapSpecial() p4: %f %f %f\n",p4[0],p4[1],p4[2]); + + VectorCopy(p4, p->ctrl[0][0].xyz); + VectorCopy(p4, p->ctrl[1][0].xyz); + VectorCopy(p4, p->ctrl[0][1].xyz); + VectorCopy(p4, p->ctrl[1][1].xyz); + VectorCopy(p4, p->ctrl[0][2].xyz); + VectorCopy(p4, p->ctrl[1][2].xyz); + VectorCopy(p2, p->ctrl[2][0].xyz); + VectorCopy(p1, p->ctrl[2][1].xyz); + VectorCopy(p3, p->ctrl[2][2].xyz); + + } + else if (nType == ENDCAP) + { + VectorAdd(pParent->ctrl[4][nIndex].xyz, pParent->ctrl[0][nIndex].xyz, vTemp); + VectorScale(vTemp, 0.5, vTemp); + VectorCopy(pParent->ctrl[0][nIndex].xyz, p->ctrl[0][0].xyz); + VectorCopy(vTemp, p->ctrl[1][0].xyz); + VectorCopy(pParent->ctrl[4][nIndex].xyz, p->ctrl[2][0].xyz); + + VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[0][2].xyz); + VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[1][2].xyz); + VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][2].xyz); + VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[1][1].xyz); + + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[0][1].xyz); + VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[2][1].xyz); + } + else + { + VectorCopy(pParent->ctrl[4][nIndex].xyz, p->ctrl[0][0].xyz); + VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[1][0].xyz); + VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][0].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[3][0].xyz); + VectorCopy(pParent->ctrl[0][nIndex].xyz, p->ctrl[4][0].xyz); + + VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[0][1].xyz); + VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[1][1].xyz); + VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][1].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[3][1].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[4][1].xyz); + + VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[0][2].xyz); + VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[1][2].xyz); + VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][2].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[3][2].xyz); + VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[4][2].xyz); + } + + + if (!bFirst) + { + drawVert_t vertTemp; + for (i = 0; i < p->width; i++) + { + for (j = 0; j < p->height / 2; j++) + { + memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t)); + memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t)); + memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t)); + } + } + } + + //--Patch_CalcBounds(p, vMin, vMax); + //--Brush_RebuildBrush(p->pSymbiot, vMin, vMax); + Patch_Rebuild(p); + Patch_CapTexture(p); + return p->pSymbiot; +} + +void Patch_CapCurrent() +{ + patchMesh_t *pParent = NULL; + brush_t *b[4]; + brush_t *pCap = NULL; + b[0] = b[1] = b[2] = b[3] = NULL; + int nIndex = 0; + bool b_GroupResult = TRUE; + + if (!QE_SingleBrush(true)) + { + Sys_Printf("Patch_CapCurrent: you must have a single patch selected\n"); + return; + } + + + for (brush_t *pb = selected_brushes.next ; pb != NULL && pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + pParent = pb->pPatch; + // decide which if any ends we are going to cap + // if any of these compares hit, it is a closed patch and as such + // the generic capping will work.. if we do not find a closed edge + // then we need to ask which kind of cap to add + if (VectorCompare(pParent->ctrl[0][0].xyz, pParent->ctrl[pParent->width-1][0].xyz)) + { + pCap = Cap(pParent, true, false); + if (pCap != NULL) + { + b[nIndex++] = pCap; + } + } + if (VectorCompare(pParent->ctrl[0][pParent->height-1].xyz, pParent->ctrl[pParent->width-1][pParent->height-1].xyz)) + { + pCap = Cap(pParent, true, true); + if (pCap != NULL) + { + b[nIndex++] = pCap; + } + } + if (VectorCompare(pParent->ctrl[0][0].xyz, pParent->ctrl[0][pParent->height-1].xyz)) + { + pCap = Cap(pParent, false, false); + if (pCap != NULL) + { + b[nIndex++] = pCap; + } + } + if (VectorCompare(pParent->ctrl[pParent->width-1][0].xyz, pParent->ctrl[pParent->width-1][pParent->height-1].xyz)) + { + pCap = Cap(pParent, false, true); + if (pCap != NULL) + { + b[nIndex++] = pCap; + } + } + } + } + + if (pParent) + { + // if we did not cap anything with the above tests + if (nIndex == 0) + { + int type; + + if (DoCapDlg (&type, &b_GroupResult) == IDOK) + { + b[nIndex++] = CapSpecial(pParent, type, false); + b[nIndex++] = CapSpecial(pParent, type, true); + } + } + + if (nIndex > 0) + { + while (nIndex > 0) + { + nIndex--; + if (b[nIndex]) + { + Select_Brush(b[nIndex]); + } + } + // Gef: Added toggle for capped patch func_group + if(b_GroupResult) { + entity_t *e = Entity_Alloc(); + SetKeyValue(e, "classname", "func_group"); + SetKeyValue(e, "type", "patchCapped"); + Select_GroupEntity(e); + Entity_AddToList(e, &entities); + } + } + } +} + +/* +=============== +BrushToPatchMesh +=============== +*/ +void Patch_BrushToMesh(bool bCone, bool bBevel, bool bEndcap, bool bSquare, int nHeight) +{ + brush_t *b; + patchMesh_t *p; + int i,j; + + if (!QE_SingleBrush()) + return; + + b = selected_brushes.next; + + p = MakeNewPatch(); + + p->d_texture = b->brush_faces->d_texture; + p->pShader = b->brush_faces->pShader; + + p->height = nHeight; + + p->type = PATCH_CYLINDER; + if (bBevel & !bSquare) + { + p->type = PATCH_BEVEL; + p->width = 3; + int nStep = (int)((b->maxs[2] - b->mins[2]) / (p->height-1)); + int nStart = (int)(b->mins[2]); + for (i = 0; i < p->height; i++) + { + p->ctrl[0][i].xyz[0] = b->mins[0]; + p->ctrl[0][i].xyz[1] = b->mins[1]; + p->ctrl[0][i].xyz[2] = nStart; + + p->ctrl[1][i].xyz[0] = b->maxs[0]; + p->ctrl[1][i].xyz[1] = b->mins[1]; + p->ctrl[1][i].xyz[2] = nStart; + + p->ctrl[2][i].xyz[0] = b->maxs[0]; + p->ctrl[2][i].xyz[1] = b->maxs[1]; + p->ctrl[2][i].xyz[2] = nStart; + nStart += nStep; + } + } + else if (bEndcap & !bSquare) + { + p->type = PATCH_ENDCAP; + p->width = 5; + int nStep = (int)((b->maxs[2] - b->mins[2]) / (p->height-1)); + int nStart = (int)(b->mins[2]); + for (i = 0; i < p->height; i++) + { + p->ctrl[0][i].xyz[0] = b->mins[0]; + p->ctrl[0][i].xyz[1] = b->mins[1]; + p->ctrl[0][i].xyz[2] = nStart; + + p->ctrl[1][i].xyz[0] = b->mins[0]; + p->ctrl[1][i].xyz[1] = b->maxs[1]; + p->ctrl[1][i].xyz[2] = nStart; + + p->ctrl[2][i].xyz[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) * 0.5); + p->ctrl[2][i].xyz[1] = b->maxs[1]; + p->ctrl[2][i].xyz[2] = nStart; + + p->ctrl[3][i].xyz[0] = b->maxs[0]; + p->ctrl[3][i].xyz[1] = b->maxs[1]; + p->ctrl[3][i].xyz[2] = nStart; + + p->ctrl[4][i].xyz[0] = b->maxs[0]; + p->ctrl[4][i].xyz[1] = b->mins[1]; + p->ctrl[4][i].xyz[2] = nStart; + nStart += nStep; + } + } + else + { + p->width = 9; + p->ctrl[1][0].xyz[0] = b->mins[0]; + p->ctrl[1][0].xyz[1] = b->mins[1]; + + p->ctrl[3][0].xyz[0] = b->maxs[0]; + p->ctrl[3][0].xyz[1] = b->mins[1]; + + p->ctrl[5][0].xyz[0] = b->maxs[0]; + p->ctrl[5][0].xyz[1] = b->maxs[1]; + + p->ctrl[7][0].xyz[0] = b->mins[0]; + p->ctrl[7][0].xyz[1] = b->maxs[1]; + + for ( i = 1 ; i < p->width - 1 ; i += 2 ) + { + + p->ctrl[i][0].xyz[2] = b->mins[2]; + + VectorCopy( p->ctrl[i][0].xyz, p->ctrl[i][2].xyz ); + + p->ctrl[i][2].xyz[2] = b->maxs[2]; + + p->ctrl[i][1].xyz[0] = ( p->ctrl[i][0].xyz[0] + p->ctrl[i][2].xyz[0] ) * 0.5; + p->ctrl[i][1].xyz[1] = ( p->ctrl[i][0].xyz[1] + p->ctrl[i][2].xyz[1] ) * 0.5; + p->ctrl[i][1].xyz[2] = ( p->ctrl[i][0].xyz[2] + p->ctrl[i][2].xyz[2] ) * 0.5; + } + InterpolateInteriorPoints( p ); + + if (bSquare) + { + if (bBevel || bEndcap) + { + if (bBevel) + { + for (i = 0; i < p->height; i++) + { + VectorCopy(p->ctrl[1][i].xyz, p->ctrl[2][i].xyz); + VectorCopy(p->ctrl[7][i].xyz, p->ctrl[6][i].xyz); + } + } + else + { + for (i = 0; i < p->height; i++) + { + VectorCopy(p->ctrl[5][i].xyz, p->ctrl[4][i].xyz); + VectorCopy(p->ctrl[1][i].xyz, p->ctrl[2][i].xyz); + VectorCopy(p->ctrl[7][i].xyz, p->ctrl[6][i].xyz); + VectorCopy(p->ctrl[8][i].xyz, p->ctrl[7][i].xyz); + } + } + } + else + { + for (i = 0; i < p->width-1; i ++) + { + for (j = 0; j < p->height; j++) + { + VectorCopy(p->ctrl[i+1][j].xyz, p->ctrl[i][j].xyz); + } + } + for (j = 0; j < p->height; j++) + { + VectorCopy(p->ctrl[0][j].xyz, p->ctrl[8][j].xyz); + } + } + } + } + + + Patch_Naturalize(p); + + if (bCone) + { + p->type = PATCH_CONE; + float xc = (b->maxs[0] + b->mins[0]) * 0.5; + float yc = (b->maxs[1] + b->mins[1]) * 0.5; + + for ( i = 0 ; i < p->width ; i ++) + { + p->ctrl[i][2].xyz[0] = xc; + p->ctrl[i][2].xyz[1] = yc; + } + } + + b = AddBrushForPatch(p); + + Select_Delete(); + Select_Brush(b); + +} + +/* +================== +Patch_GenericMesh +================== +*/ +brush_t* Patch_GenericMesh(int nWidth, int nHeight, int nOrientation, bool bDeleteSource, bool bOverride) +{ + int i,j; + + if (nHeight < 3 || nHeight > 15 || nWidth < 3 || nWidth > 15) + { + Sys_Printf("Invalid patch width or height.\n"); + return NULL; + } + + if (! bOverride && !QE_SingleBrush()) + { + Sys_Printf("Error: you must have a single brush selected\n"); + return NULL; + } + + patchMesh_t* p = MakeNewPatch(); + p->pShader = g_qeglobals.d_texturewin.pShader; + p->d_texture = g_qeglobals.d_texturewin.pShader->getTexture(); + + p->width = nWidth; + p->height = nHeight; + p->type = PATCH_GENERIC; + + int nFirst = 0; + int nSecond = 1; + if (nOrientation == 0) + { + nFirst = 1; + nSecond = 2; + } + else if (nOrientation == 1) + { + nSecond = 2; + } + + brush_t *b = selected_brushes.next; + // set the workzone to this brush, use it later to create the patch points + UpdateWorkzone_ForBrush( b ); + + int xStep = (int)(b->mins[nFirst]); + float xAdj = fabs((b->maxs[nFirst] - b->mins[nFirst]) / (nWidth - 1)); + float yAdj = fabs((b->maxs[nSecond] - b->mins[nSecond]) / (nHeight - 1)); + + for (i = 0; i < nWidth; i++) + { + int yStep = (int)(b->mins[nSecond]); + for (j = 0; j < nHeight; j++) + { + p->ctrl[i][j].xyz[nFirst] = xStep; + p->ctrl[i][j].xyz[nSecond] = yStep; + // create patch based on workzone + p->ctrl[i][j].xyz[nOrientation] = g_qeglobals.d_work_max[nOrientation]; + yStep += (int)yAdj; + } + xStep += (int)xAdj; + } + + Patch_Naturalize(p); + + b = AddBrushForPatch(p); + if (bDeleteSource) + { + Select_Delete(); + Select_Brush(b); + } + + return b; + //g_qeglobals.d_select_mode = sel_curvepoint; +} + +/* +================== +PointInMoveList +================== +*/ +int PointInMoveList(float *pf) +{ + for (int i = 0; i < g_qeglobals.d_num_move_points; i++) + { + if (pf == &g_qeglobals.d_move_points[i][0]) + return i; + } + return -1; +} + +/* +================== +PointValueInMoveList +================== +*/ +int PointValueInMoveList(vec3_t v) +{ + for (int i = 0; i < g_qeglobals.d_num_move_points; i++) + { + if (VectorCompare(v, g_qeglobals.d_move_points[i])) + return i; + } + return -1; +} + + +/* +================== +RemovePointFromMoveList +================== +*/ +void RemovePointFromMoveList(vec3_t v) +{ + int n; + while ( (n = PointValueInMoveList(v)) >= 0) + { + for (int i = n; i < g_qeglobals.d_num_move_points-1; i++) + { + g_qeglobals.d_move_points[i] = g_qeglobals.d_move_points[i+1]; + } + g_qeglobals.d_num_move_points--; + } +} + +/* +================== +ColumnSelected +================== +*/ +bool ColumnSelected(patchMesh_t* p, int nCol) +{ + for (int i = 0; i < p->height; i++) + { + if (PointInMoveList(p->ctrl[nCol][i].xyz) == -1) + return false; + } + return true; +} + +/* +================== +AddPoint +================== +*/ +void AddPoint(patchMesh_t* p, vec3_t v, bool bWeldOrDrill = true) +{ + int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0; + int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2; + g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = v; + if ((g_bPatchWeld || g_bPatchDrillDown) && bWeldOrDrill) + { + for ( int i = 0 ; i < p->width ; i++ ) + { + for ( int j = 0 ; j < p->height ; j++ ) + { + if (g_bPatchWeld) + { + if ( VectorCompare(v, p->ctrl[i][j].xyz) + && PointInMoveList(p->ctrl[i][j].xyz) == -1) + { + g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz; + continue; + } + } + if (g_bPatchDrillDown && g_nPatchClickedView != W_CAMERA) + { + if ( (fabs(v[nDim1] - p->ctrl[i][j].xyz[nDim1]) <= EQUAL_EPSILON) + &&(fabs(v[nDim2] - p->ctrl[i][j].xyz[nDim2]) <= EQUAL_EPSILON)) + { + if (PointInMoveList(p->ctrl[i][j].xyz) == -1) + { + g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz; + continue; + } + } + } + } + } + } +} + +/* +================== +SelectRow +================== +*/ +void SelectRow(patchMesh_t* p, int nRow, bool bMulti) +{ + if (!bMulti) + g_qeglobals.d_num_move_points = 0; + for (int i = 0; i < p->width; i++) + { + AddPoint(p, p->ctrl[i][nRow].xyz, false); + } + //Sys_Printf("Selected Row %d\n", nRow); +} + +/* +================== +SelectColumn +================== +*/ +void SelectColumn(patchMesh_t* p, int nCol, bool bMulti) +{ + if (!bMulti) + g_qeglobals.d_num_move_points = 0; + for (int i = 0; i < p->height; i++) + { + AddPoint(p, p->ctrl[nCol][i].xyz, false); + } + //Sys_Printf("Selected Col %d\n", nCol); +} + + +/* +================== +AddPatchMovePoint +================== +*/ +void AddPatchMovePoint(vec3_t v, bool bMulti, bool bFull) +{ + if (!g_bSameView && !bMulti && !bFull) + { + g_bSameView = true; + //return; // was causing odd behaviour on patch vertex selection + } + + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t* p = pb->pPatch; + for ( int i = 0 ; i < p->width ; i++ ) + { + for ( int j = 0 ; j < p->height ; j++ ) + { + if (VectorCompare(v, p->ctrl[i][j].xyz)) + { + if (PointInMoveList(p->ctrl[i][j].xyz) == -1) + { + if (bFull) // if we want the full row/col this is on + { + SelectColumn(p, i, bMulti); + } + else + { + if (!bMulti) + g_qeglobals.d_num_move_points = 0; + AddPoint(p, p->ctrl[i][j].xyz); + //Sys_Printf("Selected col:row %d:%d\n", i, j); + } + //--if (!bMulti) + return; + } + else + { + if (bFull) + { + if (ColumnSelected(p, i)) + { + SelectRow(p, j, bMulti); + } + else + { + SelectColumn(p, i, bMulti); + } + return; + } + //if (!bMulti) + //{ + // g_qeglobals.d_num_move_points = 0; + // AddPoint(p, p->ctrl[i][j].xyz); + //} + if (bMulti)// if (g_bSameView) // this is not having desired effect + { + RemovePointFromMoveList(v); + return; + } + } + } + } + } + } + } +} + +/* +================== +Patch_UpdateSelected +================== +*/ +void Patch_UpdateSelected(vec3_t vMove) +{ + int i;//, j; + for (i=0 ; i < g_qeglobals.d_num_move_points ; i++) + { + VectorAdd (g_qeglobals.d_move_points[i], vMove, g_qeglobals.d_move_points[i]); + if (g_qeglobals.d_num_move_points == 1) + { + } + } + + //--patchMesh_t* p = &patchMeshes[g_nSelectedPatch]; + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t* p = pb->pPatch; + +#if 0 //moving to SelectCurvePointByRay + g_qeglobals.d_numpoints = 0; + for (i = 0 ; i < p->width ; i++ ) + { + for ( j = 0 ; j < p->height ; j++ ) + { + VectorCopy (p->ctrl[i][j].xyz, g_qeglobals.d_points[g_qeglobals.d_numpoints]); + if (g_qeglobals.d_numpoints < MAX_POINTS-1) + { + g_qeglobals.d_numpoints++; + } + } + } +#endif + vec3_t vMin, vMax; + Patch_CalcBounds(p, vMin, vMax); + Brush_RebuildBrush(p->pSymbiot, vMin, vMax); + } + } + //Brush_Free(p->pSymbiot); + //Select_Brush(AddBrushForPatch(g_nSelectedPatch)); +} + + + +/* +=============== +SampleSinglePatch +=============== +*/ +void SampleSinglePatch (float ctrl[3][3][5], float u, float v, float out[5]) { + float vCtrl[3][5]; + int vPoint; + int axis; + + // find the control points for the v coordinate + for (vPoint = 0 ; vPoint < 3 ; vPoint++) + { + for (axis = 0 ; axis < 5 ; axis++) + { + float a, b, c; + float qA, qB, qC; + + a = ctrl[0][vPoint][axis]; + b = ctrl[1][vPoint][axis]; + c = ctrl[2][vPoint][axis]; + qA = a - 2 * b + c; + qB = 2 * b - 2 * a; + qC = a; + + vCtrl[vPoint][axis] = qA * u * u + qB * u + qC; + } + } + + // interpolate the v value + for (axis = 0 ; axis < 5 ; axis++) + { + float a, b, c; + float qA, qB, qC; + + a = vCtrl[0][axis]; + b = vCtrl[1][axis]; + c = vCtrl[2][axis]; + qA = a - 2 * b + c; + qB = 2 * b - 2 * a; + qC = a; + + out[axis] = qA * v * v + qB * v + qC; + } +} + +//spog - Curve LOD stuff starts + +float ShadeForNormal(vec3_t normal) +{ + float f; + + vec3_t L; + L[0] = 1.0f; + L[1] = 1.0f; + L[2] = 1.0f; + + + // quick diffuse shading + f = DotProduct(L, normal); + + // range 0.5 to 1.0 + f = (f+1)/4.0f; + //if (f < 0.0f) f = 0.0f; + + f += 0.5f; + + return f; +} + +void ShadeVertex (drawVert_t &p) +{ + p.lightmap[0] = ShadeForNormal(p.normal); +} + + +void Patch_DrawNormals(patchMesh_t *patch) +{ + int row, col; + vec3_t vNormal; + + qglBegin (GL_LINES); + for (col=0; colwidth; col++) + { + for (row=0; rowheight; row++) + { + VectorAdd(patch->ctrl[col][row].xyz, patch->ctrl[col][row].normal, vNormal); + qglVertex3fv (patch->ctrl[col][row].xyz); + qglVertex3fv (vNormal); + } + } + qglEnd (); +} + + +// take an array of three drawVerts, and the addresses of three more drawVerts +// interpolate new XYZST values from the three drawVerts, these are: +// the left sub-control-point, the right sub-control-point and the midpoint of the curve respectively +// store these values in the drawVerts passed to the function +void Patch_CurveSplit(drawVert_t *vCurve[3], drawVert_t &pLeft, drawVert_t &pRight, drawVert_t &pMid, float u) +{ + int i; + //float u = 0.5f; +// float a, b; + drawVert_t v1, v2, v3; +// vec3_t v4; + + for (i=0; i<3; i++) + { + // xyz + v1.xyz[i] = vCurve[1]->xyz[i] - vCurve[0]->xyz[i]; + v2.xyz[i] = vCurve[2]->xyz[i] - vCurve[1]->xyz[i]; + v1.xyz[i] *= u; + v2.xyz[i] *= u; + pLeft.xyz[i] = vCurve[0]->xyz[i] + v1.xyz[i]; + pRight.xyz[i] = vCurve[1]->xyz[i] + v2.xyz[i]; + + v3.xyz[i] = pRight.xyz[i] - pLeft.xyz[i]; + v3.xyz[i] *= u; + pMid.xyz[i] = pLeft.xyz[i] + v3.xyz[i]; + + // normal (weighted average) // no, that's b0rked + //a = 1 / u; // total + //b = u * a; // component 2 + //a = u - b; // component 1 + //pMid.normal[i] = u * ((vCurve[0]->normal[i] * b) + (vCurve[2]->normal[i] * a)); + + if (i==2) continue; + + // st + v1.st[i] = vCurve[1]->st[i] - vCurve[0]->st[i]; + v2.st[i] = vCurve[2]->st[i] - vCurve[1]->st[i]; + v1.st[i] *= u; + v2.st[i] *= u; + pLeft.st[i] = vCurve[0]->st[i] + v1.st[i]; + pRight.st[i] = vCurve[1]->st[i] + v2.st[i]; + + v3.st[i] = pRight.st[i] - pLeft.st[i]; + v3.st[i] *= u; + pMid.st[i] = pLeft.st[i] + v3.st[i]; + } +} + +// take an array of three points, return an index representing the curvature of those three points +// return zero if the curve is a straight line, unless the midpoint is not between the endpoints +float Patch_CurveIndex(vec3_t vCurve[]) +{ + vec3_t vTemp, v1, v2, v3, vClear; +// int i; + float width, angle; + float index, dot; + + VectorClear(vClear); + + VectorSubtract(vCurve[2], vCurve[0], vTemp); + VectorSubtract(vCurve[1], vCurve[0], v1); + VectorSubtract(vCurve[2], vCurve[1], v2); + + if (VectorCompare(v1, vClear) || VectorCompare(vTemp, v1)) // return 0 if 1->2 == 0 or 1->2 == 1->3 + return 0.0f; + + VectorNormalize(v1, v1); + VectorNormalize(v2, v2); + if (VectorCompare(v1, v2)) + return 0.0f; + + VectorCopy(vTemp, v3); + width = VectorNormalize(v3, v3); + + if (VectorCompare(v1, v3) && VectorCompare(v2, v3)) + return 0.0f; + + dot = DotProduct(v1, v2); + + angle = acos(dot) / Q_PI; + + index = width * angle; + + return index; +} + + +// create a new tree root, give it the coordinate values of the drawVert +// return a pointer to the new tree root +BTNode_t *BTree_Create(drawVert_t info) +{ + BTNode_t *BTree = new BTNode_t; + BTree->left = BTree->right = NULL; + VectorCopy(info.xyz, BTree->info.xyz); + VectorCopy(info.xyz, BTree->vMid.xyz); + for (int i=0; i<2; i++) + { + BTree->info.st[i] = info.st[i]; + BTree->vMid.st[i] = info.st[i]; + } + return BTree; +} + +// take ownership of the subtree +// delete the entire subtree +// return a NULL pointer +BTNode_t *BTree_Delete(BTNode_t *pBT) +{ + if (pBT != NULL) + { + BTree_Delete(pBT->left); + BTree_Delete(pBT->right); + delete pBT; + } + return NULL; +} + +// NOT currently used +BTNode_t *BTree_Clear(BTNode_t *pBT, bool bFirst = true) +{ + if (pBT != NULL) + { + BTree_Clear(pBT->left, false); + BTree_Clear(pBT->right, false); + if (!bFirst) delete pBT; + } + return pBT; +} + +// take a pointer to the last item added to the list (this can also be a NULL pointer) +// take a pointer to the root of a subtree, and the patch points to the left and right of it +// add a new item to the subtree list, and add the subtree and its adjacent points to the new item +// return a pointer to the last item added to the subtree list +BTreeList_t *BTree_AddToList(BTreeList_t *pBTList, BTNode_t *pBT, drawVert_t &pLeft, drawVert_t &pRight) +{ + BTreeList_t *newBTList = new BTreeList_t; + newBTList->next = pBTList; + newBTList->pBT = pBT; + VectorCopy(pLeft.xyz, newBTList->vLeft.xyz); + VectorCopy(pRight.xyz, newBTList->vRight.xyz); + VectorCopy(pLeft.normal, newBTList->vLeft.normal); + VectorCopy(pRight.normal, newBTList->vRight.normal); + for (int i=0; i<2; i++) + { + newBTList->vLeft.st[i] = pLeft.st[i]; + newBTList->vRight.st[i] = pRight.st[i]; + } + return newBTList; +} + +// NOT currently used, subtrees are now stored on the patch +// take ownership of the subtree list +// delete the entire list and the subtrees it points to +// return a NULL pointer +BTreeList_t *BTree_DeleteList(BTreeList_t *pBTList) +{ + if (pBTList != NULL) + { + BTree_DeleteList(pBTList->next); + pBTList->pBT = BTree_Delete(pBTList->pBT); + delete pBTList; + } + return NULL; +} + +// take ownership of the subtree list +// delete the entire subtree list, but not the subtrees themselves +// return a NULL pointer +BTreeList_t *BTree_DeletePointerList(BTreeList_t *pBTList) +{ + if (pBTList != NULL) + { + BTree_DeletePointerList(pBTList->next); + delete pBTList; + } + return NULL; +} + +// take a pointer to the last item added to the list of subtree lists +// add a subtree list to the list +// return a pointer to the last item added +BTListList_t *BTree_AddListToList(BTListList_t *pBTListList, BTreeList_t *pBTList) +{ + BTListList_t *newBTListList = new BTListList_t; + newBTListList->next = pBTListList; + newBTListList->list = pBTList; + return newBTListList; +} + + +// take ownership of the list of subtree lists +// delete the entire list of lists, but not the subtrees themselves +// return a NULL pointer +BTListList_t *BTree_DeleteListFromList(BTListList_t *pBTListList) +{ + if (pBTListList != NULL) + { + BTree_DeleteListFromList(pBTListList->next); + pBTListList->list = BTree_DeletePointerList(pBTListList->list); + delete pBTListList; + } + return NULL; +} + +// take a pointer to the last item in the list +// add a NULL linker subtree to the list, setting the "flipped" flag using the left curvepoint normal .. er.. hacky? +BTreeList_t *BTree_AddLinkToList(BTreeList_t *pBTList, bool bFlipped = false) +{ + BTreeList_t *linkBTList = new BTreeList_t; + linkBTList->pBT = NULL; + linkBTList->next = pBTList; + linkBTList->vLeft.normal[0] = (bFlipped) ? 1.0f : 0.0f; + return linkBTList; +} + + +// take an array of three points and the address of a vector +// store midpoint of the bezier curve formed by the three points, in the vector +void Patch_BezierInterpolate(vec3_t vCurve[], vec3_t &pMid) +{ + vec3_t vTemp; + int i; + VectorSubtract(vCurve[2], vCurve[0], vTemp); // Start->End + for (i=0; i<3; i++) + vTemp[i] /= 2; + VectorAdd(vCurve[0], vTemp, vTemp); // midpoint of Start->End + + VectorSubtract(vTemp, vCurve[1], vTemp); // Mid->(midpoint of Start->End) + for (i=0; i<3; i++) + vTemp[i] /= 2; + VectorAdd(vCurve[1], vTemp, pMid); // midpoint of Mid->(midpoint of Start->End) +} + + +// take a pointer to the list of subtrees, and a threshold value +// generate REAL surface curvature for the subtree curves, using bezier interpolation +// if any of the real curves has an index greater than the threshold, return true +bool Patch_MostCurvedRow(BTreeList_t *pBTList, int threshold) +{ + BTreeList_t *p; + float index;//, bestindex = 0; + vec3_t vCurve[3]; + vec3_t vRow[3]; +// int i; + + for (p = pBTList; p != NULL; p = p->next->next) + { + // this row + VectorCopy(p->vLeft.xyz, vCurve[0]); + VectorCopy(p->pBT->info.xyz, vCurve[1]); + VectorCopy(p->vRight.xyz, vCurve[2]); + + index = Patch_CurveIndex(vCurve); + if (index > threshold) + return true; + + if (p->next == NULL) + break; + + if (p->next->pBT == NULL) continue; + + VectorCopy(p->vLeft.xyz, vCurve[0]); + VectorCopy(p->next->vLeft.xyz, vCurve[1]); + VectorCopy(p->next->next->vLeft.xyz, vCurve[2]); + Patch_BezierInterpolate(vCurve, vRow[0]); + + VectorCopy(p->pBT->info.xyz, vCurve[0]); + VectorCopy(p->next->pBT->info.xyz, vCurve[1]); + VectorCopy(p->next->next->pBT->info.xyz, vCurve[2]); + Patch_BezierInterpolate(vCurve, vRow[1]); + + VectorCopy(p->vRight.xyz, vCurve[0]); + VectorCopy(p->next->vRight.xyz, vCurve[1]); + VectorCopy(p->next->next->vRight.xyz, vCurve[2]); + Patch_BezierInterpolate(vCurve, vRow[2]); + + index = Patch_CurveIndex(vRow); + if (index > threshold) + return true; + } + return false; +} + + +// take a pointer to a list of subtrees.. each subtree in the list is a 3-point bezier curve formed by two endpoints owned by the list, and a midpoint subtree node owned by a patch. +// if any of the subtrees are curved above a threshold, create a left and right subsubtree for each subtree in the list. +// if a NULL linker subtree is found, check for an orientation flip - ie. an inverted LOD-match - and create a NULL subsubtree with the same orientation flip +// this effectively generates trees for multiple patches at the same time.. the subtrees are always owned by their respective patches though +void BTree_ListCurveRecurse(BTreeList_t *pBTList) +{ + BTreeList_t *p; + BTreeList_t *leftBTList, *rightBTList; + //drawVert_t pLeft, pRight, pMid; + drawVert_t *vCurve[3]; + int threshold; + //int i; + bool bFlipped = false; + + if (g_PrefsDlg.m_nSubdivisions >= 1) + threshold = g_PrefsDlg.m_nSubdivisions; + + leftBTList = rightBTList = NULL; + + if (Patch_MostCurvedRow(pBTList, threshold)) // split all subtrees in list if any subtree is above threshold + { + //Sys_Printf("| "); + // traverse nodes in list + for (p = pBTList; p != NULL; p=p->next) + { + if (p->pBT == NULL) + { + leftBTList = BTree_AddLinkToList(leftBTList, (p->vLeft.normal[0] == 1.0f)); + rightBTList = BTree_AddLinkToList(rightBTList, (p->vLeft.normal[0] == 1.0f)); + if (p->vLeft.normal[0] == 1.0f) bFlipped = (!bFlipped) ? true : false; // switch bFlipped if true + continue; + } + + // create left node for this subtree + BTNode_t *newLeft = new BTNode_t; + p->pBT->left = newLeft; + newLeft->left = newLeft->right = NULL; + + // create right node for this subtree + BTNode_t *newRight = new BTNode_t; + p->pBT->right = newRight; + newRight->left = newRight->right = NULL; + + // split this node + vCurve[0] = &p->vLeft; + vCurve[1] = &p->pBT->info; + vCurve[2] = &p->vRight; + Patch_CurveSplit(vCurve, newLeft->info, newRight->info, p->pBT->vMid, 0.5); + + memcpy(&newLeft->vMid, &newLeft->info, sizeof(drawVert_t)); + memcpy(&newRight->vMid, &newRight->info, sizeof(drawVert_t)); + + + if (!bFlipped) + { + // add new left subtree to left subtree list + leftBTList = BTree_AddToList(leftBTList, newLeft, p->vLeft, p->pBT->vMid); + + // add new right subtree to right subtree list + rightBTList = BTree_AddToList(rightBTList, newRight, p->pBT->vMid, p->vRight); + } + else + { + // add new left subtree to right subtree list + rightBTList = BTree_AddToList(rightBTList, newLeft, p->vLeft, p->pBT->vMid); + + // add new right subtree to left subtree list + leftBTList = BTree_AddToList(leftBTList, newRight, p->pBT->vMid, p->vRight); + } + } + + // continue tree left + BTree_ListCurveRecurse(leftBTList); + leftBTList = BTree_DeletePointerList(leftBTList); + + // continue tree right + BTree_ListCurveRecurse(rightBTList); + rightBTList = BTree_DeletePointerList(rightBTList); + } +} + +// take mins and maxs values from two brushes +// return true if they intersect on every axis +bool TouchingAABBs(vec3_t mins1, vec3_t maxs1, vec3_t mins2, vec3_t maxs2) +{ + //bool xyz[3]; + vec3_t v1, v2, p1, p2, T; + for (int i=0; i<3; i++) + { + v1[i] = maxs1[i] - mins1[i]; + v2[i] = maxs2[i] - mins2[i]; + v1[i] /=2; + v2[i] /=2; + p1[i] = mins1[i] + v1[i]; + p2[i] = mins2[i] + v2[i]; + // p1 == origin of aabb1 + // p2 == origin of aabb1 + // v1 == displacement of aabb1 + // v1 == displacement of aabb2 + T[i] = p2[i] - p1[i]; // T == vector from aabb1 to aabb2 + if ( fabs(T[i]) > (fabs(v1[i]) + fabs(v2[i])) ) + return false; + } + return true; +} + +// take a pointer to the last item added to pBTList, a pointer to the patch, a row index (start) and a column index +// generate a row of row-curve tree roots, owned by the patch and add the entire column of row-curves to the list, using the row index to decide the order to add +// return a pointer to the last item added to the list +BTreeList_t *Patch_CreateBTListForRows(BTreeList_t *pBTList, patchMesh_t *patch, int start, int col) +{ + int row, pos; + patch->colDirty[(col-1)/2] = true; + + if (start == 0) + { + for (row=0; rowheight; row++) + { + pos = (((col-1)/2)*patch->height)+row; + patch->rowLOD[pos] = BTree_Delete(patch->rowLOD[pos]); + patch->rowLOD[pos] = BTree_Create(patch->ctrl[col][row]); + pBTList = BTree_AddToList(pBTList, patch->rowLOD[pos], patch->ctrl[col-1][row], patch->ctrl[col+1][row]); + } + } + else + { + for (row=patch->height-1; row>=0; row--) + { + pos = (((col-1)/2)*patch->height)+row; + patch->rowLOD[pos] = BTree_Delete(patch->rowLOD[pos]); + patch->rowLOD[pos] = BTree_Create(patch->ctrl[col][row]); + pBTList = BTree_AddToList(pBTList, patch->rowLOD[pos], patch->ctrl[col-1][row], patch->ctrl[col+1][row]); + } + } + return pBTList; +} + +// take a pointer to the last item added to pBTList, a pointer to the patch, a row index and a column index (start) +// generate a row of column-curve tree roots, owned by the patch and add the entire row of column-curves to the list, using the column index to decide the order to add +// return a pointer to the last item added to the list +BTreeList_t *Patch_CreateBTListForCols(BTreeList_t *pBTList, patchMesh_t *patch, int row, int start) +{ + int col, pos; + patch->rowDirty[(row-1)/2] = true; + + if (start == 0) + { + for (col=0; colwidth; col++) + { + pos = (((row-1)/2)*patch->width)+col; + patch->colLOD[pos] = BTree_Delete(patch->colLOD[pos]); + patch->colLOD[pos] = BTree_Create(patch->ctrl[col][row]); + pBTList = BTree_AddToList(pBTList, patch->colLOD[pos], patch->ctrl[col][row-1], patch->ctrl[col][row+1]); + } + } + else + { + for (col=patch->width-1; col>=0; col--) + { + pos = (((row-1)/2)*patch->width)+col; + patch->colLOD[pos] = BTree_Delete(patch->colLOD[pos]); + patch->colLOD[pos] = BTree_Create(patch->ctrl[col][row]); + pBTList = BTree_AddToList(pBTList, patch->colLOD[pos], patch->ctrl[col][row-1], patch->ctrl[col][row+1]); + } + + } + return pBTList; +} + +bool BTree_IsInList(BTreeList_t *pBTList, BTNode_t *pBT) +{ + BTreeList_t *p; + if (pBTList == NULL) return false; + + for (p=pBTList; p != NULL; p=p->next) + { + if (p->pBT != NULL) + { + if (p->pBT == pBT) + return true; + } + } + return false; +} + +int Patch_DegenCurve(vec3_t &start, vec3_t &mid, vec3_t &end) +{ + if (VectorCompare(start, mid) || VectorCompare(end, mid)) + { + if (VectorCompare(start, end)) return 2; + else return 1; + } + else return 0; +} + +// take a pointer to the last item added to the list, and a pointer to a patch (this patch is the owner of the three drawverts) +// take the addresses of three drawVerts, and compare them with the edges of all patches that touch the patch +// if they match an edge, add the tree roots for that section of the matched patch to the list, and recurse for the opposite edge of that patch section. Also, set the matched patch Dirty, so that its drawlists will be rebuilt +// return a pointer to the last item added +BTreeList_t *Patch_FindLODMatches(patchMesh_t *patch, BTreeList_t *pBTList, drawVert_t &pMid, drawVert_t &pLeft, drawVert_t &pRight) +{ + brush_t *pb, *brushlist; + int row, col, i;//, pos; + vec3_t vTemp, v1, v2;//, vClear; + bool bAlreadyAdded; + + //Sys_Printf("Patch_FindLODMatches: called\n"); + + if (VectorCompare(pMid.xyz, pLeft.xyz) && VectorCompare(pMid.xyz, pRight.xyz)) + return pBTList; + + //VectorClear(vClear); + VectorSubtract(pRight.xyz, pLeft.xyz, vTemp); + VectorSubtract(pMid.xyz, pLeft.xyz, v1); + VectorSubtract(pRight.xyz, pMid.xyz, v2); + + //if (VectorCompare(v1, vClear) || VectorCompare(vTemp, v1)) // return null if 1->2 == 0 or 1->2 == 1->3 + // return pBTList; + + VectorNormalize(v1, v1); + VectorNormalize(v2, v2); + if (VectorCompare(v1, v2)) + return pBTList; + + VectorNormalize(vTemp, vTemp); + if (VectorCompare(v1, vTemp) && VectorCompare(v2, vTemp)) + return pBTList; + + brushlist = &active_brushes; + for (i=0; i<2; i++) + { + for (pb = brushlist->next; pb != brushlist; pb=pb->next) + { + if (!pb->patchBrush || pb->pPatch == patch) + continue; + + // ignore this patch if its AABB does not touch the subject patch + if (!TouchingAABBs(patch->pSymbiot->maxs, patch->pSymbiot->mins, pb->maxs, pb->mins)) + continue; + + // all columns of curves + for (col=1; colpPatch->width; col+=2) + { + if (pb->pPatch->colDirty[(col-1)/2]) continue; + + bAlreadyAdded = false; + + // top and bottom curves of this column + for (row=0; rowpPatch->height; row+=pb->pPatch->height-1) + { + if (bAlreadyAdded) + continue; + //if (!BTree_IsInList(pBTList, pb->pPatch->rowLOD[(((col-1)/2)*patch->height)+row])) + // continue; + // ignore this curve if it shares no mid ctrl point with the test curve + if (!VectorCompare (pb->pPatch->ctrl[col][row].xyz, pMid.xyz)) + continue; + // ignore this curve if it is degenerate + if (VectorCompare (pb->pPatch->ctrl[col][row].xyz, pb->pPatch->ctrl[col-1][row].xyz) || VectorCompare (pb->pPatch->ctrl[col][row].xyz, pb->pPatch->ctrl[col+1][row].xyz)) + continue; + // if curve matches the test curve directly + if (VectorCompare (pb->pPatch->ctrl[col-1][row].xyz, pLeft.xyz) && VectorCompare (pb->pPatch->ctrl[col+1][row].xyz, pRight.xyz)) + { + // add a blank link as separator + pBTList = BTree_AddLinkToList(pBTList); + // add this entire column, if top, top-to-bottom, else bottom to top + pBTList = Patch_CreateBTListForRows(pBTList, pb->pPatch, row, col); + // continue checking from last curve added to list + pBTList = Patch_FindLODMatches(pb->pPatch, pBTList, pBTList->pBT->info, pBTList->vLeft, pBTList->vRight); + // set flag + pb->pPatch->LODUpdated = true; + bAlreadyAdded = true; + } + // if curve matches test curve but flipped + else if (VectorCompare (pb->pPatch->ctrl[col-1][row].xyz, pRight.xyz) && VectorCompare (pb->pPatch->ctrl[col+1][row].xyz, pLeft.xyz)) + { + pBTList = BTree_AddLinkToList(pBTList, true); // flip + pBTList = Patch_CreateBTListForRows(pBTList, pb->pPatch, row, col); + pBTList = Patch_FindLODMatches(pb->pPatch, pBTList, pBTList->pBT->info, pBTList->vLeft, pBTList->vRight); + pb->pPatch->LODUpdated = true; + bAlreadyAdded = true; + } + } + } + + // all rows of curves + for (row=1; rowpPatch->height; row+=2) + { + if (pb->pPatch->rowDirty[(row-1)/2]) continue; + + bAlreadyAdded = false; + + for (col=0; colpPatch->width; col+=pb->pPatch->width-1) + { + if (bAlreadyAdded) + continue; + //if (BTree_IsInList(pBTList, pb->pPatch->colLOD[(((row-1)/2)*patch->width)+col])) + // continue; + if (!VectorCompare (pb->pPatch->ctrl[col][row].xyz, pMid.xyz)) + continue; + if (VectorCompare (pb->pPatch->ctrl[col][row].xyz, pb->pPatch->ctrl[col][row-1].xyz) || VectorCompare (pb->pPatch->ctrl[col][row].xyz, pb->pPatch->ctrl[col][row+1].xyz)) + continue; + if (VectorCompare (pb->pPatch->ctrl[col][row-1].xyz, pLeft.xyz) && VectorCompare (pb->pPatch->ctrl[col][row+1].xyz, pRight.xyz)) + { + pBTList = BTree_AddLinkToList(pBTList); + pBTList = Patch_CreateBTListForCols(pBTList, pb->pPatch, row, col); + pBTList = Patch_FindLODMatches(pb->pPatch, pBTList, pBTList->pBT->info, pBTList->vLeft, pBTList->vRight); + pb->pPatch->LODUpdated = true; + bAlreadyAdded = true; + } + else if (VectorCompare (pb->pPatch->ctrl[col][row-1].xyz, pRight.xyz) && VectorCompare (pb->pPatch->ctrl[col][row+1].xyz, pLeft.xyz)) + { + pBTList = BTree_AddLinkToList(pBTList, true); // flip + pBTList = Patch_CreateBTListForCols(pBTList, pb->pPatch, row, col); + pBTList = Patch_FindLODMatches(pb->pPatch, pBTList, pBTList->pBT->info, pBTList->vLeft, pBTList->vRight); + pb->pPatch->LODUpdated = true; + bAlreadyAdded = true; + } + } + } + } + brushlist = &selected_brushes; + } + return pBTList; +} + +// take a pointer to a patch +// create tree roots for all the rows and columns of curves in the patch, the patch takes ownership of these new tree roots +// generate lists of pointers to all the trees in all the patches in the map which need to match the LOD of trees owned by this patch +// store all the lists in a list of lists +// recursively generate the rest of every tree in each list in the list +void Patch_CreateLODTrees(patchMesh_t *patch) +{ + BTreeList_t *pBTList; + int col, row, pos;//, rowcount, colcount; + BTListList_t *pLists; + + //Sys_Printf("Patch_CreateMatchedLODTrees: called\n"); + + BTListList_t *LODLists; + LODLists = NULL; + + pBTList = NULL; + + patch->bDirty = false; + patch->LODUpdated = true; + + for(col=1; colwidth; col+=2) + { + if (patch->colDirty[(col-1)/2]) continue; + else patch->colDirty[(col-1)/2] = true; + + // create list for rows of current patch + for(row=0; rowheight; row++) + { + pos = (((col-1)/2)*patch->height)+row; + patch->rowLOD[pos] = BTree_Delete(patch->rowLOD[pos]); + patch->rowLOD[pos] = BTree_Create(patch->ctrl[col][row]); + pBTList = BTree_AddToList(pBTList, patch->rowLOD[pos], patch->ctrl[col-1][row], patch->ctrl[col+1][row]); + } + + //create connection list for first row + pBTList = Patch_FindLODMatches(patch, pBTList, patch->ctrl[col][0], patch->ctrl[col-1][0], patch->ctrl[col+1][0]); + //create connection list for last row + pBTList = Patch_FindLODMatches(patch, pBTList, patch->ctrl[col][row-1], patch->ctrl[col-1][row-1], patch->ctrl[col+1][row-1]); + + LODLists = BTree_AddListToList(LODLists, pBTList); + pBTList = NULL; + } + + pBTList = NULL; + for(row=1; rowheight; row+=2) + { + if (patch->rowDirty[(row-1)/2]) continue; + else patch->rowDirty[(row-1)/2] = true; + + // create list for cols of current patch + for(col=0; colwidth; col++) + { + pos = (((row-1)/2)*patch->width)+col; + patch->colLOD[pos] = BTree_Delete(patch->colLOD[pos]); + patch->colLOD[pos] = BTree_Create(patch->ctrl[col][row]); + pBTList = BTree_AddToList(pBTList, patch->colLOD[pos], patch->ctrl[col][row-1], patch->ctrl[col][row+1]); + } + + //create connection list for first col + pBTList = Patch_FindLODMatches(patch, pBTList, patch->ctrl[0][row], patch->ctrl[0][row-1], patch->ctrl[0][row+1]); + //create connection list for last col + pBTList = Patch_FindLODMatches(patch, pBTList, patch->ctrl[col-1][row], patch->ctrl[col-1][row-1], patch->ctrl[col-1][row+1]); + + LODLists = BTree_AddListToList(LODLists, pBTList); + pBTList = NULL; + } + + for (pLists = LODLists; pLists != NULL; pLists=pLists->next) + BTree_ListCurveRecurse(pLists->list); + LODLists = BTree_DeleteListFromList(LODLists); +} + +int Patch_GetCVTangent(vec3_t &v1, vec3_t &p1, vec3_t &p2, vec3_t &p3) +{ + if (VectorCompare(p1, p2)) + { + if (VectorCompare(p1, p3)) + { + return 2; + } + else VectorSubtract(p3, p1, v1); + return 1; + } + else VectorSubtract(p2, p1, v1); + return 0; +} + +void Patch_CVNormal(vec3_t ctrl[3][3], vec3_t &normal) +{ + vec3_t v1, v2, vTemp1, vTemp2; + int a, b; + + a = Patch_GetCVTangent(v1, ctrl[0][0], ctrl[1][0], ctrl[2][0]); + b = Patch_GetCVTangent(v2, ctrl[0][0], ctrl[0][1], ctrl[0][2]); + + //Sys_Printf("p1: (%1.1f %1.1f %1.1f) p2: (%1.1f %1.1f %1.1f) p2: (%1.1f %1.1f %1.1f)\n", + // ctrl[0][0][0], ctrl[0][0][1], ctrl[0][0][2], ctrl[0][2][0], ctrl[0][2][1], ctrl[0][2][2], ctrl[2][0][0], ctrl[2][0][1], ctrl[2][0][2]); + + if (a == 2) + { + a = Patch_GetCVTangent(v1, ctrl[0][0], ctrl[1][1], ctrl[1][2]); + } + if (b == 2) + { + b = Patch_GetCVTangent(v2, ctrl[0][0], ctrl[1][1], ctrl[2][1]); + } + + if (a == 2) + { + a = Patch_GetCVTangent(v1, ctrl[0][0], ctrl[2][1], ctrl[2][2]); + } + if (b == 2) + { + b = Patch_GetCVTangent(v2, ctrl[0][0], ctrl[1][2], ctrl[2][2]); + } + + CrossProduct(v1, v2, normal); + + + if (normal[0] == 0.0f && normal[1] == 0.0f && normal[2] == 0.0f) + { + // more degenerate cases + vec3_t pMid; + vec3_t vCurve[3]; + /* + if (VectorCompare(ctrl[0][0], ctrl[2][0])) // endcap left + { + if (VectorCompare(ctrl[0][2], ctrl[1][2])) + { + VectorSubtract(ctrl[2][2], ctrl[0][0], v2); + } + else if (VectorCompare(ctrl[1][2], ctrl[2][2])) + { + VectorSubtract(ctrl[0][2], ctrl[0][0], v2); + } + else + a = Patch_DegenCurve(ctrl[0][2], ctrl[1][2], ctrl[2][2]); + if (a == 0) + { + VectorCopy(ctrl[0][2], vCurve[0]); + VectorCopy(ctrl[1][2], vCurve[1]); + VectorCopy(ctrl[2][2], vCurve[2]); + Patch_BezierInterpolate(vCurve, pMid); + VectorSubtract(pMid, ctrl[0][0], v1); + } + + + } + else if (VectorCompare(ctrl[0][0], ctrl[0][2])) // endcap right + { + + if (VectorCompare(ctrl[2][0], ctrl[2][1])) + { + VectorSubtract(ctrl[2][2], ctrl[0][0], v2); + } + else if (VectorCompare(ctrl[2][1], ctrl[2][2])) + { + VectorSubtract(ctrl[2][0], ctrl[0][0], v2); + } + else + + b = Patch_DegenCurve(ctrl[2][0], ctrl[2][1], ctrl[2][2]); + if (b == 0) + { + VectorCopy(ctrl[2][0], vCurve[0]); + VectorCopy(ctrl[2][1], vCurve[1]); + VectorCopy(ctrl[2][2], vCurve[2]); + Patch_BezierInterpolate(vCurve, pMid); + VectorSubtract(pMid, ctrl[0][0], v2); + } + + } + */ + if (VectorCompare(ctrl[0][0], ctrl[2][0])) // bottom degen + { + Patch_GetCVTangent(v1, ctrl[0][0], ctrl[2][1], ctrl[2][2]); + } + else if (VectorCompare(ctrl[0][0], ctrl[0][2])) // left degen + { + Patch_GetCVTangent(v2, ctrl[0][0], ctrl[1][2], ctrl[2][2]); + } + else if (VectorCompare(ctrl[0][2], ctrl[2][2])) // top degen + { + VectorSubtract(ctrl[2][0], ctrl[0][0], v1); + } + else if (VectorCompare(ctrl[2][0], ctrl[2][2])) // right degen + { + VectorSubtract(ctrl[0][2], ctrl[0][0], v2); + } + else // tangents parallel + { + VectorCopy(v1, vTemp1); + VectorCopy(v2, vTemp2); + VectorNormalize(vTemp1, vTemp1); + VectorNormalize(vTemp2, vTemp2); + if (VectorCompare(vTemp1, vTemp2)) // parallel same way + { + VectorSubtract(ctrl[2][0], ctrl[0][0], vTemp1); + VectorNormalize(vTemp1, vTemp1); + if (VectorCompare(vTemp1, vTemp2)) + { + VectorSubtract(ctrl[0][2], ctrl[0][0], v2); + } + else + { + VectorCopy(vTemp1, v1); + } + } + else // parallel opposite way + { + VectorCopy(ctrl[2][0], vCurve[0]); + VectorCopy(ctrl[1][1], vCurve[1]); + VectorCopy(ctrl[0][2], vCurve[2]); + Patch_BezierInterpolate(vCurve, pMid); + VectorSubtract(pMid, ctrl[0][0], v2); + } + } + + CrossProduct(v1, v2, normal); + } +} + +void Patch_CalcCVNormals(patchMesh_t *patch) +{ + int row, col, i, j, n; + vec3_t ctrl[3][3]; + vec3_t normals[4]; + + for (col=0; colwidth; col+=2) + { + for (row=0; rowheight; row+=2) + { + n=0; + if (col+1 != patch->width && row+1 != patch->height) + { + for (i=0; i<3; i++) + for (j=0; j<3; j++) + VectorCopy (patch->ctrl[col+i][row+j].xyz, ctrl[i][j]); + + Patch_CVNormal(ctrl, normals[n]); + VectorNormalize(normals[n], normals[n]); + n++; + } + + if (col-1 >= 0 && row-1 >= 0) + { + for (i=0; i<3; i++) + for (j=0; j<3; j++) + VectorCopy (patch->ctrl[col-i][row-j].xyz, ctrl[i][j]); + + Patch_CVNormal(ctrl, normals[n]); + VectorNormalize(normals[n], normals[n]); + n++; + } + if (col-1 >= 0 && row+1 != patch->height) + { + for (i=0; i<3; i++) + for (j=0; j<3; j++) + VectorCopy (patch->ctrl[col-i][row+j].xyz, ctrl[j][i]); + + Patch_CVNormal(ctrl, normals[n]); + VectorNormalize(normals[n], normals[n]); + n++; + } + if (col+1 != patch->width && row-1 >= 0) + { + for (i=0; i<3; i++) + for (j=0; j<3; j++) + VectorCopy (patch->ctrl[col+i][row-j].xyz, ctrl[j][i]); + + Patch_CVNormal(ctrl, normals[n]); + VectorNormalize(normals[n], normals[n]); + n++; + } + + for (i=0; i<3; i++) + { + if (n == 1) patch->ctrl[col][row].normal[i] = normals[0][i]; + if (n == 2) patch->ctrl[col][row].normal[i] = (normals[0][i] + normals[1][i]) / n; + //if (n == 3) patch->ctrl[col][row].normal[i] = (normals[0][i] + normals[1][i] + normals[2][i]) / n; + if (n == 4) patch->ctrl[col][row].normal[i] = (normals[0][i] + normals[1][i] + normals[2][i] + normals[3][i]) / n; + } + VectorNormalize(patch->ctrl[col][row].normal, patch->ctrl[col][row].normal); + //if (!g_PrefsDlg.m_bGLLighting) + // ShadeVertex(patch->ctrl[col][row]); + } + } +} + + +void BTree_SetNormals(BTNode_t *pBT, vec3_t &normal) +{ + if (pBT != NULL) + { + if (pBT->left != NULL && pBT->right != NULL) + { + VectorCopy(normal, pBT->vMid.normal); + //if (!g_PrefsDlg.m_bGLLighting) + // ShadeVertex(pBT->vMid); + } + BTree_SetNormals(pBT->left, normal); + BTree_SetNormals(pBT->right, normal); + } +} + + +void NormalFromPoints(vec3_t p1, vec3_t p2, vec3_t p3, vec3_t &normal, bool flip = false) +{ + vec3_t v1, v2; + + if (flip) + { + VectorSubtract(p2, p3, v1); //p3->p2 + VectorSubtract(p1, p2, v2); //p2->p1 + } + else + { + VectorSubtract(p2, p1, v1); //p1->p2 + VectorSubtract(p3, p2, v2); //p2->p3 + } + CrossProduct(v1, v2, normal); +} + + +void BTree_GenerateNormals(BTNode_t *pBTMid, BTNode_t *pBTLeft, BTNode_t *pBTRight, bool avg, bool flat, bool nomid, bool noleft, bool noright, /*bool endcap, vec3_t &n1, vec3_t &n2,*/ bool flip) +{ + if (pBTMid != NULL) + { + if (pBTMid->left != NULL && pBTMid->right != NULL) + { + vec3_t normal; + + if (noleft) // left curve is degenerate + { + if (nomid) // mid curve is degenerate + { + NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, normal, flip); + NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip); + } + //else if (endcap) + //{ + // VectorCopy(n1, normal); + // NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip); + //} + else + { + NormalFromPoints(pBTMid->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip); + NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip); + } + } + else if (noright) // right curve is degenerate + { + if (nomid) // mid curve is degenerate + { + NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip); + NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip); + } + //else if (endcap) + //{ + // NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip); + // VectorCopy(n2, pBTRight->vMid.normal); + //} + else + { + NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip); + NormalFromPoints(pBTMid->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip); + } + } + else + { + if (flat) // all curves are semi-degenerate (flat) or degenerate + { + NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTRight->vMid.xyz, normal, flip); + NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTLeft->vMid.xyz, pBTRight->vMid.normal, flip); + } + else + { + NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip); + NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip); + } + } + + VectorNormalize(normal, normal); + if (avg) + for (int i=0; i<3; i++) + pBTLeft->vMid.normal[i] = (normal[i] + pBTLeft->vMid.normal[i]) / 2.0f; + else VectorCopy(normal, pBTLeft->vMid.normal); + + VectorNormalize(pBTLeft->vMid.normal, pBTLeft->vMid.normal); + VectorNormalize(pBTRight->vMid.normal, pBTRight->vMid.normal); + + } + BTree_GenerateNormals(pBTMid->left, pBTLeft->left, pBTRight->left, avg, flat, nomid, noleft, noright, /*endcap, n1, n2,*/ flip); + BTree_GenerateNormals(pBTMid->right, pBTLeft->right, pBTRight->right, avg, flat, nomid, noleft, noright, /*endcap, n1, n2,*/ flip); + } +} + + + +void Patch_GenerateLODNormals(patchMesh_t *patch) +{ + int col, row, rowpos, colpos, i; + BTNode_t *tree[2][3]; + int degen[2][3]; + bool rowAvg, colAvg; + + for(col=0; col+2width; col+=2) + { + for(row=0; row+2height; row+=2) + { + if (!patch->colDirty[col/2] && !patch->rowDirty[row/2]) continue; + + rowpos = ((col/2)*patch->height)+row; + colpos = ((row/2)*patch->width)+col; + + if (row==0) rowAvg = false; + else rowAvg = true; + if (col==0) colAvg = false; + else colAvg = true; + + for (i=0; i<3; i++) + { + tree[0][i] = patch->rowLOD[rowpos+i]; + tree[1][i] = patch->colLOD[colpos+i]; + + degen[0][i] = Patch_DegenCurve(patch->ctrl[col][row+i].xyz, patch->ctrl[col+1][row+i].xyz, patch->ctrl[col+2][row+i].xyz); + degen[1][i] = Patch_DegenCurve(patch->ctrl[col+i][row].xyz, patch->ctrl[col+i][row+1].xyz, patch->ctrl[col+i][row+2].xyz); + } + + BTree_GenerateNormals(tree[0][1], tree[0][0], tree[0][2], rowAvg, (degen[1][0] && degen[1][1] && degen[1][2]), degen[0][1] == 2, degen[0][0] == 2, degen[0][2] == 2, /*degen[1][1], patch->ctrl[col][row].normal, patch->ctrl[col][row+2].normal,*/ false); + BTree_GenerateNormals(tree[1][1], tree[1][0], tree[1][2], colAvg, (degen[0][0] && degen[0][1] && degen[0][2]), degen[1][1] == 2, degen[1][0] == 2, degen[1][2] == 2, /*degen[0][1], patch->ctrl[col][row].normal, patch->ctrl[col+2][row].normal,*/ true); + } + } +} + + +void Patch_ClearLODFlags(patchMesh_t *p) +{ + int i; + + for (i=0;i<(p->width-1)/2; i++) + p->colDirty[i] = false; + + for (i=0;i<(p->height-1)/2; i++) + p->rowDirty[i] = false; +} + +// reset the lodDirty flags owned by all patches in the map +// create new LOD trees for all dirty patches, matched with all other patches in the map +void Patch_LODMatchAll() +{ + brush_t *pb, *brushlist; + int i; + + // create LOD tree roots and LOD tree lists for all patches that are dirty + + brushlist = &active_brushes; + for (i=0; i<2; i++) + { + for (pb = brushlist->next; pb && (pb != brushlist); pb=pb->next) + { + // create lod for selected patches when patches are filtered + if (pb->bFiltered && (pb->patchBrush && !pb->pPatch->bSelected)) + continue; + if (!pb->patchBrush) + continue; + if (!pb->pPatch->bDirty) + continue; + + Patch_CalcCVNormals(pb->pPatch); + Patch_CreateLODTrees(pb->pPatch); + } + brushlist = &selected_brushes; + } + + brushlist = &active_brushes; + for (i=0; i<2; i++) + { + for (pb = brushlist->next; pb && (pb != brushlist); pb=pb->next) + { + if (!pb->patchBrush) + continue; + + if (pb->pPatch->LODUpdated) + Patch_GenerateLODNormals(pb->pPatch); + + Patch_ClearLODFlags(pb->pPatch); + } + brushlist = &selected_brushes; + } + +} + +void Vertex_TransformTexture(drawVert_t *pVert, float fx, float fy, transformtype xform) +{ + switch(xform) + { + case TRANSLATE: + pVert->st[0] += fx; + pVert->st[1] += fy; + break; + case SCALE: + pVert->st[0] *= fx; + pVert->st[1] *= fy; + break; + case ROTATE: + float x = pVert->st[0]; + float y = pVert->st[1]; + pVert->st[0] = x * fx - y * fy; + pVert->st[1] = y * fx + x * fy; + } +} + +void BTree_TransformTexture(BTNode_t *pBT, float fx, float fy, transformtype xform) +{ + if (pBT != NULL) + { // PreOrder traversal + Vertex_TransformTexture(&pBT->info, fx, fy, xform); + Vertex_TransformTexture(&pBT->vMid, fx, fy, xform); + BTree_TransformTexture(pBT->left, fx, fy, xform); + BTree_TransformTexture(pBT->right, fx, fy, xform); + } +} + +void Patch_TransformLODTexture(patchMesh_t *p, float fx, float fy, transformtype xform) +{ + int col, row; + + for(col=1; colwidth; col+=2) + for(row=0; rowheight; row++) + BTree_TransformTexture(p->rowLOD[(((col-1)/2)*p->height)+row], fx, fy, xform); + + for(row=1; rowheight; row+=2) + for(col=0; colwidth; col++) + BTree_TransformTexture(p->colLOD[(((row-1)/2)*p->width)+col], fx, fy, xform); +} + +void Patch_AddBTreeToDrawListInOrder(list *drawList, BTNode_t *pBT) +{ + if (pBT != NULL) //traverse InOrder + { + Patch_AddBTreeToDrawListInOrder(drawList, pBT->left); + if (pBT->left != NULL && pBT->right != NULL) + drawList->push_back(pBT->vMid); + Patch_AddBTreeToDrawListInOrder(drawList, pBT->right); + } +} + +void Patch_InterpolateListFromRowBT(list *drawList, BTNode_t *rowBT, BTNode_t *rowBTLeft, drawVert_t *vCurve[], float u, float n, float v) +{ + if (rowBT != NULL) + { + Patch_InterpolateListFromRowBT(drawList, rowBT->left, rowBTLeft->left, vCurve, u-n, n*0.5f, v); + if (rowBT->left != NULL && rowBT->right != NULL) + { + vec3_t v1, v2; + drawVert_t newVert, vTemp1, vTemp2; + Patch_CurveSplit(vCurve, vTemp1, vTemp2, newVert, u); + for (int i=0; i<3; i++) + { + v1[i] = rowBT->vMid.xyz[i] - rowBTLeft->vMid.xyz[i]; // left -> mid + v1[i] = rowBTLeft->vMid.xyz[i] + (v1[i] * v); + v1[i] = newVert.xyz[i] - v1[i]; + } + VectorSubtract(vTemp1.xyz, newVert.xyz, v2); + CrossProduct(v1, v2, newVert.normal); + VectorNormalize(newVert.normal, newVert.normal); + //if (!g_PrefsDlg.m_bGLLighting) + // ShadeVertex(newVert); + drawList->push_back(newVert); + } + Patch_InterpolateListFromRowBT(drawList, rowBT->right, rowBTLeft->right, vCurve, u+n, n*0.5f, v); + } +} + +void Patch_TraverseColBTInOrder(list*>::iterator& iter, BTNode_t *colBTLeft, BTNode_t *colBT, BTNode_t *colBTRight, BTNode_t *rowBT, BTNode_t *rowBTLeft, float v, float n) +{ + if (colBT != NULL) + { + //traverse subtree In Order + Patch_TraverseColBTInOrder(iter, colBTLeft->left, colBT->left, colBTRight->left, rowBT, rowBTLeft, v-n, n*0.5f); + if (colBT->left != NULL && colBT->right != NULL) + { + drawVert_t *vCurve[3]; + vCurve[0] = &colBTLeft->vMid; + vCurve[1] = &colBT->vMid; + vCurve[2] = &colBTRight->vMid; + Patch_InterpolateListFromRowBT((*iter), rowBT, rowBTLeft, vCurve, 0.5f, 0.25f, v); + + (*iter)->push_back(colBTRight->vMid); + iter++; + } + Patch_TraverseColBTInOrder(iter, colBTLeft->right, colBT->right, colBTRight->right, rowBT, rowBTLeft, v+n, n*0.5f); + } +} + + +void Patch_StartDrawLists(list*> *drawLists, BTNode_t *colBT) +{ + if (colBT != NULL) + { + //traverse subtree In Order + Patch_StartDrawLists(drawLists, colBT->left); + if (colBT->left != NULL && colBT->right != NULL) + { + list *newList = new list; + drawLists->push_back(newList); // add empty list to back + drawLists->back()->push_back(colBT->vMid); + } + Patch_StartDrawLists(drawLists, colBT->right); + } +} + +typedef list drawList_t; +typedef list*> drawLists_t; + +void Patch_CreateDrawLists(patchMesh_t *patch) +{ + int col, row, colpos, rowpos; + + drawLists_t *drawLists = new drawLists_t; + + drawLists_t::iterator iter1, iter2; + + for (row=0; rowheight; row+=2) + { + colpos = (row/2)*patch->width; + drawList_t *newList = new drawList_t; + drawLists->push_back(newList); // add a new empty list to back + drawLists->back()->push_back(patch->ctrl[0][row]); // fill list at back + + if (row+1 == patch->height) + continue; + Patch_StartDrawLists(drawLists, patch->colLOD[colpos]); + } + + iter1 = drawLists->begin(); + for (row=0; rowheight; row+=2) + { + iter2 = iter1; + for (col=0; col+1width; col+=2) + { + iter1 = iter2; + colpos = ((row/2)*patch->width)+col; + rowpos = ((col/2)*patch->height)+row; + + Patch_AddBTreeToDrawListInOrder((*iter1), patch->rowLOD[rowpos]); + (*iter1)->push_back(patch->ctrl[col+2][row]); + + if (row+1 == patch->height) + continue; + + iter1++; + + Patch_TraverseColBTInOrder(iter1, patch->colLOD[colpos], patch->colLOD[colpos+1], patch->colLOD[colpos+2], patch->rowLOD[rowpos+1], patch->rowLOD[rowpos], 0.5, 0.25); + } + } + + patch->drawLists = drawLists; +} + + +void Patch_DeleteDrawLists(patchMesh_t *patch) +{ + drawLists_t *drawLists; + drawLists_t::iterator iter; + + if (patch->drawLists == NULL) + return; + + drawLists = (drawLists_t *)patch->drawLists; + + for (iter=drawLists->begin(); iter != drawLists->end(); iter++) + { + delete (*iter); + } + + delete drawLists; + patch->drawLists = NULL; +} + + +void Patch_DrawLODPatchMesh(patchMesh_t *patch) +{ + drawLists_t *drawLists; + + drawLists_t::iterator iterLists, iterListsNext; + drawList_t::iterator iterList, iterListNext; + + //int nGLState = g_pParentWnd->GetCamera()->Camera()->draw_glstate; + + if (patch->drawLists == NULL) + return; + + drawLists = (drawLists_t *)patch->drawLists; + + iterListsNext=drawLists->begin(); + iterListsNext++; + for (iterLists=drawLists->begin(); iterLists != drawLists->end() && iterListsNext != drawLists->end(); iterLists++, iterListsNext++) + { + // traverse two drawlists at once to draw a strip + //if (nGLState & DRAW_GL_LINE) + qglBegin(GL_QUAD_STRIP); + //else + // qglBegin(GL_TRIANGLE_STRIP); + for (iterList=(*iterLists)->begin(), iterListNext=(*iterListsNext)->begin(); iterList != (*iterLists)->end() && iterListNext != (*iterListsNext)->end(); iterList++, iterListNext++) + { + //if (g_PrefsDlg.m_bGLLighting) + qglNormal3fv((*iterList).normal); + //else if (bShade && !g_PrefsDlg.m_bDisplayLists) + // qglColor3f((*iterList).lightmap[0], (*iterList).lightmap[0], (*iterList).lightmap[0]); + + qglTexCoord2fv((*iterList).st); + qglVertex3fv((*iterList).xyz); + + //if (g_PrefsDlg.m_bGLLighting) + qglNormal3fv((*iterListNext).normal); + //else if (bShade && !g_PrefsDlg.m_bDisplayLists) + // qglColor3f((*iterListNext).lightmap[0], (*iterListNext).lightmap[0], (*iterListNext).lightmap[0]); + + qglTexCoord2fv((*iterListNext).st); + qglVertex3fv((*iterListNext).xyz); + } + qglEnd(); + } +/* +#ifdef _DEBUG + vec3_t vNormal; + for (iterLists=drawLists->begin(); iterLists != drawLists->end(); iterLists++) + { + qglBegin (GL_LINES); // draw normals + //qglColor3f(1,1,1); + for (iterList=(*iterLists)->begin(); iterList != (*iterLists)->end(); iterList++) + { + VectorAdd((*iterList).xyz, (*iterList).normal, vNormal); + qglVertex3fv ((*iterList).xyz); + qglVertex3fv (vNormal); + } + qglEnd (); + } + + Patch_DrawNormals(patch); + +#endif + */ +} + +/* +// fast memory-efficient ray-triangle intersection - MollerTrumbore97 + +#define EPSILON 0.000001 +#define CROSS(dest,v1,v2) {dest[0]=v1[1]*v2[2]-v1[2]*v2[1];dest[1]=v1[2]*v2[0]-v1[0]*v2[2];dest[2]=v1[0]*v2[1]-v1[1]*v2[0];} +#define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]) +#define SUB(dest,v1,v2) {dest[0]=v1[0]-v2[0];dest[1]=v1[1]-v2[1];dest[2]=v1[2]-v2[2];} + +int intersect_triangle(float orig[3], float dir[3], + float vert0[3], float vert1[3], float vert2[3], + double *t, double *u, double *v) +{ + double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; + double det,inv_det; + + // find vectors for two edges sharing vert0 + SUB(edge1, vert1, vert0); + SUB(edge2, vert2, vert0); + + // begin calculating determinant - also used to calculate U parameter + CROSS(pvec, dir, edge2); + + // if determinant is near zero, ray lies in plane of triangle + det = DOT(edge1, pvec); + +#ifdef TEST_CULL // define TEST_CULL if culling is desired + if (det < EPSILON) + return 0; + + // calculate distance from vert0 to ray origin + SUB(tvec, orig, vert0); + + // calculate U parameter and test bounds + *u = DOT(tvec, pvec); + if (*u < 0.0 || *u > det) + return 0; + + // prepare to test V parameter + CROSS(qvec, tvec, edge1); + + // calculate V parameter and test bounds + *v = DOT(dir, qvec); + if (*v < 0.0 || *u + *v > det) + return 0; + + // calculate t, scale parameters, ray intersects triangle + *t = DOT(edge2, qvec); + inv_det = 1.0 / det; + *t *= inv_det; + *u *= inv_det; + *v *= inv_det; +#else // the non-culling branch + if (det > -EPSILON && det < EPSILON) + return 0; + inv_det = 1.0 / det; + + // calculate distance from vert0 to ray origin + SUB(tvec, orig, vert0); + + // calculate U parameter and test bounds + *u = DOT(tvec, pvec) * inv_det; + if (*u < 0.0 || *u > 1.0) + return 0; + + // prepare to test V parameter + CROSS(qvec, tvec, edge1); + + // calculate V parameter and test bounds + *v = DOT(dir, qvec) * inv_det; + if (*v < 0.0 || *u + *v > 1.0) + return 0; + + // calculate t, ray intersects triangle + *t = DOT(edge2, qvec) * inv_det; +#endif + return 1; +} +*/ + +int Triangle_Ray(float orig[3], float dir[3], bool bCullBack, + float vert0[3], float vert1[3], float vert2[3], + double *t, double *u, double *v) +{ + float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; + double det,inv_det; + + /* find vectors for two edges sharing vert0 */ + VectorSubtract(vert1, vert0, edge1); + VectorSubtract(vert2, vert0, edge2); + + /* begin calculating determinant - also used to calculate U parameter */ + CrossProduct(dir, edge2, pvec); + + /* if determinant is near zero, ray lies in plane of triangle */ + det = DotProduct(edge1, pvec); + + if (bCullBack) + { + if (det < 0.000001) + return 0; + + // calculate distance from vert0 to ray origin + VectorSubtract(orig, vert0, tvec); + + // calculate U parameter and test bounds + *u = DotProduct(tvec, pvec); + if (*u < 0.0 || *u > det) + return 0; + + // prepare to test V parameter + CrossProduct(tvec, edge1, qvec); + + // calculate V parameter and test bounds + *v = DotProduct(dir, qvec); + if (*v < 0.0 || *u + *v > det) + return 0; + + // calculate t, scale parameters, ray intersects triangle + *t = DotProduct(edge2, qvec); + inv_det = 1.0 / det; + *t *= inv_det; + *u *= inv_det; + *v *= inv_det; + } + else + { + /* the non-culling branch */ + if (det > -0.000001 && det < 0.000001) + return 0; + inv_det = 1.0 / det; + + /* calculate distance from vert0 to ray origin */ + VectorSubtract(orig, vert0, tvec); + + /* calculate U parameter and test bounds */ + *u = DotProduct(tvec, pvec) * inv_det; + if (*u < 0.0 || *u > 1.0) + return 0; + + /* prepare to test V parameter */ + CrossProduct(tvec, edge1, qvec); + + /* calculate V parameter and test bounds */ + *v = DotProduct(dir, qvec) * inv_det; + if (*v < 0.0 || *u + *v > 1.0) + return 0; + + /* calculate t, ray intersects triangle */ + *t = DotProduct(edge2, qvec) * inv_det; + } + return 1; +} + +bool Patch_Ray(patchMesh_t *patch, vec3_t origin, vec3_t dir, double *t, double *u, double *v) +{ + drawLists_t *drawLists; + + drawLists_t::iterator iterLists, iterListsNext; + drawList_t::iterator i1, i2, i3, i4; + +// vec3_t tris[2][3]; + bool bIntersect = false; + float tBest = FLT_MAX; + + if (patch->drawLists == NULL) + return false; + + drawLists = (drawLists_t *)patch->drawLists; + + iterListsNext=drawLists->begin(); + iterListsNext++; + for (iterLists=drawLists->begin(); iterLists != drawLists->end() && iterListsNext != drawLists->end(); iterLists++, iterListsNext++) + { + // traverse two drawlists at once with two iterators each to triangulate + i1 = i3 = (*iterLists)->begin(); + i2 = i4 = (*iterListsNext)->begin(); + i3++; + i4++; + while (i3 != (*iterLists)->end() && i4 != (*iterListsNext)->end()) + { + if (Triangle_Ray(origin, dir, false, (*i1).xyz, (*i2).xyz, (*i3).xyz, t, u, v)) + { + bIntersect = true; + if (*t < tBest) + tBest = *t; + } + if (Triangle_Ray(origin, dir, false, (*i3).xyz, (*i4).xyz, (*i2).xyz, t, u, v)) + { + bIntersect = true; + if (*t < tBest) + tBest = *t; + } + i1++; + i2++; + i3++; + i4++; + } + } + if (bIntersect) + { + *t = tBest; + return true; + } + else + { + *t = 0; + return false; + } +} + +// spog - curve LOD stuff ends + +/* +================= +DrawPatchMesh +================= +*/ +void DrawPatchMesh(patchMesh_t *pm) +{ + if (g_PrefsDlg.m_bDisplayLists) + { + if (pm->bDirty || pm->nListID <= 0 || pm->LODUpdated) + { + if (pm->nListID <= 0) + pm->nListID = qglGenLists(1); + if (pm->nListID > 0) + { + qglNewList(pm->nListID, GL_COMPILE_AND_EXECUTE); + } + + Patch_DeleteDrawLists(pm); + Patch_CreateDrawLists(pm); + + Patch_DrawLODPatchMesh(pm); + + if (pm->nListID > 0) + { + qglEndList(); + } + + pm->bDirty = false; + pm->LODUpdated = false; + } + else + { + qglCallList(pm->nListID); + } + } + else + { + if (pm->bDirty || pm->LODUpdated) + { + Patch_DeleteDrawLists(pm); + Patch_CreateDrawLists(pm); + pm->bDirty = false; + pm->LODUpdated = false; + } + Patch_DrawLODPatchMesh(pm); + } +} + +/* +================= +DrawPatchControls +================= +*/ +void DrawPatchControls(patchMesh_t *pm) +{ + int i, j; + bool bSelectedPoints[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT]; + + bool bOverlay = pm->bOverlay; + + // bending + if (g_bPatchBendMode) + { + qglPointSize(6); + if (g_bPatchAxisOnRow) + { + qglColor3f(1, 0, 1); + if(!g_PrefsDlg.m_bGlPtWorkaround) + { + qglBegin(GL_POINTS); + for (i = 0; i < pm->width; i++) + { + qglVertex3fv(pm->ctrl[i][g_nPatchAxisIndex].xyz); + } + qglEnd(); + } + else + { + qglLineWidth(2.0); + qglBegin(GL_LINES); + for(i = 0; i < pm->width; i++) + { + DrawAlternatePoint(pm->ctrl[i][g_nPatchAxisIndex].xyz, 0); + } + qglEnd(); + qglLineWidth(1.0); + } + + if (g_nPatchBendState == BEND_SELECT_EDGE || g_nPatchBendState == BEND_BENDIT || g_nPatchBendState == BEND_SELECT_ORIGIN) + { + if(!g_PrefsDlg.m_bGlPtWorkaround) + { + qglColor3f(0, 0, 1); + qglBegin(GL_POINTS); + if (g_nPatchBendState == BEND_SELECT_ORIGIN) + { + qglVertex3fv(g_vBendOrigin); + } + else + { + for (i = 0; i < pm->width; i++) + { + if (g_bPatchLowerEdge) + { + for (j = 0; j < g_nPatchAxisIndex; j++) + qglVertex3fv(pm->ctrl[i][j].xyz); + } + else + { + for (j = pm->height-1; j > g_nPatchAxisIndex; j--) + qglVertex3fv(pm->ctrl[i][j].xyz); + } + } + } + qglEnd(); + } + else { + qglColor3f(0, 0, 1); + qglLineWidth(2.0); + qglBegin(GL_LINES); + if(g_nPatchBendState == BEND_SELECT_ORIGIN) + { + DrawAlternatePoint(g_vBendOrigin, 0); + } + else + { + for(i = 0; i < pm->width; i++) + { + if(g_bPatchLowerEdge) + { + for(j = 0; j < g_nPatchAxisIndex; j++) + { + DrawAlternatePoint(pm->ctrl[i][j].xyz, 0); + } + } + else + { + for (j = pm->height-1; j > g_nPatchAxisIndex; j--) + { + DrawAlternatePoint(pm->ctrl[i][j].xyz, 0); + } + } + } + } + qglEnd(); + qglLineWidth(1.0); + } + } + } + else + { + if(!g_PrefsDlg.m_bGlPtWorkaround) + { + qglColor3f(1, 0, 1); + qglBegin(GL_POINTS); + for (i = 0; i < pm->height; i++) + { + qglVertex3fv(pm->ctrl[g_nPatchAxisIndex][i].xyz); + } + qglEnd(); + } + else { + qglColor3f(1, 0, 1); + qglLineWidth(2.0); + qglBegin(GL_LINES); + for(i = 0; i < pm->height; i++) + { + DrawAlternatePoint(pm->ctrl[g_nPatchAxisIndex][i].xyz, 0); + } + qglEnd(); + qglLineWidth(1.0); + } + + if (g_nPatchBendState == BEND_SELECT_EDGE || g_nPatchBendState == BEND_BENDIT || g_nPatchBendState == BEND_SELECT_ORIGIN) + { + if(!g_PrefsDlg.m_bGlPtWorkaround) + { + qglColor3f(0, 0, 1); + qglBegin(GL_POINTS); + for (i = 0; i < pm->height; i++) + { + if (g_nPatchBendState == BEND_SELECT_ORIGIN) + { + qglVertex3fv(pm->ctrl[g_nBendOriginIndex][i].xyz); + } + else + { + if (g_bPatchLowerEdge) + { + for (j = 0; j < g_nPatchAxisIndex; j++) + qglVertex3fv(pm->ctrl[j][i].xyz); + } + else + { + for (j = pm->width-1; j > g_nPatchAxisIndex; j--) + qglVertex3fv(pm->ctrl[j][i].xyz); + } + } + } + qglEnd(); + } + else { + qglColor3f(0, 0, 1); + qglLineWidth(2.0); + qglBegin(GL_LINES); + for(i = 0; i < pm->height; i++) + { + if(g_nPatchBendState == BEND_SELECT_ORIGIN) + { + DrawAlternatePoint(pm->ctrl[g_nBendOriginIndex][i].xyz, 0); + } + else + { + if(g_bPatchLowerEdge) + { + for(j = 0; j < g_nPatchAxisIndex; j++) + { + DrawAlternatePoint(pm->ctrl[j][i].xyz, 0); + } + } + else + { + for(j = pm->width-1; j > g_nPatchAxisIndex; j--) + { + DrawAlternatePoint(pm->ctrl[j][i].xyz, 0); + } + } + } + } + qglEnd(); + qglLineWidth(1.0); + } + } + } + } + else + { + //qglDisable(GL_TEXTURE_2D); // stops point colours being multiplied by texture colour.. + //draw CV lattice - could be made optional + //qglDisable( GL_CULL_FACE ); + // qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + qglEnable (GL_POLYGON_OFFSET_LINE); + if (g_PrefsDlg.m_bNoStipple == FALSE) + qglDisable (GL_LINE_STIPPLE); + qglLineWidth (1); + qglColor3f(1.0f, 0.75f, 0.0f); + for ( i = 0 ; i+1 < pm->width ; i++ ) + { + qglBegin(GL_QUAD_STRIP); + for ( j = 0 ; j < pm->height ; j++ ) + { + qglVertex3fv(pm->ctrl[i][j].xyz); + qglVertex3fv(pm->ctrl[i+1][j].xyz); + } + qglEnd(); + } + qglDisable (GL_POLYGON_OFFSET_LINE); + //if (g_PrefsDlg.m_bNoStipple == FALSE) + // qglEnable (GL_LINE_STIPPLE); + + // draw selection handles + if(!g_PrefsDlg.m_bGlPtWorkaround) + { + qglPointSize(6); + qglBegin(GL_POINTS); + for ( i = 0 ; i < pm->width ; i++ ) + { + for ( j = 0 ; j < pm->height ; j++ ) + { + if (PointInMoveList(pm->ctrl[i][j].xyz) != -1) + { + bSelectedPoints[i][j] = true; + } + else + { + bSelectedPoints[i][j] = false; + if (i & 0x01 || j & 0x01) + qglColor3f(1, 0, 1); + else + qglColor3f(0, 1, 0); + + qglVertex3fv(pm->ctrl[i][j].xyz); + } + } + } + qglColor3f(0, 0, 1); + for ( i = 0 ; i < pm->width ; i++ ) + { + for ( j = 0 ; j < pm->height ; j++ ) + { + if (bSelectedPoints[i][j]) + qglVertex3fv(pm->ctrl[i][j].xyz); + } + } + qglEnd(); + } + else + { + qglLineWidth(2.0); + qglBegin(GL_LINES); + for(i = 0; i < pm->width; i++) + { + for(j = 0; j < pm->height; j++) + { + if(PointInMoveList(pm->ctrl[i][j].xyz) != -1) + { + bSelectedPoints[i][j] = true; + } + else + { + bSelectedPoints[i][j] = false; + if(i & 0x01 || j & 0x01) + qglColor3f(1, 0, 1); + else + qglColor3f(0, 1, 0); + + // draw verts + DrawAlternatePoint(pm->ctrl[i][j].xyz, 0); + } + } + } + qglColor3f(0, 0, 1); + for(i = 0; i < pm->width; i++) + { + for(j = 0; j < pm->height; j++) + { + if(bSelectedPoints[i][j]) + { + // draw verts + DrawAlternatePoint(pm->ctrl[i][j].xyz, 0); + } + } + } + qglEnd(); + qglLineWidth(1.0); + } + } + if (bOverlay) + { + if(!g_PrefsDlg.m_bGlPtWorkaround) + { + qglPointSize(6); + qglBegin(GL_POINTS); + for ( i = 0 ; i < pm->width ; i++ ) + { + for ( j = 0 ; j < pm->height ; j++ ) + { + if (i & 0x01 || j & 0x01) + qglColor3f(1, 0, 1); + else + qglColor3f(0, 1, 0); + qglVertex3fv(pm->ctrl[i][j].xyz); + } + } + qglEnd(); + } + else + { + qglLineWidth(2.0); + qglBegin(GL_LINES); + for ( i = 0 ; i < pm->width ; i++ ) + { + for ( j = 0 ; j < pm->height ; j++ ) + { + if (i & 0x01 || j & 0x01) + qglColor3f(1, 0, 1); + else + qglColor3f(0, 1, 0); + // draw verts + DrawAlternatePoint(pm->ctrl[i][j].xyz, 0); + } + } + qglEnd(); + qglLineWidth(1.0); + } + } + //qglPopAttrib(); +} + +/* +================== +Patch_DrawXY +================== +*/ +void Patch_DrawXY(patchMesh_t *pm) +{ + qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + + if (pm->bSelected) + { + qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES]); + if (g_PrefsDlg.m_bNoStipple == FALSE) + qglEnable (GL_LINE_STIPPLE); + qglLineWidth (2); + } + + DrawPatchMesh(pm); + + if ( (pm->bSelected && (g_qeglobals.d_select_mode == sel_curvepoint + || g_qeglobals.d_select_mode == sel_area + || g_bPatchBendMode)) + || pm->bOverlay ) + DrawPatchControls(pm); +} + +/* +================== +Patch_DrawCam +================== +*/ +void Patch_DrawCam(patchMesh_t *pm) +{ + qglPushAttrib(GL_ALL_ATTRIB_BITS); // save the current state + + if (g_bPatchWireFrame) + { + qglDisable( GL_CULL_FACE ); + qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + qglDisable(GL_TEXTURE_2D); + if (g_PrefsDlg.m_bGLLighting) + qglDisable(GL_LIGHTING); + + DrawPatchMesh(pm); + + //if (g_PrefsDlg.m_bGLLighting) + // qglEnable(GL_LIGHTING); + //qglEnable( GL_CULL_FACE ); + } + else + { + qglDisable(GL_CULL_FACE); + qglBindTexture (GL_TEXTURE_2D, pm->d_texture->texture_number); + qglPolygonMode (GL_FRONT, GL_FILL); + qglPolygonMode (GL_BACK, GL_LINE); + + if (pm->pShader->getTrans() < 1.0f) + { + qglEnable(GL_BLEND); + qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + qglColor4f(pm->d_texture->color[0], pm->d_texture->color[1], pm->d_texture->color[2], pm->pShader->getTrans()); + } + + DrawPatchMesh(pm); // both sides + } + + qglPopAttrib(); // restore saved state +} + +void ConvexHullForSection( float section[2][4][7] ) { +} + +void BrushesForSection( float section[2][4][7] ) { +} + +/* +================ +Patch_BuildPoints +================ +*/ +void Patch_BuildPoints (brush_t *b) +{ + face_t *f; + b->patchBrush = false; + for (f=b->brush_faces ; f ; f=f->next) + { + if (f->texdef.flags & SURF_PATCH) + { + b->patchBrush = true; + //vec3_t vMin, vMax; + //Patch_CalcBounds(&patchMeshes[b->nPatchID], vMin, vMax); + //VectorCopy(vMin, b->mins); + //VectorCopy(vMax, b->maxs); + break; + } + } +} + +/* +================== +Patch_Move +================== +*/ +void Patch_Move(patchMesh_t *pm, const vec3_t vMove, bool bRebuild) +{ + pm->bDirty = true; + for (int w = 0; w < pm->width; w++) + { + for (int h = 0; h < pm->height; h++) + { + VectorAdd(pm->ctrl[w][h].xyz, vMove, pm->ctrl[w][h].xyz); + } + } + // bRebuild is never true + if (bRebuild) + { + vec3_t vMin, vMax; + Patch_CalcBounds(pm, vMin, vMax); + //Brush_RebuildBrush(patchMeshes[n].pSymbiot, vMin, vMax); + } + UpdatePatchInspector(); + +} + +/* +================== +Patch_ApplyMatrix +================== +*/ +void Patch_ApplyMatrix(patchMesh_t *p, const vec3_t vOrigin, const vec3_t vMatrix[3], bool bSnap) +{ + vec3_t vTemp; + + for (int w = 0; w < p->width; w++) + { + for (int h = 0; h < p->height; h++) + { + if (((g_qeglobals.d_select_mode == sel_curvepoint && g_qeglobals.d_num_move_points != 0) || g_bPatchBendMode) + && PointInMoveList(p->ctrl[w][h].xyz) == -1) // snap selected points only, if selected + continue; + VectorSubtract (p->ctrl[w][h].xyz, vOrigin, vTemp); + for (int j = 0; j < 3; j++) + { + p->ctrl[w][h].xyz[j] = DotProduct(vTemp, vMatrix[j]) + vOrigin[j]; + if (bSnap) + { + p->ctrl[w][h].xyz[j] = floor(p->ctrl[w][h].xyz[j] + 0.5); + } + } + } + } + vec3_t vMin, vMax; + Patch_CalcBounds(p, vMin, vMax); + Brush_RebuildBrush(p->pSymbiot, vMin, vMax); +} + +/* +================== +Patch_EditPatch +================== +*/ +void Patch_EditPatch() +{ + //--patchMesh_t* p = &patchMeshes[n]; + g_qeglobals.d_numpoints = 0; + g_qeglobals.d_num_move_points = 0; + + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t* p = pb->pPatch; + for ( int i = 0 ; i < p->width ; i++ ) + { + for ( int j = 0 ; j < p->height ; j++ ) + { + VectorCopy (p->ctrl[i][j].xyz, g_qeglobals.d_points[g_qeglobals.d_numpoints]); + if (g_qeglobals.d_numpoints < MAX_POINTS-1) + { + g_qeglobals.d_numpoints++; + } + } + } + } + } + g_qeglobals.d_select_mode = sel_curvepoint; + //--g_nSelectedPatch = n; +} + + + +/* +================== +Patch_Deselect +================== +*/ +//FIXME: need all sorts of asserts throughout a lot of this crap +void Patch_Deselect() +{ + //--g_nSelectedPatch = -1; + g_qeglobals.d_select_mode = sel_brush; + + for (brush_t *b = selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + if (b->patchBrush) + { + b->pPatch->bSelected = false; + } + } + + //for (int i = 0; i < numPatchMeshes; i++) + // patchMeshes[i].bSelected = false; + + if (g_bPatchBendMode) + Patch_BendToggle(); +// if (g_bPatchInsertMode) +// Patch_InsDelToggle(); +} + + +/* +================== +Patch_Select +================== +*/ +void Patch_Select(patchMesh_t *p) +{ + // maintained for point manip.. which i need to fix as this + // is pf error prone + //--g_nSelectedPatch = n; + p->bSelected = true; +} + + +/* +================== +Patch_Deselect +================== +*/ +void Patch_Deselect(patchMesh_t *p) +{ + p->bSelected = false; +} + + +/* +================== +Patch_Delete +================== +*/ +extern BTNode_t *BTree_Delete(BTNode_t *pBT); +extern BTListList_t *BTree_DeleteListFromList(BTListList_t *pBTListList); + +void Patch_Delete(patchMesh_t *p) +{ + if (p->pSymbiot) // Hydra - added a check to prevent access violations. + { + p->pSymbiot->pPatch = NULL; + p->pSymbiot->patchBrush = false; + } + + // spog - free dynamically allocated memory used by LODs + int rowcount = ((MAX_PATCH_WIDTH-1)/2) * MAX_PATCH_HEIGHT; + int colcount = ((MAX_PATCH_HEIGHT-1)/2) * MAX_PATCH_WIDTH; + int i; + for (i=0; irowLOD[i] = BTree_Delete(p->rowLOD[i]); + for (i=0; icolLOD[i] = BTree_Delete(p->colLOD[i]); + + // delete display list associated with patch + if (p->nListID != -1) + qglDeleteLists (p->nListID, 1); // list#, number of lists + + // delete LOD drawLists + Patch_DeleteDrawLists(p); + + + free(p); + p = NULL; + + + UpdatePatchInspector(); +} + + +/* +================== +Patch_Scale +================== +*/ +void Patch_Scale(patchMesh_t *p, const vec3_t vOrigin, const vec3_t vAmt, bool bRebuild) +{ + + for (int w = 0; w < p->width; w++) + { + for (int h = 0; h < p->height; h++) + { + if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1) + continue; + for (int i=0 ; i<3 ; i++) + { + p->ctrl[w][h].xyz[i] -= vOrigin[i]; + p->ctrl[w][h].xyz[i] *= vAmt[i]; + p->ctrl[w][h].xyz[i] += vOrigin[i]; + } + } + } + if (bRebuild) + { + vec3_t vMin, vMax; + Patch_CalcBounds(p, vMin, vMax); + Brush_RebuildBrush(p->pSymbiot, vMin, vMax); + } + UpdatePatchInspector(); +} + + +/* +================== +Patch_SetView +================== +*/ +void Patch_SetView(int n) +{ + g_bSameView = (n == g_nPatchClickedView); + g_nPatchClickedView = n; +} + + +/* +================== +Patch_SetTexture +================== +*/ +// FIXME: need array validation throughout +void Patch_SetTexture(patchMesh_t *p, texdef_t *tex_def, IPluginTexdef* pPlugTexdef) +{ + // NOTE: I don't know for sure if this happens + if (p->pShader) + p->pShader->DecRef(); + p->pShader = QERApp_Shader_ForName(tex_def->GetName()); + p->pShader->IncRef(); + p->d_texture = p->pShader->getTexture(); + + UpdatePatchInspector(); +} + + +/* +================== +Patch_DragScale +================== +*/ +bool Patch_DragScale(patchMesh_t *p, vec3_t vAmt, vec3_t vMove) +{ + vec3_t vMin, vMax, vScale, vTemp, vMid; + int i; + + Patch_CalcBounds(p, vMin, vMax); + + VectorSubtract(vMax, vMin, vTemp); + + // if we are scaling in the same dimension the patch has no depth + for (i = 0; i < 3; i ++) + { + if (vTemp[i] == 0 && vMove[i] != 0) + { + //Patch_Move(n, vMove, true); + return false; + } + } + + for (i=0 ; i<3 ; i++) + vMid[i] = (vMin[i] + ((vMax[i] - vMin[i]) / 2)); + + for (i = 0; i < 3; i++) + { + if (vAmt[i] != 0) + { + vScale[i] = 1.0 + vAmt[i] / vTemp[i]; + } + else + { + vScale[i] = 1.0; + } + } + + Patch_Scale(p, vMid, vScale, false); + + VectorSubtract(vMax, vMin, vTemp); + + Patch_CalcBounds(p, vMin, vMax); + + VectorSubtract(vMax, vMin, vMid); + + VectorSubtract(vMid, vTemp, vTemp); + + VectorScale(vTemp, 0.5, vTemp); + + // abs of both should always be equal + if (!VectorCompare(vMove, vAmt)) + { + for (i = 0; i < 3; i++) + { + if (vMove[i] != vAmt[i]) + vTemp[i] = -(vTemp[i]); + } + } + + Patch_Move(p, vTemp); + return true; +} + +/* +================== +Patch_InsertColumn +================== +*/ +void Patch_InsertColumn(patchMesh_t *p, bool bAdd) +{ + int w, h, i, width; + vec3_t vTemp; + float stTemp[2]; + + if (p->width + 2 >= MAX_PATCH_WIDTH) + return; + + // check for selected column points + for (h = 0; h < p->height; h++) + { + for (w = 1; w < p->width; w+=2) + if (PointInMoveList(p->ctrl[w][h].xyz) != -1) + break; + if (w < p->width) + break; + for (w = 0; w < p->width; w+=2) + if (PointInMoveList(p->ctrl[w][h].xyz) != -1) + break; + if (w < p->width) + break; + } + + if (w >= p->width) + { + if (bAdd) w=p->width-1; + else w=2; + } + else if (w==0) w=2; + else if (w%2) w++; + + // add columns at w + for (h = 0; h < p->height; h++) + { + for (width = p->width-1; width > w; width--) + memcpy(&p->ctrl[width+2][h],&p->ctrl[width][h], sizeof(drawVert_t)); + + // set two new column points + memcpy(&p->ctrl[w+2][h],&p->ctrl[w][h], sizeof(drawVert_t)); + memcpy(&p->ctrl[w+1][h],&p->ctrl[w-1][h], sizeof(drawVert_t)); + + for (i=0; i<3; i++) // xyz + { + vTemp[i] = p->ctrl[w][h].xyz[i] - p->ctrl[w-1][h].xyz[i]; + p->ctrl[w+1][h].xyz[i] = p->ctrl[w+1][h].xyz[i] + (vTemp[i] / 2); + + vTemp[i] = p->ctrl[w-2][h].xyz[i] - p->ctrl[w-1][h].xyz[i]; + p->ctrl[w-1][h].xyz[i] = p->ctrl[w-1][h].xyz[i] + (vTemp[i] / 2); + + vTemp[i] = p->ctrl[w+1][h].xyz[i] - p->ctrl[w-1][h].xyz[i]; + p->ctrl[w][h].xyz[i] = p->ctrl[w-1][h].xyz[i] + (vTemp[i] / 2); + } + for (i=0; i<2; i++) // st + { + stTemp[i] = p->ctrl[w][h].st[i] - p->ctrl[w-1][h].st[i]; + p->ctrl[w+1][h].st[i] = p->ctrl[w+1][h].st[i] + (stTemp[i] / 2); + + stTemp[i] = p->ctrl[w-2][h].st[i] - p->ctrl[w-1][h].st[i]; + p->ctrl[w-1][h].st[i] = p->ctrl[w-1][h].st[i] + (stTemp[i] / 2); + + stTemp[i] = p->ctrl[w+1][h].st[i] - p->ctrl[w-1][h].st[i]; + p->ctrl[w][h].st[i] = p->ctrl[w-1][h].st[i] + (stTemp[i] / 2); + } + } + + p->width += 2; + // deselect all points to keep things neat + if (g_qeglobals.d_select_mode == sel_curvepoint) + Patch_EditPatch(); + + UpdatePatchInspector(); +} + +/* +================== +Patch_InsertRow +================== +*/ + +void Patch_InsertRow(patchMesh_t *p, bool bAdd) +{ + int h, w, i, height; + vec3_t vTemp; + float stTemp[2]; + + if (p->height + 2 >= MAX_PATCH_HEIGHT) + return; + + // check for selected row points + for (w = 0; w < p->width; w++) + { + for (h = 1; h < p->height; h+=2) + if (PointInMoveList(p->ctrl[w][h].xyz) != -1) + break; + if (h < p->height) + break; + for (h = 0; h < p->height; h+=2) + if (PointInMoveList(p->ctrl[w][h].xyz) != -1) + break; + if (h < p->height) + break; + } + if (h >= p->height) + { + if (bAdd) h=p->height-1; + else h=2; + } + else if (h==0) h=2; + else if (h%2) h++; + + // add rows at h + for (w = 0; w < p->width; w++) + { + for (height = p->height-1; height > h; height--) + memcpy(&p->ctrl[w][height+2],&p->ctrl[w][height], sizeof(drawVert_t)); + + // set two new row points + memcpy(&p->ctrl[w][h+2],&p->ctrl[w][h], sizeof(drawVert_t)); + memcpy(&p->ctrl[w][h+1],&p->ctrl[w][h-1], sizeof(drawVert_t)); + + for (i=0; i<3; i++) // xyz + { + vTemp[i] = p->ctrl[w][h].xyz[i] - p->ctrl[w][h-1].xyz[i]; + p->ctrl[w][h+1].xyz[i] = p->ctrl[w][h+1].xyz[i] + (vTemp[i] / 2); + + vTemp[i] = p->ctrl[w][h-2].xyz[i] - p->ctrl[w][h-1].xyz[i]; + p->ctrl[w][h-1].xyz[i] = p->ctrl[w][h-1].xyz[i] + (vTemp[i] / 2); + + vTemp[i] = p->ctrl[w][h+1].xyz[i] - p->ctrl[w][h-1].xyz[i]; + p->ctrl[w][h].xyz[i] = p->ctrl[w][h-1].xyz[i] + (vTemp[i] / 2); + } + for (i=0; i<2; i++) // st + { + stTemp[i] = p->ctrl[w][h].st[i] - p->ctrl[w][h-1].st[i]; + p->ctrl[w][h+1].st[i] = p->ctrl[w][h+1].st[i] + (stTemp[i] / 2); + + stTemp[i] = p->ctrl[w][h-2].st[i] - p->ctrl[w][h-1].st[i]; + p->ctrl[w][h-1].st[i] = p->ctrl[w][h-1].st[i] + (stTemp[i] / 2); + + stTemp[i] = p->ctrl[w][h+1].st[i] - p->ctrl[w][h-1].st[i]; + p->ctrl[w][h].st[i] = p->ctrl[w][h-1].st[i] + (stTemp[i] / 2); + } + } + + p->height += 2; + // deselect all points to keep things neat + if (g_qeglobals.d_select_mode == sel_curvepoint) + Patch_EditPatch(); + + UpdatePatchInspector(); +} + +/* +================== +Patch_RemoveRow +================== +*/ +void Patch_RemoveRow(patchMesh_t *p, bool bFirst) +{ + int w, h, i, height; + vec3_t vTemp; + float stTemp[2]; + bool bExtrapolate = true; + + if (p->height <= MIN_PATCH_HEIGHT) + return; + + for (w = 0; w < p->width; w++) + { + for (h = 0; h < p->height; h+=2) + if (PointInMoveList(p->ctrl[w][h].xyz) != -1) + break; + if (h < p->height) + break; + for (h = 1; h < p->height; h+=2) + if (PointInMoveList(p->ctrl[w][h].xyz) != -1) + break; + if (h < p->height) + break; + } + + if (h >= p->height) + { + bExtrapolate = false; + if (bFirst) h=p->height-3; + else h=2; + } + else if (h <= 0) h=2; + else if (h > p->height-3) h = p->height-3; + else if (h%2) h++; + + p->height -= 2; + + for (w = 0; w < p->width; w++) + { + if (bExtrapolate) + { + for (i = 0; i < 3; i++) // xyz + { + vTemp[i] = p->ctrl[w][h+2].xyz[i] - p->ctrl[w][h-2].xyz[i]; + p->ctrl[w][h-1].xyz[i] = p->ctrl[w][h-2].xyz[i] + (vTemp[i] / 2); + + vTemp[i] = p->ctrl[w][h].xyz[i] - p->ctrl[w][h-1].xyz[i]; + p->ctrl[w][h-1].xyz[i] = p->ctrl[w][h-1].xyz[i] + (vTemp[i] * 2); + } + + for (i = 0; i < 2; i++) // st + { + stTemp[i] = p->ctrl[w][h+2].st[i] - p->ctrl[w][h-2].st[i]; + p->ctrl[w][h-1].st[i] = p->ctrl[w][h-2].st[i] + (stTemp[i] / 2); + + stTemp[i] = p->ctrl[w][h].st[i] - p->ctrl[w][h-1].st[i]; + p->ctrl[w][h-1].st[i] = p->ctrl[w][h-1].st[i] + (stTemp[i] * 2); + } + } + else + { + if (!bFirst) + continue; + else h=0; + } + for (height = h; height < p->height; height++) + memcpy(&p->ctrl[w][height], &p->ctrl[w][height+2], sizeof(drawVert_t)); + } + // deselect all points to keep things neat + if (g_qeglobals.d_select_mode == sel_curvepoint) + Patch_EditPatch(); + + UpdatePatchInspector(); +} + +/* +================== +Patch_RemoveColumn +================== +*/ +void Patch_RemoveColumn(patchMesh_t *p, bool bFirst) +{ + int w, h, i, width; + vec3_t vTemp; + float stTemp[2]; + bool bExtrapolate = true; + + if (p->width <= MIN_PATCH_WIDTH) + return; + + for (h = 0; h < p->height; h++) + { + for (w = 0; w < p->width; w+=2) + if (PointInMoveList(p->ctrl[w][h].xyz) != -1) + break; + if (w < p->width) + break; + for (w = 1; w < p->width; w+=2) + if (PointInMoveList(p->ctrl[w][h].xyz) != -1) + break; + if (w < p->width) + break; + } + + if (w >= p->width) + { + bExtrapolate = false; + if (bFirst) w=p->width-3; + else w=2; + } + else if (w<=0) w=2; + else if (w > p->width-3) w = p->width-3; + else if (w%2) w++; + + p->width -= 2; + + for (h = 0; h < p->height; h++) + { + if (bExtrapolate) + { + for (i = 0; i < 3; i++) // xyz + { + vTemp[i] = p->ctrl[w+2][h].xyz[i] - p->ctrl[w-2][h].xyz[i]; + p->ctrl[w-1][h].xyz[i] = p->ctrl[w-2][h].xyz[i] + (vTemp[i] / 2); + + vTemp[i] = p->ctrl[w][h].xyz[i] - p->ctrl[w-1][h].xyz[i]; + p->ctrl[w-1][h].xyz[i] = p->ctrl[w-1][h].xyz[i] + (vTemp[i] * 2); + } + + for (i = 0; i < 2; i++) // st + { + stTemp[i] = p->ctrl[w+2][h].st[i] - p->ctrl[w-2][h].st[i]; + p->ctrl[w-1][h].st[i] = p->ctrl[w-2][h].st[i] + (stTemp[i] / 2); + + stTemp[i] = p->ctrl[w][h].st[i] - p->ctrl[w-1][h].st[i]; + p->ctrl[w-1][h].st[i] = p->ctrl[w-1][h].st[i] + (stTemp[i] * 2); + } + } + else + { + if (!bFirst) + continue; + else w=0; + } + + for (width = w; width < p->width; width++) + memcpy(&p->ctrl[width][h], &p->ctrl[width+2][h], sizeof(drawVert_t)); + } + // deselect all points to keep things neat + if (g_qeglobals.d_select_mode == sel_curvepoint) + Patch_EditPatch(); + + UpdatePatchInspector(); +} + +/* +================== +Patch_AdjustColumns +================== +*/ +/* +void Patch_AdjustColumns(patchMesh_t *p, int nCols) +{ + vec3_t vTemp, vTemp2; + int i, w, h; + + if (nCols & 0x01 || p->width + nCols < 3 || p->width + nCols > MAX_PATCH_WIDTH) + return; + + // add in column adjustment + p->width += nCols; + + for (h = 0; h < p->height; h++) + { + // for each column, we need to evenly disperse p->width number + // of points across the old bounds + + // calc total distance to interpolate + VectorSubtract(p->ctrl[p->width - 1 - nCols][h].xyz, p->ctrl[0][h].xyz, vTemp); + + // amount per cycle + for (i = 0; i < 3; i ++) + { + vTemp2[i] = vTemp[i] / (p->width - 1); + } + + // move along + for (w = 0; w < p->width-1; w++) + { + VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w+1][h].xyz); + } + + } + for ( w = 0 ; w < p->width ; w++ ) + { + for ( h = 0 ; h < p->height ; h++ ) + { + p->ctrl[w][h].st[0] = 4 * (float)w / (p->width - 1); + p->ctrl[w][h].st[1] = 4 * (float)h / (p->height - 1); + } + } + UpdatePatchInspector(); +} +*/ + +/* +================== +Patch_AdjustRows +================== +*/ +/* +void Patch_AdjustRows(patchMesh_t *p, int nRows) +{ + vec3_t vTemp, vTemp2; + int i, w, h; + + if (nRows & 0x01 || p->height + nRows < 3 || p->height + nRows > MAX_PATCH_HEIGHT) + return; + + // add in column adjustment + p->height += nRows; + + for (w = 0; w < p->width; w++) + { + // for each row, we need to evenly disperse p->height number + // of points across the old bounds + + // calc total distance to interpolate + VectorSubtract(p->ctrl[w][p->height - 1 - nRows].xyz, p->ctrl[w][0].xyz, vTemp); + + //vTemp[0] = vTemp[1] = vTemp[2] = 0; + //for (h = 0; h < p->height - nRows; h ++) + //{ + // VectorAdd(vTemp, p->ctrl[w][h], vTemp); + //} + + // amount per cycle + for (i = 0; i < 3; i ++) + { + vTemp2[i] = vTemp[i] / (p->height - 1); + } + + // move along + for (h = 0; h < p->height-1; h++) + { + VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w][h+1].xyz); + } + + } + for ( w = 0 ; w < p->width ; w++ ) + { + for ( h = 0 ; h < p->height ; h++ ) + { + p->ctrl[w][h].st[0] = 4 * (float)w / (p->width - 1); + p->ctrl[w][h].st[1] = 4 * (float)h / (p->height - 1); + } + } + UpdatePatchInspector(); +} +*/ + +/* +================== +Patch_DisperseRows +================== +*/ + +void Patch_DisperseRows() +{ + vec3_t vTemp, vTemp2; + int i, w, h; + + + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t *p = pb->pPatch; + Patch_Rebuild(p); + for (w = 0; w < p->width; w++) + { + // for each row, we need to evenly disperse p->height number + // of points across the old bounds + + // calc total distance to interpolate + VectorSubtract(p->ctrl[w][p->height - 1].xyz, p->ctrl[w][0].xyz, vTemp); + + //vTemp[0] = vTemp[1] = vTemp[2] = 0; + //for (h = 0; h < p->height - nRows; h ++) + //{ + // VectorAdd(vTemp, p->ctrl[w][h], vTemp); + //} + + // amount per cycle + for (i = 0; i < 3; i ++) + { + vTemp2[i] = vTemp[i] / (p->height - 1); + } + + // move along + for (h = 0; h < p->height-1; h++) + { + VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w][h+1].xyz); + } + Patch_Naturalize(p); + + } + } + } + UpdatePatchInspector(); +} + +/* +================== +Patch_DisperseIntermediateRows +================== +*/ + +void Patch_DisperseIntermediateRows() +{ + vec3_t vTemp, vTemp2; + int i, w, h; + + + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t *p = pb->pPatch; + Patch_Rebuild(p); + for (w = 0; w < p->width; w++) + { + // move along + for (h = 0; h < p->height; h+=2) + { + // calc distance to interpolate + VectorSubtract(p->ctrl[w][h+2].xyz, p->ctrl[w][h].xyz, vTemp); + + // halve distance + for (i = 0; i < 3; i ++) + { + vTemp2[i] = vTemp[i] / 2; + } + + // move control points + VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w][h+1].xyz); + } + } + } + } + UpdatePatchInspector(); +} + +/* +================== +Patch_DisperseIntermediateColumns +================== +*/ +void Patch_DisperseIntermediateColumns() +{ + vec3_t vTemp, vTemp2; + int i, w, h; + + + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t *p = pb->pPatch; + Patch_Rebuild(p); + for (h = 0; h < p->height; h++) + { + // move along + for (w = 0; w < p->width; w+=2) + { + // calc distance to interpolate + VectorSubtract(p->ctrl[w+2][h].xyz, p->ctrl[w][h].xyz, vTemp); + + // halve distance + for (i = 0; i < 3; i ++) + { + vTemp2[i] = vTemp[i] / 2; + } + + // move control points + VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w+1][h].xyz); + } + } + } + } + UpdatePatchInspector(); +} + + + +/* +================== +Patch_AdjustSelected +================== +*/ +void Patch_AdjustSelected(bool bInsert, bool bColumn, bool bFlag) +{ + bool bUpdate = false; + for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + if (bInsert) + { + if (bColumn) + { + Patch_InsertColumn(pb->pPatch, bFlag); + } + else + { + Patch_InsertRow(pb->pPatch, bFlag); + } + } + else + { + if (bColumn) + { + Patch_RemoveColumn(pb->pPatch, bFlag); + } + else + { + Patch_RemoveRow(pb->pPatch, bFlag); + } + } + bUpdate = true; + vec3_t vMin, vMax; + patchMesh_t *p = pb->pPatch; + Patch_CalcBounds(p, vMin, vMax); + Brush_RebuildBrush(p->pSymbiot, vMin, vMax); + pb->pPatch->bDirty = true; // rebuild LOD trees and their normals + } + } + if (bUpdate) + { + Sys_UpdateWindows(W_ALL); + } +} + + +/* +================== +Patch_AdjustSelectedRowCols +================== +*/ +/* +void Patch_AdjustSelectedRowCols(int nRows, int nCols) +{ + for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + Patch_InsertColumn(pb->pPatch, false); + if (nRows != 0) + { + Patch_AdjustRows(pb->pPatch, nRows); + } + + if (nCols != 0) + { + Patch_AdjustColumns(pb->pPatch, nCols); + } + } + } + UpdatePatchInspector(); +} +*/ + +/* +================= +CheckName +temporary stuff, detect potential problems when saving the texture name +will correct the patch on the fly if problem detected +================= +*/ +/*! +\todo performance issue with CheckName calls +don't call this too much, only when absolutely necessary +strategies that call here too much are known to be slow +patch 84 to bug 253 adds an additionnal check for textures/ +*/ +void CheckName( patchMesh_t *p, char *pname ) +{ + if(strncmp(p->pShader->getName(), "textures/", 9) != 0) + p->pShader = QERApp_Shader_ForName(SHADER_NOT_FOUND); + + // some manage to get long filename textures (with spaces) in their maps + if (strchr( p->pShader->getName(), ' ' )) + { + char Msg1[1024]; + sprintf( Msg1, "Can't save texture with spaces in name. Rename %s\nNOTE: This message may popup several times .. once for each buggy face detected.", p->pShader->getName() ); + Sys_Printf("%s\n", Msg1 ); + gtk_MessageBox(g_pParentWnd->m_pWidget, Msg1, "Error saving map", MB_OK ); + strcpy( pname, SHADER_NOT_FOUND ); + p->pShader = QERApp_Shader_ForName(SHADER_NOT_FOUND); + p->d_texture = p->pShader->getTexture(); + return; + } + strcpy( pname, p->pShader->getName()+9 ); // remove "textures/" +} + +/* +================== +Patch_Write +================== +*/ +void Patch_Write (patchMesh_t *p, MemStream *file) +{ + char pname[1024]; + + MemFile_fprintf(file, " {\n patchDef2\n {\n"); + + CheckName( p, pname ); + MemFile_fprintf(file, " %s\n", pname ); + MemFile_fprintf(file, " ( %i %i %i %i %i ) \n", p->width, p->height, p->contents, p->flags, p->value); + + + float ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5]; + + int w, h; + for (w = 0; w < p->width; w++) + { + for (h = 0; h < p->height; h++) + { + ctrl[w][h][0] = p->ctrl[w][h].xyz[0]; + ctrl[w][h][1] = p->ctrl[w][h].xyz[1]; + ctrl[w][h][2] = p->ctrl[w][h].xyz[2]; + ctrl[w][h][3] = p->ctrl[w][h].st[0]; + ctrl[w][h][4] = p->ctrl[w][h].st[1]; + } + } + + _Write3DMatrix(file, p->width, p->height, 5, reinterpret_cast(&ctrl)); + + if (g_qeglobals.m_bBrushPrimitMode) + { + if (p->epairs) + { + for (epair_t *ep = p->epairs ; ep ; ep=ep->next) + { + MemFile_fprintf (file, "\"%s\" \"%s\"\n", ep->key, ep->value); + } + } + } + + MemFile_fprintf(file, " }\n }\n"); +} + +void Patch_Write (patchMesh_t *p, FILE *file) +{ + char pname[1024]; + + fprintf(file, " {\n patchDef2\n {\n"); + { + CheckName( p, pname ); + fprintf(file, " %s\n", pname ); + fprintf(file, " ( %i %i %i %i %i ) \n", p->width, p->height, p->contents, p->flags, p->value); + } + + float ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5]; + + int w, h; + for (w = 0; w < p->width; w++) + { + for (h = 0; h < p->height; h++) + { + ctrl[w][h][0] = p->ctrl[w][h].xyz[0]; + ctrl[w][h][1] = p->ctrl[w][h].xyz[1]; + ctrl[w][h][2] = p->ctrl[w][h].xyz[2]; + ctrl[w][h][3] = p->ctrl[w][h].st[0]; + ctrl[w][h][4] = p->ctrl[w][h].st[1]; + } + } + + _Write3DMatrix(file, p->width, p->height, 5, reinterpret_cast(&ctrl)); + + if (g_qeglobals.m_bBrushPrimitMode) + { + if (p->epairs) + { + for (epair_t *ep = p->epairs ; ep ; ep=ep->next) + { + fprintf (file, "\"%s\" \"%s\"\n", ep->key, ep->value); + } + } + } + + fprintf(file, " }\n }\n"); +} + + +/* +================== +Patch_RotateTexture +================== +*/ +void Patch_RotateTexture(patchMesh_t *p, float fAngle) +{ + p->bDirty = true; + float c = cos(fAngle * Q_PI / 180); + float s = sin(fAngle * Q_PI / 180); + + Patch_TransformLODTexture(p, c, s, ROTATE); + + for (int w = 0; w < p->width; w++) + { + for (int h = 0; h < p->height; h++) + { + //if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1) + // continue; + + float x = p->ctrl[w][h].st[0]; + float y = p->ctrl[w][h].st[1]; + p->ctrl[w][h].st[0] = x * c - y * s; + p->ctrl[w][h].st[1] = y * c + x * s; + } + } +} + + +/* +================== +Patch_ScaleTexture +================== +*/ +void Patch_ScaleTexture(patchMesh_t *p, float fx, float fy, bool bFixup) +{ + // FIXME: + // this hack turns scales into 1.1 or 0.9 + if (bFixup) + { + fx = (fx == 0) ? 1.0 : (fx > 0) ? 0.9 : 1.10; + fy = (fy == 0) ? 1.0 : (fy > 0) ? 0.9 : 1.10; + } + else + { + if (fx == 0) + fx = 1.0; + if (fy == 0) + fy = 1.0; + } + + for (int w = 0; w < p->width; w++) + { + for (int h = 0; h < p->height; h++) + { + if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1) + continue; + + p->ctrl[w][h].st[0] *= fx; + p->ctrl[w][h].st[1] *= fy; + } + } + if (g_qeglobals.d_select_mode == sel_curvepoint) + { + p->bDirty = true; + Patch_LODMatchAll(); + } + else + { + Patch_TransformLODTexture(p, fx, fy, SCALE); + p->LODUpdated = true; + } +} + + +/* +================== +Patch_ShiftTexture +shift a texture given a pixel count +================== +*/ +void Patch_ShiftTexture(patchMesh_t *p, float fx, float fy) +{ + qtexture_t *pTex; + pTex = p->pShader->getTexture(); + fx = -1 * fx / pTex->width; + fy = fy / pTex->height; + Patch_ShiftTextureST(p, fx, fy); +} + +/* +==================== +Patch_ShiftTextureST +shift a patch texture given an ST increment +==================== +*/ +void Patch_ShiftTextureST(patchMesh_t *p, float fx, float fy) +{ +#ifdef _DEBUG + // NOTE: when called by Patch_ShiftTexture this warning may be bogus + if ((ABS(fx) >= 1) || (ABS(fy) >= 1)) + Sys_Printf("WARNING: increments exceed 1 in Patch_ShiftTextureST\n"); +#endif + for (int w = 0; w < p->width; w++) + { + for (int h = 0; h < p->height; h++) + { + if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1) + continue; + + p->ctrl[w][h].st[0] += fx; + p->ctrl[w][h].st[1] += fy; + } + } + if (g_qeglobals.d_select_mode == sel_curvepoint) + { + p->bDirty = true; + Patch_LODMatchAll(); + } + else + { + Patch_TransformLODTexture(p, fx, fy, TRANSLATE); + p->LODUpdated = true; + } +} + +/* +================== +Patch_ToggleInverted +================== +*/ +void Patch_ToggleInverted() +{ + bool bUpdate = false; + + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + bUpdate = true; + patchInvert(pb->pPatch); + } + } + + if (bUpdate) + { + Sys_UpdateWindows(W_ALL); + } + UpdatePatchInspector(); +} + +/* +================== +Patch_ToggleInverted +================== +*/ +void Patch_InvertTexture(bool bY) +{ + bool bUpdate = false; + + float fTemp[2]; + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + bUpdate = true; + patchMesh_t *p = pb->pPatch; + p->bDirty = true; + if (bY) + { + for ( int i = 0 ; i < p->height ; i++ ) + { + for (int j = 0; j < p->width / 2; j++) + { + memcpy(fTemp, &p->ctrl[p->width - 1- j][i].st[0], sizeof (float[2])); + memcpy(&p->ctrl[p->width - 1- j][i].st[0], &p->ctrl[j][i].st[0], sizeof(float[2])); + memcpy(&p->ctrl[j][i].st[0], fTemp, sizeof(float[2])); + } + } + } + else + { + for ( int i = 0 ; i < p->width ; i++ ) + { + for (int j = 0; j < p->height / 2; j++) + { + memcpy(fTemp, &p->ctrl[i][p->height - 1- j].st[0], sizeof (float[2])); + memcpy(&p->ctrl[i][p->height - 1 - j].st[0], &p->ctrl[i][j].st[0], sizeof(float[2])); + memcpy(&p->ctrl[i][j].st[0], fTemp, sizeof(float[2])); + } + } + } + } + } + + if (bUpdate) + { + Sys_UpdateWindows(W_ALL); + } + UpdatePatchInspector(); +} + + + + +/* +================== +Patch_Save +================== + Saves patch ctrl info (originally to deal with a + cancel in the surface dialog +*/ +void Patch_Save(patchMesh_t *p) +{ + patchSave.width = p->width; + patchSave.height = p->height; + memcpy(patchSave.ctrl, p->ctrl, sizeof(p->ctrl)); +} + + +/* +================== +Patch_Restore +================== +*/ +void Patch_Restore(patchMesh_t *p) +{ + p->width = patchSave.width; + p->height = patchSave.height; + memcpy(p->ctrl, patchSave.ctrl, sizeof(p->ctrl)); +} + +void Patch_ResetTexturing(float fx, float fy) +{ + for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t *p = pb->pPatch; + p->bDirty = true; + for ( int i = 0 ; i < p->width ; i++ ) + { + for ( int j = 0 ; j < p->height ; j++ ) + { + p->ctrl[i][j].st[0] = fx * (float)i / (p->width - 1); + p->ctrl[i][j].st[1] = 1 - fy * (float)j / (p->height - 1); + } + } + } + } +} + +// NOTE TTimo stub! +void Patch_FitTexturing() +{ + Patch_ResetTexturing(1.0f, 1.0f); +} + +void Patch_SetTextureInfo(texdef_t *pt) +{ + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + if (pt->rotate) + Patch_RotateTexture(pb->pPatch, pt->rotate); + + if (pt->shift[0] || pt->shift[1]) + Patch_ShiftTexture(pb->pPatch, pt->shift[0], pt->shift[1]); + + if (pt->scale[0] || pt->scale[1]) + Patch_ScaleTexture(pb->pPatch, pt->scale[0], pt->scale[1], false); + + patchMesh_t *p = pb->pPatch; + p->contents = pt->contents; + p->flags = pt->flags; + p->value = pt->value; + } + } +} + +bool OnlyPatchesSelected() +{ + if (g_ptrSelectedFaces.GetSize() > 0 || selected_brushes.next == &selected_brushes) + return false; + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (!pb->patchBrush) + { + return false; + } + } + return true; +} + +bool AnyPatchesSelected() +{ + if (g_ptrSelectedFaces.GetSize() > 0 || selected_brushes.next == &selected_brushes) + return false; + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + return true; + } + } + return false; +} + +patchMesh_t* SinglePatchSelected() +{ + if (selected_brushes.next->patchBrush) + { + return selected_brushes.next->pPatch; + } + return NULL; +} + +void Patch_BendToggle() +{ + if (g_bPatchBendMode) + { + g_bPatchBendMode = false; + HideInfoDialog(); + g_pParentWnd->UpdatePatchToolbarButtons() ; + return; + } + + brush_t* b = selected_brushes.next; + + if (!QE_SingleBrush(true) || !b->patchBrush) + { + Sys_Printf("Patch_BendToggle: you must have a single patch selected\n"); + return; + } + + Patch_Save(b->pPatch); + g_bPatchBendMode = true; + g_nPatchBendState = BEND_SELECT_ROTATION; + g_bPatchAxisOnRow = true; + g_nPatchAxisIndex = 1; + ShowInfoDialog(g_pBendStateMsg[BEND_SELECT_ROTATION]); +} + +void Patch_BendHandleTAB() +{ + if (!g_bPatchBendMode) + { + return; + } + + brush_t* b = selected_brushes.next; + if (!QE_SingleBrush() || !b->patchBrush) + { + Patch_BendToggle(); + Sys_Printf("No patch to bend!"); + return; + } + + patchMesh_t *p = b->pPatch; + + bool bShift = Sys_ShiftDown (); + + if (g_nPatchBendState == BEND_SELECT_ROTATION) + { + // only able to deal with odd numbered rows/cols + g_nPatchAxisIndex += (bShift) ? -2 : 2; + if (g_bPatchAxisOnRow) + { + if ((bShift) ? g_nPatchAxisIndex <= 0 : g_nPatchAxisIndex >= p->height) + { + g_bPatchAxisOnRow = false; + g_nPatchAxisIndex = (bShift) ? p->width-1 : 1; + } + } + else + { + if ((bShift) ? g_nPatchAxisIndex <= 0 : g_nPatchAxisIndex >= p->width) + { + g_bPatchAxisOnRow = true; + g_nPatchAxisIndex = (bShift) ? p->height-1 : 1; + } + } + } + else + if (g_nPatchBendState == BEND_SELECT_ORIGIN) + { + g_nBendOriginIndex += (bShift) ? -1 : 1; + if (g_bPatchAxisOnRow) + { + if (bShift) + { + if (g_nBendOriginIndex < 0) + g_nBendOriginIndex = p->width-1; + } + else + { + if (g_nBendOriginIndex > p->width-1) + g_nBendOriginIndex = 0; + } + VectorCopy(p->ctrl[g_nBendOriginIndex][g_nPatchAxisIndex].xyz, g_vBendOrigin); + } + else + { + if (bShift) + { + if (g_nBendOriginIndex < 0) + g_nBendOriginIndex = p->height-1; + } + else + { + if (g_nBendOriginIndex > p->height-1) + g_nBendOriginIndex = 0; + } + VectorCopy(p->ctrl[g_nPatchAxisIndex][g_nBendOriginIndex].xyz, g_vBendOrigin); + } + } + else + if (g_nPatchBendState == BEND_SELECT_EDGE) + { + g_bPatchLowerEdge ^= 1; + } + Sys_UpdateWindows(W_ALL); +} + +void Patch_BendHandleENTER() +{ + if (!g_bPatchBendMode) + { + return; + } + + if (g_nPatchBendState < BEND_BENDIT) + { + g_nPatchBendState++; + ShowInfoDialog(g_pBendStateMsg[g_nPatchBendState]); + if (g_nPatchBendState == BEND_SELECT_ORIGIN) + { + g_vBendOrigin[0] = g_vBendOrigin[1] = g_vBendOrigin[2] = 0; + g_nBendOriginIndex = 0; + Patch_BendHandleTAB(); + } + else + if (g_nPatchBendState == BEND_SELECT_EDGE) + { + g_bPatchLowerEdge = true; + } + else + if (g_nPatchBendState == BEND_BENDIT) + { + // basically we go into rotation mode, set the axis to the center of the + } + } + else + { + // done + Patch_BendToggle(); + } + Sys_UpdateWindows(W_ALL); + +} + + +void Patch_BendHandleESC() +{ + if (!g_bPatchBendMode) + { + return; + } + Patch_BendToggle(); + brush_t* b = selected_brushes.next; + if (QE_SingleBrush() && b->patchBrush) + { + Patch_Restore(b->pPatch); + } + Sys_UpdateWindows(W_ALL); +} + +void Patch_SetBendRotateOrigin(patchMesh_t *p) +{ +#if 1 + int nType = g_pParentWnd->ActiveXY()->GetViewType(); + int nDim3 = (nType == XY) ? 2 : (nType == YZ) ? 0 : 1; + + g_vBendOrigin[nDim3] = 0; + VectorCopy(g_vBendOrigin, g_pParentWnd->ActiveXY()->RotateOrigin()); + return; +#else + int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0; + int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2; + + float fxLo, fyLo, fxHi, fyHi; + fxLo = fyLo = 9999; + fxHi = fyHi = -9999; + + if (g_bPatchAxisOnRow) + { + for (int i = 0; i < p->width; i++) + { + if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1] < fxLo) + fxLo = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1]; + + if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1] > fxHi) + fxHi = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1]; + + if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2] < fyLo) + fyLo = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2]; + + if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2] > fyHi) + fyHi = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2]; + } + } + else + { + for (int i = 0; i < p->height; i++) + { + if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1] < fxLo) + fxLo = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1]; + + if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1] > fxHi) + fxHi = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1]; + + if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2] < fyLo) + fyLo = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2]; + + if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2] > fyHi) + fyHi = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2]; + } + } + + g_pParentWnd->ActiveXY()->RotateOrigin()[0] = g_pParentWnd->ActiveXY()->RotateOrigin()[1] = g_pParentWnd->ActiveXY()->RotateOrigin()[2] = 0.0; + g_pParentWnd->ActiveXY()->RotateOrigin()[nDim1] = (fxLo + fxHi) * 0.5; + g_pParentWnd->ActiveXY()->RotateOrigin()[nDim2] = (fyLo + fyHi) * 0.5; +#endif +} + +// also sets the rotational origin +void Patch_SelectBendAxis() +{ + brush_t* b = selected_brushes.next; + if (!QE_SingleBrush() || !b->patchBrush) + { + // should not ever happen + Patch_BendToggle(); + return; + } + + patchMesh_t *p = b->pPatch; + if (g_bPatchAxisOnRow) + { + SelectRow(p, g_nPatchAxisIndex, false); + } + else + { + SelectColumn(p, g_nPatchAxisIndex, false); + } + + //FIXME: this only needs to be set once... + Patch_SetBendRotateOrigin(p); + +} + +void Patch_SelectBendNormal() +{ + brush_t* b = selected_brushes.next; + if (!QE_SingleBrush() || !b->patchBrush) + { + // should not ever happen + Patch_BendToggle(); + return; + } + + patchMesh_t *p = b->pPatch; + + g_qeglobals.d_num_move_points = 0; + if (g_bPatchAxisOnRow) + { + if (g_bPatchLowerEdge) + { + for (int j = 0; j < g_nPatchAxisIndex; j++) + SelectRow(p, j, true); + } + else + { + for (int j = p->height-1; j > g_nPatchAxisIndex; j--) + SelectRow(p, j, true); + } + } + else + { + if (g_bPatchLowerEdge) + { + for (int j = 0; j < g_nPatchAxisIndex; j++) + SelectColumn(p, j, true); + } + else + { + for (int j = p->width-1; j > g_nPatchAxisIndex; j--) + SelectColumn(p, j, true); + } + } + Patch_SetBendRotateOrigin(p); +} + + + +/* +void Patch_InsDelToggle() +{ + if (g_bPatchInsertMode) + { + g_bPatchInsertMode = false; + HideInfoDialog(); + g_pParentWnd->UpdatePatchToolbarButtons() ; + return; + } + + brush_t* b = selected_brushes.next; + + if (!QE_SingleBrush(true) || !b->patchBrush) + { + Sys_Printf("Patch_InsDelToggle: you must have a single patch selected\n"); + return; + } + + Patch_Save(b->pPatch); + g_bPatchInsertMode = true; + g_nPatchInsertState = INSERT_SELECT_EDGE; + g_bPatchAxisOnRow = true; + g_nPatchAxisIndex = 0; + ShowInfoDialog(g_pInsertStateMsg[INSERT_SELECT_EDGE]); + +} + +void Patch_InsDelESC() +{ + if (!g_bPatchInsertMode) + { + return; + } + Patch_InsDelToggle(); + Sys_UpdateWindows(W_ALL); +} + + +void Patch_InsDelHandleENTER() +{ +} + +void Patch_InsDelHandleTAB() +{ + if (!g_bPatchInsertMode) + { + Patch_InsDelToggle(); + return; + } + + brush_t* b = selected_brushes.next; + if (!QE_SingleBrush() || !b->patchBrush) + { + Patch_BendToggle(); + Sys_Printf("No patch to bend!"); + return; + } + + patchMesh_t *p = b->pPatch; + + // only able to deal with odd numbered rows/cols + g_nPatchAxisIndex += 2; + if (g_bPatchAxisOnRow) + { + if (g_nPatchAxisIndex >= p->height-1) + { + g_bPatchAxisOnRow = false; + g_nPatchAxisIndex = 0; + } + } + else + { + if (g_nPatchAxisIndex >= p->width-1) + { + g_bPatchAxisOnRow = true; + g_nPatchAxisIndex = 0; + } + } + Sys_UpdateWindows(W_ALL); +} +*/ + + +void _Write1DMatrix (FILE *f, int x, float *m) { + int i; + + fprintf (f, "( "); + for (i = 0 ; i < x ; i++) { + if (m[i] == (int)m[i] ) { + fprintf (f, "%i ", (int)m[i]); + } else { + fprintf (f, "%f ", m[i]); + } + } + fprintf (f, ")"); +} + +void _Write2DMatrix (FILE *f, int y, int x, float *m) { + int i; + + fprintf (f, "( "); + for (i = 0 ; i < y ; i++) { + _Write1DMatrix (f, x, m + i*x); + fprintf (f, " "); + } + fprintf (f, ")\n"); +} + + +void _Write3DMatrix (FILE *f, int z, int y, int x, float *m) { + int i; + + fprintf (f, "(\n"); + for (i = 0 ; i < z ; i++) { + _Write2DMatrix (f, y, x, m + i*(x*MAX_PATCH_HEIGHT) ); + } + fprintf (f, ")\n"); +} + +void _Write1DMatrix (MemStream *f, int x, float *m) { + int i; + + MemFile_fprintf (f, "( "); + for (i = 0 ; i < x ; i++) { + if (m[i] == (int)m[i] ) { + MemFile_fprintf (f, "%i ", (int)m[i]); + } else { + MemFile_fprintf (f, "%f ", m[i]); + } + } + MemFile_fprintf (f, ")"); +} + +void _Write2DMatrix (MemStream *f, int y, int x, float *m) { + int i; + + MemFile_fprintf (f, "( "); + for (i = 0 ; i < y ; i++) { + _Write1DMatrix (f, x, m + i*x); + MemFile_fprintf (f, " "); + } + MemFile_fprintf (f, ")\n"); +} + + +void _Write3DMatrix (MemStream *f, int z, int y, int x, float *m) { + int i; + + MemFile_fprintf (f, "(\n"); + for (i = 0 ; i < z ; i++) { + _Write2DMatrix (f, y, x, m + i*(x*MAX_PATCH_HEIGHT) ); + } + MemFile_fprintf (f, ")\n"); +} + +// NOTE: why the hell is this called Naturalize? +// we dispatch either to Patch+Naturalize or Patch_CapTexture.. +void Patch_NaturalizeSelected(bool bCap) +{ + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + if (bCap) + Patch_CapTexture(pb->pPatch);//, bCycleCap); + else + Patch_Naturalize(pb->pPatch); + } + } +} + +// go through the selected patches and call Patch_CapTexture +// deal with cycling +void Patch_CycleCapSelected() +{ + // compute the g_vCycleCapNormal according to g_nCycleCapIndex + VectorClear (g_vCycleCapNormal); + g_vCycleCapNormal[g_nCycleCapIndex] = 1.0f; // cf VIEWTYPE defintion: enum VIEWTYPE {YZ, XZ, XY}; + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + Patch_CapTexture(pb->pPatch, true); + } + } + switch (g_nCycleCapIndex) + { + case YZ: + g_nCycleCapIndex = XZ; + break; + case XZ: + g_nCycleCapIndex = XY; + break; + case XY: + g_nCycleCapIndex = YZ; + break; + } +} + +bool within(vec3_t vTest, vec3_t vTL, vec3_t vBR) +{ + int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0; + int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2; + if ((vTest[nDim1] > vTL[nDim1] && vTest[nDim1] < vBR[nDim1]) || + (vTest[nDim1] < vTL[nDim1] && vTest[nDim1] > vBR[nDim1])) + { + if ((vTest[nDim2] > vTL[nDim2] && vTest[nDim2] < vBR[nDim2]) || + (vTest[nDim2] < vTL[nDim2] && vTest[nDim2] > vBR[nDim2])) + return true; + } + return false; +} + + +void Patch_SelectAreaPoints(bool bMulti) +{ + if (!bMulti) + g_qeglobals.d_num_move_points = 0; + + if( g_nPatchClickedView == W_CAMERA ) { + // Clip against a pyramid + // Create our 5 normals (that are pointing to the inside) + camera_t *m_pCamera = g_pParentWnd->GetCamWnd()->Camera(); + vec3_t norm[5]; + float r[2], u[2], hh, hw; + int idx; + vec_t corners[2][2]; + vec3_t ray[4]; + vec3_t check; + + VectorCopy( m_pCamera->vpn, norm[0] ); // only points in front of the camera + + // get our rectangle + corners[0][0] = MIN( g_qeglobals.d_vAreaTL[0], g_qeglobals.d_vAreaBR[0] ); + corners[0][1] = MAX( g_qeglobals.d_vAreaTL[1], g_qeglobals.d_vAreaBR[1] ); + corners[1][0] = MAX( g_qeglobals.d_vAreaTL[0], g_qeglobals.d_vAreaBR[0] ); + corners[1][1] = MIN( g_qeglobals.d_vAreaTL[1], g_qeglobals.d_vAreaBR[1] ); + + // calculate our four ray vectors + hh = m_pCamera->height/2; + hw = m_pCamera->width/2; + u[0] = (float)(corners[0][1] - hh) / (hw); + r[0] = (float)(corners[0][0] - hw) / (hw); + u[1] = (float)(corners[1][1] - hh) / (hw); + r[1] = (float)(corners[1][0] - hw) / (hw); + + for (idx=0 ; idx<3; idx++) + ray[0][idx] = m_pCamera->vpn[idx] + m_pCamera->vright[idx] * r[0] + m_pCamera->vup[idx] * u[0]; + for (idx=0 ; idx<3; idx++) + ray[1][idx] = m_pCamera->vpn[idx] + m_pCamera->vright[idx] * r[1] + m_pCamera->vup[idx] * u[0]; + for (idx=0 ; idx<3; idx++) + ray[2][idx] = m_pCamera->vpn[idx] + m_pCamera->vright[idx] * r[1] + m_pCamera->vup[idx] * u[1]; + for (idx=0 ; idx<3; idx++) + ray[3][idx] = m_pCamera->vpn[idx] + m_pCamera->vright[idx] * r[0] + m_pCamera->vup[idx] * u[1]; + + // Create our four other directions from these + CrossProduct( ray[0], ray[1], norm[1] ); VectorNormalize( norm[1], norm[1] ); + CrossProduct( ray[1], ray[2], norm[2] ); VectorNormalize( norm[2], norm[2] ); + CrossProduct( ray[2], ray[3], norm[3] ); VectorNormalize( norm[3], norm[3] ); + CrossProduct( ray[3], ray[0], norm[4] ); VectorNormalize( norm[4], norm[4] ); + + // 3D clipping + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t *p = pb->pPatch; + for (int i = 0; i < p->width; i++) + { + for (int j = 0; j < p->height; j++) + { + VectorSubtract( m_pCamera->origin, p->ctrl[i][j].xyz, check ); + VectorNormalize( check, check ); + for (idx=0 ; idx<5; idx++) + { + if (DotProduct(check, norm[idx])>=0) + break; + } + if (idx == 5) // all test were good + { + if (bMulti && PointInMoveList(p->ctrl[i][j].xyz) != -1) + RemovePointFromMoveList(p->ctrl[i][j].xyz); + else + g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz; + } + } + } + } + } + } else + { + // Simple 2D clipping + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t *p = pb->pPatch; + for (int i = 0; i < p->width; i++) + { + for (int j = 0; j < p->height; j++) + { + if (within(p->ctrl[i][j].xyz, g_qeglobals.d_vAreaTL, g_qeglobals.d_vAreaBR)) + { + if (bMulti && PointInMoveList(p->ctrl[i][j].xyz) != -1) + RemovePointFromMoveList(p->ctrl[i][j].xyz); + else + g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz; + } + } + } + } + } + } + + g_nPatchClickedView = -1; +} + +// TTimo: return the shader name for a patch +const char* Patch_GetTextureName() +{ + brush_t* b = selected_brushes.next; + if (b->patchBrush) + { + patchMesh_t *p = b->pPatch; + return p->pShader->getName(); + } + return ""; +} + +patchMesh_t* Patch_Duplicate(patchMesh_t *pFrom) +{ + patchMesh_t* p = MakeNewPatch(); + memcpy(p, pFrom , sizeof(patchMesh_t)); + + // spog - initialise patch LOD pointers (again) + Patch_InitialiseLODPointers(p); + p->drawLists = NULL; + + p->bSelected = false; + p->bDirty = true; + p->bOverlay = false; + p->nListID = -1; + AddBrushForPatch(p); + + return p; +} + + +void Patch_Thicken(int nAmount, bool bSeam, qboolean bGroupResult) +{ + int i, j, h, w; + brush_t *b; + patchMesh_t *pSeam; + vec3_t vMin, vMax; + CPtrArray brushes; + + nAmount = -nAmount; + + + if (!QE_SingleBrush()) + { + Sys_Printf("Cannot thicken multiple patches. Please select a single patch.\n"); + return; + } + + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t *p = pb->pPatch; + Patch_MeshNormals(p); + patchMesh_t *pNew = Patch_Duplicate(p); + for (i = 0; i < p->width; i++) + { + for (j = 0; j < p->height; j++) + { + VectorMA (p->ctrl[i][j].xyz, nAmount, p->ctrl[i][j].normal, pNew->ctrl[i][j].xyz); + } + } + + Patch_Rebuild(pNew); + pNew->type |= PATCH_THICK; + brushes.Add(pNew->pSymbiot); + + if (bSeam) + { + + // FIXME: this should detect if any edges of the patch are closed and act appropriately + // + if (!(p->type & PATCH_CYLINDER)) + { + b = Patch_GenericMesh(3, p->height, 2, false, true); + pSeam = b->pPatch; + pSeam->type |= PATCH_SEAM; + for (i = 0; i < p->height; i++) + { + VectorCopy(p->ctrl[0][i].xyz, pSeam->ctrl[0][i].xyz); + VectorCopy(pNew->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz); + VectorAdd(pSeam->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz, pSeam->ctrl[1][i].xyz); + VectorScale(pSeam->ctrl[1][i].xyz, 0.5, pSeam->ctrl[1][i].xyz); + } + + + Patch_CalcBounds(pSeam, vMin, vMax); + Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax); + //--Patch_CapTexture(pSeam); + Patch_Naturalize(pSeam); + patchInvert(pSeam); + brushes.Add(b); + + w = p->width - 1; + b = Patch_GenericMesh(3, p->height, 2, false, true); + pSeam = b->pPatch; + pSeam->type |= PATCH_SEAM; + for (i = 0; i < p->height; i++) + { + VectorCopy(p->ctrl[w][i].xyz, pSeam->ctrl[0][i].xyz); + VectorCopy(pNew->ctrl[w][i].xyz, pSeam->ctrl[2][i].xyz); + VectorAdd(pSeam->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz, pSeam->ctrl[1][i].xyz); + VectorScale(pSeam->ctrl[1][i].xyz, 0.5, pSeam->ctrl[1][i].xyz); + } + Patch_CalcBounds(pSeam, vMin, vMax); + Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax); + //--Patch_CapTexture(pSeam); + Patch_Naturalize(pSeam); + brushes.Add(b); + } + + //--{ + // otherwise we will add one per end + b = Patch_GenericMesh(p->width, 3, 2, false, true); + pSeam = b->pPatch; + pSeam->type |= PATCH_SEAM; + for (i = 0; i < p->width; i++) + { + VectorCopy(p->ctrl[i][0].xyz, pSeam->ctrl[i][0].xyz); + VectorCopy(pNew->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz); + VectorAdd(pSeam->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz, pSeam->ctrl[i][1].xyz); + VectorScale(pSeam->ctrl[i][1].xyz, 0.5, pSeam->ctrl[i][1].xyz); + } + + + Patch_CalcBounds(pSeam, vMin, vMax); + Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax); + //--Patch_CapTexture(pSeam); + Patch_Naturalize(pSeam); + patchInvert(pSeam); + brushes.Add(b); + + h = p->height - 1; + b = Patch_GenericMesh(p->width, 3, 2, false, true); + pSeam = b->pPatch; + pSeam->type |= PATCH_SEAM; + for (i = 0; i < p->width; i++) + { + VectorCopy(p->ctrl[i][h].xyz, pSeam->ctrl[i][0].xyz); + VectorCopy(pNew->ctrl[i][h].xyz, pSeam->ctrl[i][2].xyz); + VectorAdd(pSeam->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz, pSeam->ctrl[i][1].xyz); + VectorScale(pSeam->ctrl[i][1].xyz, 0.5, pSeam->ctrl[i][1].xyz); + } + Patch_CalcBounds(pSeam, vMin, vMax); + Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax); + //--Patch_CapTexture(pSeam); + Patch_Naturalize(pSeam); + brushes.Add(b); + + } + patchInvert(pNew); + } + } + + for (i = 0; i < brushes.GetSize(); i++) + { + Select_Brush(reinterpret_cast(brushes.GetAt(i))); + } + + if(bGroupResult) + { + entity_t *e = Entity_Alloc(); + SetKeyValue(e, "classname", "func_group"); + SetKeyValue(e, "type", "patchThick"); + Select_GroupEntity(e); + Entity_AddToList(e, &entities); + } + + UpdatePatchInspector(); +} + + +/* +lets get another list together as far as necessities.. + +*snapping stuff to the grid (i will only snap movements by the mouse to the grid.. snapping the rotational bend stuff will fubar everything) + +capping bevels/endcaps + +hot keys + +texture fix for caps + +clear clipboard + +*region fix + +*surface dialog + +*/ + +void Patch_SetOverlays() +{ + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + pb->pPatch->bOverlay = true; + } + } +} + + + +void Patch_ClearOverlays() +{ + brush_t *pb; + for (pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + pb->pPatch->bOverlay = false; + } + } + + for (pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + pb->pPatch->bOverlay = false; + } + } + +} + +// FIXME: spog - er, someone forgot to finish their patch point freezing feature? +// freezes selected vertices +void Patch_Freeze() +{ + brush_t *pb; + for (pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + pb->pPatch->bOverlay = false; + } + } + + for (pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + pb->pPatch->bOverlay = false; + } + } + +} + +void Patch_UnFreeze(bool bAll) +{ +} + +void Patch_Transpose() +{ + int i, j, w; + drawVert_t dv; + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t *p = pb->pPatch; + + if ( p->width > p->height ) + { + for ( i = 0 ; i < p->height ; i++ ) + { + for ( j = i + 1 ; j < p->width ; j++ ) + { + if ( j < p->height ) + { + // swap the value + memcpy(&dv,&p->ctrl[j][i],sizeof(drawVert_t)); + memcpy(&p->ctrl[j][i],&p->ctrl[i][j], sizeof(drawVert_t)); + memcpy(&p->ctrl[i][j],&dv, sizeof(drawVert_t)); + } + else + { + // just copy + memcpy(&p->ctrl[i][j],&p->ctrl[j][i], sizeof(drawVert_t)); + } + } + } + } + else + { + for ( i = 0 ; i < p->width ; i++ ) + { + for ( j = i + 1 ; j < p->height ; j++ ) + { + if ( j < p->width ) + { + // swap the value + memcpy(&dv,&p->ctrl[i][j], sizeof(drawVert_t)); + memcpy(&p->ctrl[i][j],&p->ctrl[j][i], sizeof(drawVert_t)); + memcpy(&p->ctrl[j][i],&dv, sizeof(drawVert_t)); + } + else + { + // just copy + memcpy(&p->ctrl[j][i],&p->ctrl[i][j], sizeof(drawVert_t)); + } + } + } + } + + w = p->width; + p->width = p->height; + p->height = w; + patchInvert(p); + Patch_Rebuild(p); + } + } +} + + + +void Patch_SnapToGrid(patchMesh_t *p) +{ + int i,j,k; + + // if patch points selected, snap only selected points + if (g_qeglobals.d_select_mode == sel_curvepoint && g_qeglobals.d_num_move_points != 0) + for (i=0; iwidth; i++) + for (j = 0; j < p->height; j++) + for (k = 0; k < 3; k++) + p->ctrl[i][j].xyz[k] = floor(p->ctrl[i][j].xyz[k] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + + vec3_t vMin, vMax; + Patch_CalcBounds(p, vMin, vMax); + Brush_RebuildBrush(p->pSymbiot, vMin, vMax); +} + + +void Patch_FindReplaceTexture(brush_t *pb, const char *pFind, const char *pReplace, bool bForce) +{ + if (pb->patchBrush) + { + patchMesh_t *p = pb->pPatch; + if (bForce || strcmpi(p->pShader->getName(), pFind) == 0) + { + p->pShader->DecRef(); + p->pShader = QERApp_Shader_ForName(pReplace); + p->d_texture = p->pShader->getTexture(); + } + } +} + +/* uncomment if necessary, currently not used +void Patch_FromTriangle(vec5_t vx, vec5_t vy, vec5_t vz) +{ + patchMesh_t* p = MakeNewPatch(); + p->pShader = g_qeglobals.d_texturewin.pShader; + p->d_texture = g_qeglobals.d_texturewin.pShader->getTexture(); + p->width = 3; + p->height = 3; + p->type = PATCH_TRIANGLE; + + // 0 0 goes to x + // 0 1 goes to x + // 0 2 goes to x + + // 1 0 goes to mid of x and z + // 1 1 goes to mid of x y and z + // 1 2 goes to mid of x and y + + // 2 0 goes to z + // 2 1 goes to mid of y and z + // 2 2 goes to y + + vec5_t vMidXZ; + vec5_t vMidXY; + vec5_t vMidYZ; + int j; + + for (j = 0; j < 3; j++) + { + _Vector5Add(vx, vz, vMidXZ); + _Vector5Scale(vMidXZ, 0.5, vMidXZ); + //vMidXZ[j] = vx[j] + abs((vx[j] - vz[j]) * 0.5); + } + + for (j = 0; j < 3; j++) + { + _Vector5Add(vx, vy, vMidXY); + _Vector5Scale(vMidXY, 0.5, vMidXY); + //vMidXY[j] = vx[j] + abs((vx[j] - vy[j]) * 0.5); + } + + for (j = 0; j < 3; j++) + { + _Vector5Add(vy, vz, vMidYZ); + _Vector5Scale(vMidYZ, 0.5, vMidYZ); + //vMidYZ[j] = vy[j] + abs((vy[j] - vz[j]) * 0.5); + } + + _Vector53Copy(vx, p->ctrl[0][0].xyz); + _Vector53Copy(vx, p->ctrl[0][1].xyz); + _Vector53Copy(vx, p->ctrl[0][2].xyz); + p->ctrl[0][0].st[0] = vx[3]; + p->ctrl[0][0].st[1] = vx[4]; + p->ctrl[0][1].st[0] = vx[3]; + p->ctrl[0][1].st[1] = vx[4]; + p->ctrl[0][2].st[0] = vx[3]; + p->ctrl[0][2].st[1] = vx[4]; + + _Vector53Copy(vMidXY, p->ctrl[1][0].xyz); + _Vector53Copy(vx, p->ctrl[1][1].xyz); + _Vector53Copy(vMidXZ, p->ctrl[1][2].xyz); + p->ctrl[1][0].st[0] = vMidXY[3]; + p->ctrl[1][0].st[1] = vMidXY[4]; + p->ctrl[1][1].st[0] = vx[3]; + p->ctrl[1][1].st[1] = vx[4]; + p->ctrl[1][2].st[0] = vMidXZ[3]; + p->ctrl[1][2].st[1] = vMidXZ[4]; + + _Vector53Copy(vy, p->ctrl[2][0].xyz); + _Vector53Copy(vMidYZ, p->ctrl[2][1].xyz); + _Vector53Copy(vz, p->ctrl[2][2].xyz); + p->ctrl[2][0].st[0] = vy[3]; + p->ctrl[2][0].st[1] = vy[4]; + p->ctrl[2][1].st[0] = vMidYZ[3]; + p->ctrl[2][1].st[1] = vMidYZ[4]; + p->ctrl[2][2].st[0] = vz[3]; + p->ctrl[2][2].st[1] = vz[4]; + + + //Patch_Naturalize(p); + + // brush_t *b = + AddBrushForPatch(p); + +} +*/ + +#ifdef ENABLE_GROUPS +/* +============== +Patch_SetEpair +sets an epair for the given patch +============== +*/ +void Patch_SetEpair(patchMesh_t *p, const char *pKey, const char *pValue) +{ + if (g_qeglobals.m_bBrushPrimitMode) + { + SetKeyValue(p->epairs, pKey, pValue); + } +} + +/* +================= +Patch_GetKeyValue +================= +*/ +const char* Patch_GetKeyValue(patchMesh_t *p, const char *pKey) +{ + if (g_qeglobals.m_bBrushPrimitMode) + { + return ValueForKey(p->epairs, pKey); + } + return ""; +} +#endif + + +//Real nitpicky, but could you make CTRL-S save the current map with the current name? (ie: File/Save) +/* +Feature addition. +When reading in textures, please check for the presence of a file called "textures.link" or something, which contains one line such as; + +g:\quake3\baseq3\textures\common + + So that, when I'm reading in, lets say, my \eerie directory, it goes through and adds my textures to the palette, along with everything in common. + + Don't forget to add "Finer texture alignment" to the list. I'd like to be able to move in 0.1 increments using the Shift-Arrow Keys. + + No. Sometimes textures are drawn the wrong way on patches. We'd like the ability to flip a texture. Like the way X/Y scale -1 used to worked. + + 1) Easier way of deleting rows, columns +2) Fine tuning of textures on patches (X/Y shifts other than with the surface dialog) +2) Patch matrix transposition + + 1) Actually, bump texture flipping on patches to the top of the list of things to do. +2) When you select a patch, and hit S, it should read in the selected patch texture. Should not work if you multiselect patches and hit S +3) Brandon has a wierd anomoly. He fine-tunes a patch with caps. It looks fine when the patch is selected, but as soon as he escapes out, it reverts to it's pre-tuned state. When he selects the patch again, it looks tuned + + +*1) Flipping textures on patches +*2) When you select a patch, and hit S, it should read in the selected patch texture. Should not work if you multiselect patches and hit S +3) Easier way of deleting rows columns +*4) Thick Curves +5) Patch matrix transposition +6) Inverted cylinder capping +*7) bugs +*8) curve speed + + Have a new feature request. "Compute Bounding Box" for mapobjects (md3 files). This would be used for misc_mapobject (essentially, drop in 3DS Max models into our maps) + + Ok, Feature Request. Load and draw MD3's in the Camera view with proper bounding boxes. This should be off misc_model + + Feature Addition: View/Hide Hint Brushes -- This should be a specific case. +*/ diff --git a/radiant/points.cpp b/radiant/points.cpp index 64e67667..2da92976 100644 --- a/radiant/points.cpp +++ b/radiant/points.cpp @@ -1,249 +1,249 @@ -/* -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 -*/ - -#include "stdafx.h" - -#define MAX_POINTFILE 8192 -static vec3_t s_pointvecs[MAX_POINTFILE]; -static int s_num_points, s_check_point; - -CPointfile g_pointfile; - -// CPointfile routine used by the standard code --------------------------------- - -void CPointfile::Init() -{ - s_num_points = 0; -} - -void CPointfile::PushPoint (vec3_t v) -{ - if (s_num_points < MAX_POINTFILE) - { - VectorCopy (v, s_pointvecs[s_num_points]); - s_num_points++; - } -} - -// create the display list at the end -void CPointfile::GenerateDisplayList() -{ - int i; - - if (!g_qeglobals.d_pointfile_display_list) - g_qeglobals.d_pointfile_display_list = qglGenLists(1); - - qglNewList (g_qeglobals.d_pointfile_display_list, GL_COMPILE); - - qglColor3f (1, 0, 0); - qglDisable(GL_TEXTURE_2D); - qglDisable(GL_TEXTURE_1D); - qglLineWidth (4); - qglBegin(GL_LINE_STRIP); - for (i=0;i= s_num_points-2) - { - Sys_Status ("End of pointfile", 0); - return; - } - s_check_point++; - VectorCopy (s_pointvecs[s_check_point], g_pParentWnd->GetCamWnd()->Camera()->origin); - VectorCopy (s_pointvecs[s_check_point], g_pParentWnd->GetXYWnd()->GetOrigin()); - VectorSubtract (s_pointvecs[s_check_point+1], g_pParentWnd->GetCamWnd()->Camera()->origin, dir); - VectorNormalize (dir, dir); - g_pParentWnd->GetCamWnd()->Camera()->angles[1] = atan2 (dir[1], dir[0])*180/3.14159; - g_pParentWnd->GetCamWnd()->Camera()->angles[0] = asin (dir[2])*180/3.14159; - - Sys_UpdateWindows (W_ALL); -} - -// advance camera to previous point -void Pointfile_Prev (void) -{ - vec3_t dir; - - if ( s_check_point == 0) - { - Sys_Status ("Start of pointfile", 0); - return; - } - s_check_point--; - VectorCopy (s_pointvecs[s_check_point], g_pParentWnd->GetCamWnd()->Camera()->origin); - VectorCopy (s_pointvecs[s_check_point], g_pParentWnd->GetXYWnd()->GetOrigin()); - VectorSubtract (s_pointvecs[s_check_point+1], g_pParentWnd->GetCamWnd()->Camera()->origin, dir); - VectorNormalize (dir, dir); - g_pParentWnd->GetCamWnd()->Camera()->angles[1] = atan2 (dir[1], dir[0])*180/3.14159; - g_pParentWnd->GetCamWnd()->Camera()->angles[0] = asin (dir[2])*180/3.14159; - - Sys_UpdateWindows (W_ALL); -} - -void WINAPI Pointfile_Check (void) -{ - char name[1024]; - int size; - char *data; - char *text; - int line = 1; - vec3_t v; - - strcpy (name, currentmap); - StripExtension (name); - strcat (name, ".lin"); - - size = vfsLoadFullPathFile (name, (void**)&data); - if (size <= 0) - { - Sys_FPrintf (SYS_ERR, "Pointfile %s not found\n", name); - return; - } - - // store a pointer - text = data; - - Sys_Printf ("Reading pointfile %s\n", name); - - g_pointfile.Init(); - - while (*data) - { - if (sscanf(data,"%f %f %f", &v[0], &v[1], &v[2]) != 3) - { - Sys_Printf("Corrupt point file, line %d\n",line); - break; - } - - while (*data && *data != '\n') - { - if (*(data-1) == ' ' && *(data) == '-' && *(data+1) == ' ') - break; - data++; - } - // deal with zhlt style point files. - if (*data == '-') - { - if (sscanf(data,"- %f %f %f", &v[0], &v[1], &v[2]) != 3) - { - Sys_Printf("Corrupt point file, line %d\n",line); - break; - } - - while (*data && *data != '\n') - data++; - - } - while (*data == '\n') - { - data++; // skip the \n - line++; - } - g_pointfile.PushPoint (v); - } - - g_free(text); - - g_pointfile.GenerateDisplayList(); - - Sys_UpdateWindows (W_ALL); -} - -void Pointfile_Draw( void ) -{ - qglCallList (g_qeglobals.d_pointfile_display_list); -} - -void Pointfile_Clear (void) -{ - if (!g_qeglobals.d_pointfile_display_list) - return; - - qglDeleteLists (g_qeglobals.d_pointfile_display_list, 1); - g_qeglobals.d_pointfile_display_list = 0; - Sys_UpdateWindows (W_ALL); -} - -// CPointfile implementation for SAX speicific stuff ------------------------------- -void CPointfile::saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs) -{ - if (strcmp ((char *)name, "polyline")==0) - { - Init(); - // there's a prefs setting to avoid stopping on leak - if (!g_PrefsDlg.m_bLeakStop) - ctx->stop_depth = 0; - } -} - -void CPointfile::saxEndElement (message_info_t *ctx, const xmlChar *name) -{ - if (strcmp ((char *)name, "polyline")==0) - { - // we are done - GenerateDisplayList(); - ctx->bGeometry = false; - } -} - -// only "point" is expected to have characters around here -void CPointfile::saxCharacters (message_info_t *ctx, const xmlChar *ch, int len) -{ - vec3_t v; - - sscanf ((char *)ch, "%f %f %f\n", &v[0], &v[1], &v[2]); - PushPoint (v); -} - -char * CPointfile::getName() -{ - return "Map is leaked"; -} +/* +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 +*/ + +#include "stdafx.h" + +#define MAX_POINTFILE 8192 +static vec3_t s_pointvecs[MAX_POINTFILE]; +static int s_num_points, s_check_point; + +CPointfile g_pointfile; + +// CPointfile routine used by the standard code --------------------------------- + +void CPointfile::Init() +{ + s_num_points = 0; +} + +void CPointfile::PushPoint (vec3_t v) +{ + if (s_num_points < MAX_POINTFILE) + { + VectorCopy (v, s_pointvecs[s_num_points]); + s_num_points++; + } +} + +// create the display list at the end +void CPointfile::GenerateDisplayList() +{ + int i; + + if (!g_qeglobals.d_pointfile_display_list) + g_qeglobals.d_pointfile_display_list = qglGenLists(1); + + qglNewList (g_qeglobals.d_pointfile_display_list, GL_COMPILE); + + qglColor3f (1, 0, 0); + qglDisable(GL_TEXTURE_2D); + qglDisable(GL_TEXTURE_1D); + qglLineWidth (4); + qglBegin(GL_LINE_STRIP); + for (i=0;i= s_num_points-2) + { + Sys_Status ("End of pointfile", 0); + return; + } + s_check_point++; + VectorCopy (s_pointvecs[s_check_point], g_pParentWnd->GetCamWnd()->Camera()->origin); + VectorCopy (s_pointvecs[s_check_point], g_pParentWnd->GetXYWnd()->GetOrigin()); + VectorSubtract (s_pointvecs[s_check_point+1], g_pParentWnd->GetCamWnd()->Camera()->origin, dir); + VectorNormalize (dir, dir); + g_pParentWnd->GetCamWnd()->Camera()->angles[1] = atan2 (dir[1], dir[0])*180/3.14159; + g_pParentWnd->GetCamWnd()->Camera()->angles[0] = asin (dir[2])*180/3.14159; + + Sys_UpdateWindows (W_ALL); +} + +// advance camera to previous point +void Pointfile_Prev (void) +{ + vec3_t dir; + + if ( s_check_point == 0) + { + Sys_Status ("Start of pointfile", 0); + return; + } + s_check_point--; + VectorCopy (s_pointvecs[s_check_point], g_pParentWnd->GetCamWnd()->Camera()->origin); + VectorCopy (s_pointvecs[s_check_point], g_pParentWnd->GetXYWnd()->GetOrigin()); + VectorSubtract (s_pointvecs[s_check_point+1], g_pParentWnd->GetCamWnd()->Camera()->origin, dir); + VectorNormalize (dir, dir); + g_pParentWnd->GetCamWnd()->Camera()->angles[1] = atan2 (dir[1], dir[0])*180/3.14159; + g_pParentWnd->GetCamWnd()->Camera()->angles[0] = asin (dir[2])*180/3.14159; + + Sys_UpdateWindows (W_ALL); +} + +void WINAPI Pointfile_Check (void) +{ + char name[1024]; + int size; + char *data; + char *text; + int line = 1; + vec3_t v; + + strcpy (name, currentmap); + StripExtension (name); + strcat (name, ".lin"); + + size = vfsLoadFullPathFile (name, (void**)&data); + if (size <= 0) + { + Sys_FPrintf (SYS_ERR, "Pointfile %s not found\n", name); + return; + } + + // store a pointer + text = data; + + Sys_Printf ("Reading pointfile %s\n", name); + + g_pointfile.Init(); + + while (*data) + { + if (sscanf(data,"%f %f %f", &v[0], &v[1], &v[2]) != 3) + { + Sys_Printf("Corrupt point file, line %d\n",line); + break; + } + + while (*data && *data != '\n') + { + if (*(data-1) == ' ' && *(data) == '-' && *(data+1) == ' ') + break; + data++; + } + // deal with zhlt style point files. + if (*data == '-') + { + if (sscanf(data,"- %f %f %f", &v[0], &v[1], &v[2]) != 3) + { + Sys_Printf("Corrupt point file, line %d\n",line); + break; + } + + while (*data && *data != '\n') + data++; + + } + while (*data == '\n') + { + data++; // skip the \n + line++; + } + g_pointfile.PushPoint (v); + } + + g_free(text); + + g_pointfile.GenerateDisplayList(); + + Sys_UpdateWindows (W_ALL); +} + +void Pointfile_Draw( void ) +{ + qglCallList (g_qeglobals.d_pointfile_display_list); +} + +void Pointfile_Clear (void) +{ + if (!g_qeglobals.d_pointfile_display_list) + return; + + qglDeleteLists (g_qeglobals.d_pointfile_display_list, 1); + g_qeglobals.d_pointfile_display_list = 0; + Sys_UpdateWindows (W_ALL); +} + +// CPointfile implementation for SAX speicific stuff ------------------------------- +void CPointfile::saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs) +{ + if (strcmp ((char *)name, "polyline")==0) + { + Init(); + // there's a prefs setting to avoid stopping on leak + if (!g_PrefsDlg.m_bLeakStop) + ctx->stop_depth = 0; + } +} + +void CPointfile::saxEndElement (message_info_t *ctx, const xmlChar *name) +{ + if (strcmp ((char *)name, "polyline")==0) + { + // we are done + GenerateDisplayList(); + ctx->bGeometry = false; + } +} + +// only "point" is expected to have characters around here +void CPointfile::saxCharacters (message_info_t *ctx, const xmlChar *ch, int len) +{ + vec3_t v; + + sscanf ((char *)ch, "%f %f %f\n", &v[0], &v[1], &v[2]); + PushPoint (v); +} + +char * CPointfile::getName() +{ + return "Map is leaked"; +} diff --git a/radiant/preferences.cpp b/radiant/preferences.cpp index e49a0b43..07b0a479 100644 --- a/radiant/preferences.cpp +++ b/radiant/preferences.cpp @@ -1,3102 +1,3102 @@ -/* -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 -*/ - -// -// User preferences -// -// Leonardo Zide (leo@lokigames.com) -// - -#include "stdafx.h" -#include -#if defined (__linux__) || defined (__APPLE__) -#include -#include -#include -#include -#include -#endif -#include "missing.h" -#include "gtkmisc.h" - -#ifdef _WIN32 -#include -#define X_OK 0 -#include -#endif - -#define PREF_SECTION "Prefs" -#define INTERNAL_SECTION "Internals" -#define MOUSE_KEY "MouseButtons" -#define WINDOW_KEY "QE4StyleWindows" -#define LAYOUT_KEY "WindowLayout" -#define RUNQ2_KEY "RunQuake2Run" -#define TLOCK_KEY "TextureLock" -#define RLOCK_KEY "RotateLock" -#define LOADLAST_KEY "LoadLast" -#define LOADLASTMAP_KEY "LoadLastMap" -#define LASTPROJ_KEY "LastProject" -#define LASTPROJVER_KEY "LastProjectKey" -#define LASTMAP_KEY "LastMap" -#define FACE_KEY "NewFaceGrab" -#define BSP_KEY "InternalBSP" -#define RCLICK_KEY "NewRightClick" -#define VERTEX_KEY "NewVertex" -#define AUTOSAVE_KEY "Autosave" -#define AUTOSAVETIME_KEY "AutosaveMinutes" -#define PAK_KEY "UsePAK" -#define NEWAPPLY_KEY "ApplyDismissesSurface" -#define HACK_KEY "Gatewayescapehack" -#define TEXTURE_KEY "NewTextureWindowStuff" -#define TINYBRUSH_KEY "CleanTinyBrushes" -#define TINYSIZE_KEY "CleanTinyBrusheSize" -#define SNAPSHOT_KEY "Snapshots" -#define MOVESPEED_KEY "MoveSpeed" -#define ANGLESPEED_KEY "AngleSpeed" -#define SETGAME_KEY "UseSetGame" -#define CAMXYUPDATE_KEY "CamXYUpdate" -#define CAMDRAGMULTISELECT_KEY "CamDragMultiSelect" -#define CAMFREELOOK_KEY "CamFreeLook" -#define CAMINVERSEMOUSE_KEY "CamInverseMouse" -#define CAMDISCRETE_KEY "CamDiscrete" -#define LIGHTDRAW_KEY "NewLightStyle" -#define WHATGAME_KEY "WhichGame" -#define CUBICCLIP_KEY "CubicClipping" -#define CUBICSCALE_KEY "CubicScale" -#define ALTEDGE_KEY "ALTEdgeDrag" -#define FACECOLORS_KEY "FaceColors" -#define SNAPT_KEY "SnapT" -#define XZVIS_KEY "XZVIS" -#define YZVIS_KEY "YZVIS" -#define ZVIS_KEY "ZVIS" -#define SIZEPAINT_KEY "SizePainting" -#define DLLENTITIES_KEY "DLLEntities" -#define DETACHABLEMENUS_KEY "DetachableMenus" -#define PATCHTOOLBAR_KEY "PatchToolBar" -#define WIDETOOLBAR_KEY "WideToolBar" -#define PLUGINTOOLBAR_KEY "PluginToolBar" -#define NOCLAMP_KEY "NoClamp" -#define PREFAB_KEY "PrefabPath" -#define USERINI_KEY "UserINIPath" -#define ROTATION_KEY "Rotation" -#define BUGGYICD_KEY "BuggyICD" -#define CHASEMOUSE_KEY "ChaseMouse" -#define ENTITYSHOW_KEY "EntityShow" -#define TEXTURESCALE_KEY "TextureScale" -#define TEXTURESCROLLBAR_KEY "TextureScrollbar" -#define DISPLAYLISTS_KEY "UseDisplayLists" -#define ANTIALIASEDLINES_KEY "UseAntialiasedPointsAndLines" // Fishman - Add antialiazed points and lines support. 09/03/00 -#define NORMALIZECOLORS_KEY "NormalizeColors" -#define SHADERS_KEY "UseShaders" -#define SWITCHCLIP_KEY "SwitchClipKey" -#define SELWHOLEENTS_KEY "SelectWholeEntitiesKey" -#define TEXTURESUBSET_KEY "UseTextureSubsetLoading" -#define TEXTUREQUALITY_KEY "TextureQuality" -#define SHOWSHADERS_KEY "ShowShaders" -#define SHADERTEST_KEY "ShaderTest" -#define GLLIGHTING_KEY "UseGLLighting" -#define LOADSHADERS_KEY "LoadShaders" -#define NOSTIPPLE_KEY "NoStipple" -#define UNDOLEVELS_KEY "UndoLevels" -#define VERTEXMODE_KEY "VertexSplit" -#define ENGINEPATH_KEY "EnginePath" -#define ENGINE_KEY "Engine" -#define LOGCONSOLE_KEY "LogConsole" -#define SELECTCURVES_KEY "SelectCurves" -#define SELECTMODELS_KEY "SelectModels" -#define SHADERLISTONLY_KEY "ShowShaderlistOnly" -#define WATCHBSP_KEY "WatchBSP" -#define LEAKSTOP_KEY "LeakStop" -#define DOSLEEP_KEY "SleepMode" -#define SUBDIVISIONS_KEY "Subdivisions" -#define CLIPCAULK_KEY "ClipCaulk" -#define PATCHSHOWBOUNDS_KEY "PatchShowBounds" -#define NATIVEGUI_KEY "NativeGUI" -#define STARTONPRIMMON_KEY "StartOnPrimMon" -#define NOSYSMENUPOPUPS_KEY "NoSysMenuPopups" -#define SNAPTTOGRID_KEY "SnapTToGrid" -#define FLOATINGZ_KEY "FloatingZ" -#define TARGETFIX_KEY "TargetFix" -#define GLPOINTWORKAROUND_KEY "GlPointWorkaround" // Gef: Workaround for broken Kyro * gl driver 25-aug-2001 -#define WHEELINC_KEY "WheelMouseInc" -#define PATCHBBOXSEL_KEY "PatchBBoxSel" -#define LASTLIGHTINTENSITY_KEY "LastLightIntensity" -#define CUSTOMSHADEREDITOR_KEY "UseCustomShaderEditor" -#define CUSTOMSHADEREDITORCOMMAND_KEY "CustomShaderEditorCommand" -#define TEXTURECOMPRESSIONFORMAT_KEY "TextureCompressionFormat" -#define LIGHTRADIUS_KEY "LightRadiuses" -#define Q3MAP2TEX_KEY "Q3Map2Tex" -#define ATIHACK_KEY "ATIHack" - -// window stuff -#define ENTITYSPLIT1_KEY "EntitySplit1" -#define ENTITYSPLIT2_KEY "EntitySplit2" -#define POSITIONX_KEY "PositionX" -#define POSITIONY_KEY "PositionY" -#define ENTITYWND_KEY "EntityWnd" -#define MAPINFOWND_KEY "MapInfoDlg" -#define CAMWND_KEY "CamWnd" -#define ZWND_KEY "ZWnd" -#define XYWND_KEY "XYWnd" -#define XZWND_KEY "XZWnd" -#define YZWND_KEY "YZWnd" -#define PATCHWND_KEY "PatchWnd" -#define SURFACEWND_KEY "SurfaceWnd" -#define ENTITYINFOWND_KEY "EntityInfoDlg" -#define WIDTH_KEY "Width" -#define HEIGHT_KEY "Height" -#define ZWIDTH_KEY "ZWidth" -#define XYHEIGHT_KEY "XYHeight" -#define XYWIDTH_KEY "XYWidth" -#define CAMWIDTH_KEY "CamWidth" -#define CAMHEIGHT_KEY "CamHeight" -#define ZFLOATWIDTH_KEY "ZWidthFloating" -#define STATE_KEY "State" - -// menu stuff -#define COUNT_KEY "Count" -#define FILE_KEY "File" - -//saved info -#define SI_TEXMENU_KEY "SI_TexMenu" -#define SI_GAMMA_KEY "SI_Gamma" -#define SI_COLORS_KEY "SI_Colors" -#define SI_EXCLUDE_KEY "SI_Exclude" -#define SI_INCLUDE_KEY "SI_Include" -#define SI_SURFACE_TEXDEF_KEY "SI_SurfaceTexdef" -#define SI_PATCH_TEXDEF_KEY "SI_PatchTexdef" -#define SI_AXISCOLORS_KEY "SI_AxisColors" -#define SI_SHOWNAMES_KEY "SI_ShowNames" -#define SI_SHOWCOORDS_KEY "SI_ShowCoords" -#define SI_SHOWANGLES_KEY "SI_ShowAngles" -#define SI_SHOWOUTLINES_KEY "SI_ShowOutlines" -#define SI_SHOWAXIS_KEY "SI_ShowAxis" -#define SI_NOSELOUTLINES_KEY "SI_NoSelectedOutlines" -#define SI_OUTLINESTYLE_KEY "SI_OutLineStyle" - -//for texdefs -#define TD_SCALE1_KEY "_Scale1" -#define TD_SCALE2_KEY "_Scale2" -#define TD_SHIFT1_KEY "_Shift1" -#define TD_SHIFT2_KEY "_Shift2" -#define TD_ROTATE_KEY "_Rotate" - -#define MOUSE_DEF 1 -#define WINDOW_DEF 0 -#define RUNQ2_DEF 0 -#define WATCHBSP_DEF 1 -#define TLOCK_DEF 1 -#define LOADLAST_DEF 1 -#define RUN_DEF 0 -#define SUBDIVISIONS_DEF 4 - -void WindowPosition_Parse(window_position_t& m_value, const CString& value) -{ - if(sscanf(value.GetBuffer(), "%d %d %d %d", &m_value.x, &m_value.y, &m_value.w, &m_value.h) != 4) - m_value.x = m_value.y = m_value.w = m_value.h = -1; -} - -void WindowPosition_Write(const window_position_t& m_value, CString& value) -{ - char buffer[64]; - sprintf(buffer, "%d %d %d %d", m_value.x, m_value.y, m_value.w, m_value.h); - value = buffer; -} - - -CXMLPropertyBag::CXMLPropertyBag() { - mStrFilename = ""; - mpDoc = NULL; - mbEmpty = false; -} - -// generic preference functions - -void CXMLPropertyBag::PushAssignment(char *name, PrefTypes_t type, void *pV) -{ - list::iterator iAssign; - for(iAssign=mPrefAssignments.begin(); iAssign!=mPrefAssignments.end(); iAssign++) - { - if ((*iAssign).mName == name) - { - // we have it already, check anyway - if (pV != (*iAssign).mVal) - { - Sys_FPrintf(SYS_ERR, "PushAssignment, '%s' has different mVal\n", name); - return; - } - } - } - // ok, it's not in our list yet - mPrefAssignments.push_front(CPrefAssignment(name, type, pV)); -} - -xmlNodePtr CXMLPropertyBag::EpairForName(const char *name) -{ - xmlNodePtr ret = NULL; - - xmlNodePtr pNode = mpDocNode->children; - while (pNode != NULL) - { - if(pNode->type == XML_ELEMENT_NODE) - { - xmlAttrPtr tmp_attr_ptr = xmlHasProp(pNode, (xmlChar *)"name"); - if (tmp_attr_ptr != NULL && !strcmp(name, (char *)tmp_attr_ptr->children->content)) - { - if ( ret ) { - Sys_FPrintf( SYS_WRN, "WARNING: dupe property in CXMLPropertyBag::EpairForName '%s'\n", name ); - } else { - ret = pNode; - } - } - } - pNode = pNode->next; - } - return ret; -} - -void CXMLPropertyBag::GetPref(char *name, Str *pV, char *V) -{ - xmlNodePtr pNode = EpairForName( name ); - if ( pNode ) - { - if ( pNode->children && pNode->children->content ) { - *pV = pNode->children->content; - } else { - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=427 - // means the pref exists, and that the value is "" - *pV = ""; - } - } - else - { - pNode = xmlNewChild(mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)V); - xmlSetProp(pNode, (xmlChar *)"name", (xmlChar *)name); - } - // push the pref assignment if needed - PushAssignment(name, PREF_STR, pV); -} - -void CXMLPropertyBag::GetPref(char *name, int *pV, int V) -{ - xmlNodePtr pNode; - if ((pNode = EpairForName(name)) && pNode->children && pNode->children->content) - { - *pV = atoi((char *)pNode->children->content); - } - else - { - char s[10]; - sprintf(s, "%d", V); - pNode = xmlNewChild(mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)s); - xmlSetProp(pNode, (xmlChar *)"name", (xmlChar *)name); - *pV=V; - } - // push the pref assignment if needed - PushAssignment(name, PREF_INT, pV); -} - -void CXMLPropertyBag::GetPref(char *name, bool *pV, bool V) -{ - xmlNodePtr pNode; - if ((pNode = EpairForName(name)) && pNode->children && pNode->children->content) - { - if (!strcmp((char *)pNode->children->content, "true")) - { - *pV = true; - } - else - { - *pV = false; - } - } - else - { - char s[10]; - V ? strcpy(s, "true") : strcpy(s, "false"); - pNode = xmlNewChild(mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)s); - xmlSetProp(pNode, (xmlChar *)"name", (xmlChar *)name); - *pV=V; - } - // push the pref assignment - PushAssignment(name, PREF_BOOL, pV); -} - -void CXMLPropertyBag::GetPref(char *name, float *pV, float V) -{ - xmlNodePtr pNode; - if ((pNode = EpairForName(name)) && pNode->children && pNode->children->content) - { - *pV = atof((char *)pNode->children->content); - } - else - { - char s[10]; - sprintf(s, "%f", V); - pNode = xmlNewChild(mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)s); - xmlSetProp(pNode, (xmlChar *)"name", (xmlChar *)name); - *pV=V; - } - // push the pref assignment if needed - PushAssignment(name, PREF_FLOAT, pV); -} - -void CXMLPropertyBag::GetPref(char *name, float* pV, float* V) -{ - xmlNodePtr pNode; - if ((pNode = EpairForName(name)) && pNode->children && pNode->children->content) - { - sscanf((char *)pNode->children->content, "%f %f %f", &pV[0], &pV[1], &pV[2]); - } - else - { - char s[128]; - sprintf(s, "%f %f %f", V[0], V[1], V[2]); - pNode = xmlNewChild(mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)s); - xmlSetProp(pNode, (xmlChar *)"name", (xmlChar *)name); - pV[0] = V[0]; - pV[1] = V[1]; - pV[2] = V[2]; - } - // push the pref assignment if needed - PushAssignment(name, PREF_VEC3, pV); -} - -void CXMLPropertyBag::GetPref(char *name, window_position_t* pV, window_position_t V) -{ - xmlNodePtr pNode; - if ((pNode = EpairForName(name)) && pNode->children && pNode->children->content) - { - WindowPosition_Parse(*pV, CString((xmlChar *)pNode->children->content)); - } - else - { - CString str; - WindowPosition_Write(V, str); - pNode = xmlNewChild(mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)str.GetBuffer()); - xmlSetProp(pNode, (xmlChar *)"name", (xmlChar *)name); - *pV = V; - } - // push the pref assignment if needed - PushAssignment(name, PREF_WNDPOS, pV); -} - -void CXMLPropertyBag::UpdatePrefTree() -{ - // read the assignments and update the tree - list::iterator iPref; - for(iPref = mPrefAssignments.begin(); iPref != mPrefAssignments.end(); iPref++) - { - CPrefAssignment *pPref = &(*iPref); - // look for the node - xmlNodePtr pNode; - char s[64]; - - pNode = EpairForName(pPref->mName.GetBuffer()); - // we never expect that the node could not be found, because this is supposed to happen - // after the tree was built with GetPref calls, never on a blank tree - if (!pNode) - { - Sys_FPrintf(SYS_ERR, "Unexpected EpairForName '%s' not found in UpdatePrefTree\n", pPref->mName.GetBuffer()); - return; - } - switch ((*iPref).mType) - { - case PREF_STR: - xmlNodeSetContent(pNode, (const xmlChar *)((Str *)pPref->mVal)->GetBuffer()); - break; - case PREF_INT: - sprintf(s, "%d", *(int *)pPref->mVal); - xmlNodeSetContent(pNode, (xmlChar *)s); - break; - case PREF_FLOAT: - sprintf(s, "%f", *(float *)pPref->mVal); - xmlNodeSetContent(pNode, (xmlChar *)s); - break; - case PREF_BOOL: - *(bool *)pPref->mVal ? strcpy(s, "true") : strcpy(s, "false"); - xmlNodeSetContent(pNode, (xmlChar *)s); - break; - case PREF_VEC3: - { - float* v = (float*)pPref->mVal; - sprintf(s, "%f %f %f", v[0], v[1], v[2]); - xmlNodeSetContent(pNode, (xmlChar *)s); - } - break; - case PREF_WNDPOS: - { - CString str; - WindowPosition_Write(*(window_position_t*)pPref->mVal, str); - xmlNodeSetContent(pNode, (xmlChar*)str.GetBuffer()); - } - break; - } - } -} - -void CXMLPropertyBag::Clear() -{ - if(!InUse()) - return; - - xmlFreeDoc(mpDoc); - mpDoc = NULL; - mpDocNode = NULL; - mbEmpty = false; -} - -void CXMLPropertyBag::ReadXMLFile(const char* pFilename) -{ - mpDoc = xmlParseFile(pFilename); - - // basic checks - if (mpDoc) - { - mpDocNode = mpDoc->children; - xmlAttrPtr tmp_attr_ptr = xmlHasProp(mpDocNode, (xmlChar *)"version"); - if (strcmp((char *)mpDocNode->name, "qpref")) - { - Sys_FPrintf(SYS_ERR, "Unrecognized node '%s' in '%s'\n", mpDocNode->name, mpDoc->URL); - xmlFreeDoc(mpDoc); - mpDoc = NULL; - } - else if (tmp_attr_ptr != NULL && strcmp((char*)tmp_attr_ptr->children->content, "1")) - { - Sys_FPrintf(SYS_ERR, "Wrong version '%s' in node for '%s'\n", (char*)tmp_attr_ptr->children->content, mpDoc->URL); - xmlFreeDoc(mpDoc); - mpDoc = NULL; - } - Sys_Printf("Opened XML property file: '%s'\n", pFilename); - } - - if (!mpDoc) - { - mbEmpty = true; - // no document, create one - mpDoc = xmlNewDoc((xmlChar *)"1.0"); - mpDocNode = xmlNewDocNode(mpDoc, NULL, (xmlChar *)"qpref", NULL); - xmlDocSetRootElement(mpDoc, mpDocNode); - xmlSetProp(mpDocNode, (xmlChar *)"version", (xmlChar *)"1"); - Sys_Printf("XML property file '%s' invalid/not found, creating blank properties tree\n", pFilename); - } -} - -qboolean CXMLPropertyBag::WriteXMLFile(const char* pFilename) -{ - int res = xmlSaveFormatFile(pFilename, mpDoc, 1); - - if(res == -1) - return false; - - Sys_Printf("Wrote XML property file '%s'\n", pFilename); - return true; -} - -// ============================================================================= -// Widget callbacks for PrefsDlg - -#if !defined(WIN32) -// browse for custom editor executable -static void OnBtnBrowseEditor (GtkWidget *widget, gpointer data) -{ - PrefsDlg *dlg = (PrefsDlg*)data; - - const char *filename = file_dialog(g_PrefsDlg.GetWidget(), TRUE, "Executable for Custom Editor"); - - if(filename != NULL) - { - dlg->m_strEditorCommand = filename; - dlg->UpdateData(FALSE); - } -} -#endif - -static void OnBtnBrowseprefab (GtkWidget *widget, gpointer data) -{ - PrefsDlg *dlg = (PrefsDlg*)data; - char *path = dlg->m_strPrefabPath; - if (strlen (path) == 0) - path = g_strGameToolsPath; - char *dir = dir_dialog (g_PrefsDlg.GetWidget (), "Set prefab path", path); - dlg->UpdateData(TRUE); - - if (dir != NULL) - { - CString strPath; - strPath = dir; - AddSlash(strPath); - dlg->m_strPrefabPath = strPath; - dlg->UpdateData(FALSE); - free (dir); - } -} - -static void OnBtnBrowseuserini (GtkWidget *widget, gpointer data) -{ - PrefsDlg *dlg = (PrefsDlg*)data; - char *path = dlg->m_strUserPath; - if (strlen (path) == 0) - path = g_strGameToolsPath; - // TODO: INI filter? - const char *filename = file_dialog (g_PrefsDlg.GetWidget(), TRUE, "Find INI file", path); - - if (filename != NULL) - { - dlg->UpdateData(TRUE); - dlg->m_strUserPath = filename; - dlg->UpdateData(FALSE); - } -} - -static void OnButtonClean (GtkWidget *widget, gpointer data) -{ - // make sure this is what the user wants - if (gtk_MessageBox (g_PrefsDlg.GetWidget (), "This will close Radiant and clean the corresponding registry entries.\n" - "Next time you start Radiant it will be good as new. Do you wish to continue?", - "Reset Registry", MB_YESNO) == IDYES) - { - PrefsDlg *dlg = (PrefsDlg*)data; - dlg->EndModal (IDCANCEL); - - g_qeglobals.disable_ini = true; - remove (dlg->m_inipath->str); - char buf[PATH_MAX]; - sprintf(buf, "%sSavedInfo.bin", dlg->m_rc_path->str); - remove(buf); - HandleCommand (NULL, GINT_TO_POINTER (ID_FILE_EXIT)); - _exit (0); - } -} - -// ============================================================================= -// PrefsDlg class - -// IMPORTANT NOTE: the values here don't matter very much -// the actual intialization if you start with an empty .ini is done when loading the prefs for the first time -// profile_load_int takes an argument to use if the value is not found -PrefsDlg::PrefsDlg () -{ - m_bWarn = TRUE; - m_nMouse = 1; - m_nView = MainFrame::eRegular; - m_bLoadLast = FALSE; - m_bInternalBSP = FALSE; - m_bRightClick = FALSE; - m_bSetGame = FALSE; - m_bAutoSave = TRUE; - m_nAutoSave = 5; - m_bLoadLastMap = FALSE; - m_bTextureWindow = FALSE; - m_bSnapShots = FALSE; - m_fTinySize = 0.5; - m_bCleanTiny = FALSE; - m_bCamXYUpdate = TRUE; - m_bCamDragMultiSelect = FALSE; - m_bCamFreeLook = TRUE; - m_bCamFreeLookStrafe = FALSE; - m_bCamInverseMouse = FALSE; - m_bCamDiscrete = TRUE; - m_bNewLightDraw = FALSE; - m_strPrefabPath = ""; - m_nWhatGame = 0; - m_bALTEdge = FALSE; - m_bFaceColors = FALSE; - m_bXZVis = FALSE; - m_bYZVis = FALSE; - m_bZVis = FALSE; - m_bSizePaint = FALSE; - m_bDLLEntities = FALSE; -#ifdef _WIN32 - m_bDetachableMenus = FALSE; // Most win32 users will find detachable menus annoying -#else - m_bDetachableMenus = TRUE; // Linux/Apple users are used to them... -#endif - m_bPatchToolbar = TRUE; - m_bWideToolbar = TRUE; - m_bPluginToolbar = TRUE; - m_bNoClamp = FALSE; - m_strUserPath = ""; - m_nRotation = 0; - m_bChaseMouse = FALSE; - m_bTextureScrollbar = TRUE; - m_bDisplayLists = TRUE; - m_bAntialiasedPointsAndLines = FALSE; // Fishman - Add antialiazed points and lines support. 09/03/00 - m_bShowShaders = FALSE; - m_nShader = -1; - m_bNoStipple = FALSE; - m_bVertexSplit = FALSE; - m_bSelectCurves = TRUE; - m_bSelectModels = TRUE; - m_nEntityShowState = ENTITY_SKINNED_BOXED; - m_nTextureScale = 2; - m_bSwitchClip = FALSE; - m_bSelectWholeEntities = TRUE; - m_nTextureQuality = 3; - m_bShowShaders = TRUE; - m_bGLLighting = FALSE; - m_nShader = 0; - m_nUndoLevels = 30; - m_bTexturesShaderlistOnly = FALSE; - // paths to ini files - m_rc_path = NULL; - m_inipath = NULL; - m_bWatchBSP = TRUE; - m_bLeakStop = TRUE; - m_iTimeout = 15; - m_bRunQuake = TRUE; - m_bDoSleep = FALSE; - m_nSubdivisions = 4; - // not prefs - m_bFloatingZ = FALSE; - m_bGlPtWorkaround = FALSE; // Gef: Kyro/GL_POINTS workaround 25-aug-2001 -#ifdef _WIN32 - m_bNativeGUI = FALSE; - m_bStartOnPrimMon = FALSE; -#endif - m_global_rc_path = NULL; -#ifdef _WIN32 - m_bUseWin32Editor = TRUE; -#else - // custom shader editor options - m_bUseCustomEditor = FALSE; - m_strEditorCommand = ""; -#endif - m_nLightRadiuses = 1; - m_bQ3Map2Texturing = TRUE; -#ifdef ATIHACK_812 - m_bGlATIHack = FALSE; -#endif -} - -/*! -========================================================= -Games selection dialog -========================================================= -*/ - -CGameDescription::CGameDescription(xmlDocPtr pDoc, const Str &GameFile) -{ - char *p, *prop; - mpDoc = pDoc; - // read the user-friendly game name - xmlNodePtr pNode = mpDoc->children; - - while (strcmp((const char*)pNode->name, "game") && pNode != NULL) pNode=pNode->next; - if (!pNode) - { - ///< \todo add the file name (this node and gametools should all be part of CGameDescription anyway) - Error("Didn't find 'game' node in the game description file '%s'\n", pDoc->URL); - } - // on win32, game tools path can now be specified relative to the exe's cwd - prop = (char*)xmlGetProp( pNode, (xmlChar*)"gametools" ); - if ( prop == NULL ) { - Error( "Didn't find 'gametools' node in the game description file '%s'\n", pDoc->URL ); - } - { - char full[PATH_MAX]; -#ifdef _WIN32 - _fullpath( full, prop, PATH_MAX ); -#else - strncpy( full, prop, PATH_MAX ); -#endif - xmlFree( prop ); - prop = NULL; - for ( p = full; *p != '\0'; p++ ) { - if ( *p == '\\' ) { - *p = '/'; - } - mGameToolsPath = full; - if ( p != full && *(p-1) != '/' ) { - mGameToolsPath += "/"; - } - } - } - - prop = (char*)xmlGetProp(pNode, (xmlChar*)"name"); - if (prop == NULL) - { - Sys_FPrintf(SYS_WRN, "Warning, 'name' attribute not found in '%s'\n", pDoc->URL); - mGameName = pDoc->URL; - } - else - { - mGameName = prop; - xmlFree(prop); - } - - mGameFile = GameFile; - - prop = (char*)xmlGetProp(pNode, (xmlChar*)"basegame"); - if (prop == NULL) - { - // default - mBaseGame = "baseq3"; - } - else - { - mBaseGame = prop; - xmlFree(prop); - } - - // on win32, engine path can now be specified relative to the exe's cwd - prop = (char*)xmlGetProp(pNode, (const xmlChar *)"enginepath"); - if ( prop != NULL ) { - char full[PATH_MAX]; -#ifdef _WIN32 - _fullpath( full, prop, PATH_MAX ); -#else - strncpy( full, prop, PATH_MAX ); -#endif - xmlFree( prop ); - prop = NULL; - // process seperators - for ( p = full; *p != '\0'; p++ ) { - if ( *p == '\\' ) { - *p = '/'; - } - } - mEnginePath = full; - if ( p != full && *(p-1) != '/' ) { - mEnginePath += "/"; - } - } - else - { - // if engine path was not specified in the .game, it implies we can guess it from the gametools path - // on win32, and for most game package, the gametools are installed with the game - char aux_path[PATH_MAX]; // aux - strcpy( aux_path, mGameToolsPath.GetBuffer() ); - if ( ( aux_path[ strlen(aux_path)-1 ] == '/' ) || ( aux_path[ strlen(aux_path)-1 ] == '\\' ) ) { - aux_path[strlen(aux_path)-1] = '\0'; // strip ending '/' if any - } - char up_path[PATH_MAX]; // up one level - ExtractFilePath( aux_path, up_path ); - mEnginePath = up_path; - } - - prop = (char*)xmlGetProp(pNode, (xmlChar*)"engine"); - if (prop == NULL) - { -#ifdef _WIN32 - mEngine = "quake3.exe"; -#elif __linux__ - mEngine = "quake3"; -#elif __APPLE__ - mEngine = "Quake3.app"; -#endif - } - else - { - mEngine = prop; - xmlFree(prop); - } - -#if defined (__linux__) || defined (__APPLE__) - // *nix specific - prop = (char*)xmlGetProp(pNode, (const xmlChar *)"prefix"); - if(prop != NULL) - { - mUserPathPrefix = prop; - xmlFree(prop); - } -#endif - mShaderPath = xmlGetProp(pNode, (const xmlChar *)"shaderpath"); - if (!mShaderPath.GetLength()) - { - mShaderPath = "scripts/"; - mShaderlist = "scripts/shaderlist.txt"; - } - else - { - AddSlash(mShaderPath); - mShaderlist = mShaderPath; - mShaderlist += "shaderlist.txt"; - } - xmlChar* default_scale = xmlGetProp(pNode, (const xmlChar *)"default_scale"); - if (default_scale) - { - mTextureDefaultScale = atof((const char *)default_scale); - xmlFree(default_scale); - } - else - mTextureDefaultScale = 0.5f; - xmlChar* eclass_singleload = xmlGetProp(pNode, (const xmlChar*)"eclass_singleload"); - if (eclass_singleload) - { - mEClassSingleLoad = true; - xmlFree(eclass_singleload); - } - else - mEClassSingleLoad = false; - xmlChar* no_patch = xmlGetProp(pNode, (const xmlChar *)"no_patch"); - if (no_patch) - { - mNoPatch = true; - xmlFree(no_patch); - } - else - mNoPatch = false; - xmlChar* caulk_shader = xmlGetProp(pNode, (const xmlChar *)"caulk_shader"); - if (caulk_shader) - { - mCaulkShader = caulk_shader; - xmlFree(caulk_shader); - } - else - mCaulkShader = "textures/common/caulk"; -} - -void CGameDescription::Dump() -{ -#ifdef _WIN32 - if (CGameDialog::GetNetrun()) - Sys_Printf("Running in network mode, prefs path set to '%s'\n", g_strTempPath.GetBuffer()); -#endif - Sys_Printf("game name : '%s'\n", mGameName.GetBuffer()); - Sys_Printf("game file : '%s'\n", mGameFile.GetBuffer()); - Sys_Printf("game path : '%s'\n", mGameToolsPath.GetBuffer()); - Sys_Printf("base game : '%s'\n", mBaseGame.GetBuffer()); - Sys_Printf("engine path : '%s'\n", mEnginePath.GetBuffer()); - Sys_Printf("engine : '%s'\n", mEngine.GetBuffer()); - Sys_Printf("shaderlist : '%s'\n", mShaderlist.GetBuffer()); - Sys_Printf("caulk shader: '%s'\n", mCaulkShader.GetBuffer()); -#if defined (__linux__) || defined (__APPLE__) - Sys_Printf("prefix : '%s'\n", mUserPathPrefix.GetBuffer()); -#endif - Sys_Printf("default texture scale: %g\n", mTextureDefaultScale); - Sys_Printf("single eclass load : %s\n", mEClassSingleLoad ? "Yes" : "No"); - Sys_Printf("patches supported : %s\n", mNoPatch ? "No" : "Yes"); -} - -CPrefAssignment& CPrefAssignment::operator = (const CPrefAssignment& ass) -{ - if (&ass != this) - { - mName = ass.mName; - mType = ass.mType; - mVal = ass.mVal; - } - return *this; -} - -CPrefAssignment::CPrefAssignment(const CPrefAssignment& ass) -{ - *this = ass; -} - -void CGameDialog::LoadPrefs() -{ - bool bEmpty = false; - - // if we already have a document loaded, we will free and reload from file - if (mGlobalPrefs.InUse()) - { - Sys_Printf("Reloading global prefs from file\n"); - mGlobalPrefs.Clear(); - } - - // load global .pref file - CString strGlobalPref = g_PrefsDlg.m_global_rc_path->str; - strGlobalPref += "global.pref"; - - mGlobalPrefs.ReadXMLFile(strGlobalPref.GetBuffer()); - - mGlobalPrefs.GetPref("gamefile", &m_sGameFile, ""); // NOTE: there's no default, user HAS to select something - mGlobalPrefs.GetPref("autoload", &m_bAutoLoadGame, false); - mGlobalPrefs.GetPref("log console", &m_bLogConsole, false); - // in a very particular post-.pid startup - // we may have the console turned on and want to keep it that way - // so we use a latching system - if (m_bForceLogConsole) - { - m_bLogConsole = true; - Sys_Printf("console logging has been latched on, saving prefs\n"); - SavePrefs(); - m_bForceLogConsole = false; - } - - // console logging: call Sys_LogConsole to check console logging status - // it is important that we would log console as early as possible to make it useful - Sys_LogFile(); - - if (mGlobalPrefs.mbEmpty) - { - Sys_Printf("Saving global.pref with default pref values\n"); - SavePrefs(); - } -} - -void CGameDialog::SavePrefs() -{ - // update the tree and save it - mGlobalPrefs.UpdatePrefTree(); - - CString strGlobalPref = g_PrefsDlg.m_global_rc_path->str; - strGlobalPref += "global.pref"; - - if (!mGlobalPrefs.WriteXMLFile(strGlobalPref.GetBuffer())) - Sys_FPrintf(SYS_ERR, "Error occured while saving global prefs file '%s'\n", strGlobalPref.GetBuffer()); -} - -void CGameDialog::DoGameDialog() -{ - // show the UI - DoModal(); - - // unhook so we can use in other places - // we manually incref'ed it when creating, it won't be freed (destructor) - gtk_container_remove (GTK_CONTAINER (mTopBox), GetGlobalFrame()); - - // we save the prefs file - SavePrefs(); -} - -GtkWidget* CGameDialog::GetGlobalFrame() -{ - GtkWidget *vbox, *text, *combo, *check; - - if (mFrame) - return mFrame; - - mFrame = gtk_frame_new(NULL); - gtk_container_set_border_width(GTK_CONTAINER(mFrame), 5); - gtk_widget_show(mFrame); - - vbox = gtk_vbox_new (FALSE, 6); - gtk_widget_show (vbox); - gtk_container_add (GTK_CONTAINER (mFrame), vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - - text = gtk_label_new("Select the game:"); - gtk_widget_show(text); - gtk_box_pack_start (GTK_BOX(vbox), text, FALSE, FALSE, 0); - - combo = gtk_combo_new(); - gtk_widget_show(combo); - gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0); - - // fill in with the game descriptions - GList *combo_list = (GList*)NULL; - list::iterator iGame; - for(iGame=mGames.begin(); iGame!=mGames.end(); iGame++) - { - combo_list = g_list_append (combo_list, (void *)(*iGame)->mGameName.GetBuffer()); - } - gtk_combo_set_popdown_strings (GTK_COMBO (combo), combo_list); - g_list_free (combo_list); - - AddDialogData (combo, &m_nComboSelect, DLG_COMBO_INT); - - check = gtk_check_button_new_with_label("Auto load selected game on startup"); - gtk_widget_show(check); - gtk_box_pack_start (GTK_BOX(vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bAutoLoadGame, DLG_CHECK_BOOL); - - text = gtk_label_new("(this frame is available in the prefs menu if you set auto-select)"); - gtk_widget_show(text); - gtk_box_pack_start (GTK_BOX(vbox), text, FALSE, FALSE, 0); - -#ifdef _WIN32 - check = gtk_check_button_new_with_label("Networked install - per-user settings"); - gtk_widget_show(check); - gtk_box_pack_start (GTK_BOX(vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bNetRun, DLG_CHECK_BOOL); -#endif - - check = gtk_check_button_new_with_label("Log the console to radiant.log"); - gtk_widget_show(check); - gtk_box_pack_start (GTK_BOX(vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bLogConsole, DLG_CHECK_BOOL); - - // incref it so we can pass it around - gtk_widget_ref (GTK_WIDGET(mFrame)); - - return mFrame; -} - -void CGameDialog::UpdateData (bool retrieve) -{ - if (!retrieve) - { - // use m_sGameFile to set m_nComboSelect - list::iterator iGame; - int i = 0; - for(iGame=mGames.begin(); iGame!=mGames.end(); iGame++) - { - if ((*iGame)->mGameFile == m_sGameFile) - { - m_nComboSelect = i; - break; - } - i++; - } -#ifdef _WIN32 - UpdateNetrun(false); -#endif - } - Dialog::UpdateData(retrieve); - if (retrieve) - { - // use m_nComboSelect to set m_sGameFile - list::iterator iGame = mGames.begin(); - int i; - for(i=0; imGameFile; -#ifdef _WIN32 - UpdateNetrun(true); -#endif - } -} - -void CGameDialog::BuildDialog() -{ - GtkWidget *dlg, *vbox1, *button; - - dlg = m_pWidget; - gtk_window_set_title (GTK_WINDOW (dlg), "Select Game"); - - vbox1 = gtk_vbox_new (FALSE, 0); - gtk_widget_show(vbox1); - gtk_container_add (GTK_CONTAINER (dlg), vbox1); - - gtk_container_add (GTK_CONTAINER (vbox1), GetGlobalFrame()); - mTopBox = vbox1; - - button = gtk_button_new_with_label ("OK"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (vbox1), button, FALSE, FALSE, 0); - AddModalButton(button, IDOK); - gtk_widget_set_usize (button, 60, -2); -} - -void CGameDialog::ScanForGames() -{ - CString strPath; - char *dirlist; - GDir *dir; - CString strGamesPath = g_strAppPath.GetBuffer(); - strGamesPath += "games"; - const char *path = strGamesPath.GetBuffer(); - - Sys_Printf("Scanning for game description files: %s\n", path); - - /*! - \todo FIXME LINUX: - do we put game description files below g_strAppPath, or in ~/.radiant - i.e. read only or read/write? - my guess .. readonly cause it's an install - we will probably want to add ~/.radiant//games/ scanning on top of that for developers - (if that's really needed) - */ - - // FIXME need to catch the 'no game description' situation and exit with a clean error - - dir = g_dir_open(path, 0, NULL); - - if (dir != NULL) - { - while (1) - { - const gchar* name = g_dir_read_name(dir); - if(name == NULL) - break; - - dirlist = g_strdup(name); -#ifdef _WIN32 - strlwr (dirlist); -#endif - char *ext = strrchr (dirlist, '.'); - if ((ext == NULL) || (strcmp (ext, ".game") != 0)) - continue; - strPath.Format("%s/%s", path, dirlist); - Sys_Printf("%s\n", strPath.GetBuffer()); - // got one, load it - xmlDocPtr pDoc = xmlParseFile(strPath.GetBuffer()); - if (pDoc) - { - mGames.push_front(new CGameDescription(pDoc, dirlist)); - } - else - { - Sys_FPrintf(SYS_ERR, "XML parser failed on '%s'\n", strPath.GetBuffer()); - } - - g_free(dirlist); - } - g_dir_close (dir); - } -} - -CGameDescription* CGameDialog::GameDescriptionForComboItem() -{ - list::iterator iGame; - int i=0; - for(iGame=mGames.begin(); iGame!=mGames.end(); iGame++,i++) - { - if (i == m_nComboSelect) - { - return (*iGame); - } - } - return NULL; // not found -} - -/*GString* CGameDialog::InitGlobalPrefPath() -{ - GString* global_rc_path; - // configure m_global_rc_path -#if defined (__linux__) || defined (__APPLE__) - global_rc_path = g_string_new (g_get_home_dir ()); - - if (global_rc_path->str[global_rc_path->len-1] != '/') - g_string_append (global_rc_path, "/"); - - g_string_append (global_rc_path, ".radiant/"); - mkdir (global_rc_path->str, 0775); - g_string_append (global_rc_path, RADIANT_VERSION); - g_string_append (global_rc_path, "/"); - mkdir (global_rc_path->str, 0775); -#elif WIN32 - global_rc_path = g_string_new (g_strAppPath.GetBuffer() ); -#else -#error "WTF are you compiling under" -#endif - return global_rc_path; -}*/ - -void CGameDialog::InitGlobalPrefPath() -{ - GString *global_rc_path; - // configure m_global_rc_path - // this is the g_strTempPath, and it has already been mkdir'ed - global_rc_path = g_string_new(g_strTempPath.GetBuffer()); - g_PrefsDlg.m_global_rc_path = global_rc_path; -} - -void CGameDialog::Reset() -{ - if (!g_PrefsDlg.m_global_rc_path) - InitGlobalPrefPath(); - CString strGlobalPref = g_PrefsDlg.m_global_rc_path->str; - strGlobalPref += "global.pref"; - remove(strGlobalPref.GetBuffer()); -} - -void CGameDialog::Init() -{ - InitGlobalPrefPath(); - ScanForGames(); - if (mGames.empty()) - { - Error("Didn't find any valid game file descriptions, aborting\n"); - } - LoadPrefs(); - if (m_bAutoLoadGame) - { - // search by .game name - list::iterator iGame; - for(iGame=mGames.begin(); iGame!=mGames.end(); iGame++) - { - if ((*iGame)->mGameFile == m_sGameFile) - { - m_pCurrentGameDescription = (*iGame); - break; - } - } - } - if (!m_bAutoLoadGame || !m_pCurrentGameDescription) - { - DoGameDialog(); - // use m_nComboSelect to identify the game to run as and set the globals - m_pCurrentGameDescription = GameDescriptionForComboItem(); - if (!m_pCurrentGameDescription) - Error("Lookup of game description object failed, can't continue\n"); - } - g_pGameDescription = m_pCurrentGameDescription; - - g_strGameToolsPath = g_pGameDescription->mGameToolsPath; - - // NOTE TTimo: this is moved from QE_LoadProject in 1.2 - // (probably broken) - // NOTE Hydra: was broken for win32, we don't use m_strHomeGame or m_strFSBasePath -#if defined (__linux__) || defined (__APPLE__) - g_qeglobals.m_strHomeGame = g_get_home_dir(); - g_qeglobals.m_strHomeGame += "/"; - g_qeglobals.m_strHomeGame += m_pCurrentGameDescription->mUserPathPrefix.GetBuffer(); - g_qeglobals.m_strHomeGame += "/"; -#else - g_qeglobals.m_strHomeGame = g_pGameDescription->mEnginePath.GetBuffer(); -#endif - - g_pGameDescription->Dump(); -} - -CGameDialog::~CGameDialog() -{ - if (mFrame) - { - // NOTE I'm not too sure how reliable this is - gtk_widget_unref(GTK_WIDGET(mFrame)); - } - // free all the game descriptions - list::iterator iGame; - for(iGame=mGames.begin(); iGame!=mGames.end(); iGame++) - { - delete (*iGame); - *iGame = NULL; - } -} - -void CGameDialog::AddPacksURL(Str &URL) -{ - // add the URLs for the list of game packs installed - // FIXME: this is kinda hardcoded for now.. - list::iterator iGame; - for(iGame=mGames.begin(); iGame!=mGames.end(); iGame++) - { - if ((*iGame)->mGameFile == "q3.game") - URL += "&Games_dlup%5B%5D=1"; - else if ((*iGame)->mGameFile == "wolf.game") - URL += "&Games_dlup%5B%5D=2"; - else if ((*iGame)->mGameFile == "wolf.game") - URL += "&Games_dlup%5B%5D=3"; - else if ((*iGame)->mGameFile == "jk2.game") - URL += "&Games_dlup%5B%5D=4"; - else if ((*iGame)->mGameFile == "stvef.game") - URL += "&Games_dlup%5B%5D=5"; - else if ((*iGame)->mGameFile == "sof2.game") - URL += "&Games_dlup%5B%5D=6"; - else if ((*iGame)->mGameFile == "ja.game") - URL += "&Games_dlup%5B%5D=7"; - } -} - -#ifdef _WIN32 - -#define NETRUN_FILENAME "netrun.conf" - -bool CGameDialog::m_bNetRun; - -void CGameDialog::UpdateNetrun(bool retrieve) -{ - FILE *f_netrun; - CString strNetrun; - strNetrun = g_strAppPath; strNetrun += NETRUN_FILENAME; - if (!retrieve) - { - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=639 - // now check if we are running from a network installation - // use a dummy file as the flag - f_netrun = fopen(strNetrun.GetBuffer(), "r"); - if (f_netrun) - { - fclose(f_netrun); - m_bNetRun = true; - } - else - m_bNetRun = false; - } - else - { - if (m_bNetRun) - { - f_netrun = fopen(strNetrun.GetBuffer(), "w"); - if (!f_netrun) - { - Sys_FPrintf(SYS_ERR, "ERROR: Failed to create netrun file '%s'\n", strNetrun.GetBuffer()); - m_bNetRun = false; - } - else - { - fclose(f_netrun); - Sys_Printf("Created/Checked '%s'\n", strNetrun.GetBuffer()); - } - } - else - { - if (remove(strNetrun.GetBuffer()) == -1) - { - if (errno != ENOENT) - Sys_FPrintf(SYS_ERR, "Failed to remove netrun file '%s'\n", strNetrun.GetBuffer()); - m_bNetRun = true; - } - else - { - Sys_Printf("Netrun mode is disabled\n"); - } - } - } -} - -bool CGameDialog::GetNetrun() -{ - return m_bNetRun; -} -#endif - -/* -======== - -very first prefs init deals with selecting the game and the game tools path -then we can load .ini stuff - -using prefs / ini settings: -those are per-game - -win32: -look in g_strGameToolsPath for .ini - -linux: -look in ~/.radiant//gamename -======== -*/ - -#define PREFS_LOCAL_FILENAME "local.pref" - -void PrefsDlg::Init() -{ - mGamesDialog.Init(); - - // m_global_rc_path has been set above, do m_rc_path with game specific stuff now - // the win32 and linux versions have been unified for network mode -#ifdef _WIN32 - if (!CGameDialog::GetNetrun()) - { - // legacy prefs settings, this goes where the game pack is installed - m_rc_path = g_string_new (g_strGameToolsPath.GetBuffer() ); - m_inipath = g_string_new (m_rc_path->str); - g_string_append (m_inipath, PREFS_LOCAL_FILENAME); - return; - } -#endif - // this is common to win32 and Linux init now - m_rc_path = g_string_new (m_global_rc_path->str); - - // game sub-dir - g_string_append (m_rc_path, g_pGameDescription->mGameFile.GetBuffer()); - g_string_append (m_rc_path, "/"); - Q_mkdir (m_rc_path->str, 0775); - - // then the ini file - m_inipath = g_string_new (m_rc_path->str); - g_string_append (m_inipath, PREFS_LOCAL_FILENAME); - -} - -void PrefsDlg::UpdateData (bool retrieve) -{ - // leo: the "changed" signal confuses the update function - if (m_pWidget == NULL) - return; - mGamesDialog.UpdateData (retrieve); - Dialog::UpdateData (retrieve); -} - -#ifdef _WIN32 -#define PREFSHSPACE 5 -#else -#define PREFSHSPACE 0 -#endif - -static void UpdateSensitivity( GtkWidget *widget, gpointer data ) -{ - PrefsDlg *dlg = (PrefsDlg*)data; - dlg->DoSensitivity(); -} - -static void UpdateEditorSensitivity(GtkWidget *widget, gpointer data) -{ - PrefsDlg *dlg = (PrefsDlg*)data; - dlg->DoEditorSensitivity(); -} - -// start new prefs dialog - -/*! Utility function for swapping notebook pages for tree list selections */ -void PrefsDlg::showPrefPage(int prefpage) -{ - if(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)) != prefpage) - gtk_notebook_set_page(GTK_NOTEBOOK(notebook), prefpage); - - return; -} - -static void treeSelection(GtkTreeSelection* selection, gpointer data) -{ - PrefsDlg *dlg = (PrefsDlg*)data; - - GtkTreeModel* model; - GtkTreeIter selected; - if(gtk_tree_selection_get_selected(selection, &model, &selected)) - { - int prefpage; - gtk_tree_model_get(model, &selected, 1, (gpointer*)&prefpage, -1); - dlg->showPrefPage(prefpage); - } -} - -void PrefsDlg::BuildDialog () -{ - // Main Preferences dialog - GtkWidget *dialog, *mainvbox, *hbox, *sc_win, *preflabel; - - // Widgets on notebook pages - GtkWidget *check, *label, *scale, *hbox2, *combo, - *table, *spin, *entry, *pixmap, - *radio, *button, *pageframe, *vbox; - - GList *combo_list = (GList*)NULL; - - GtkObject *adj; - - dialog = m_pWidget; - gtk_window_set_title(GTK_WINDOW(dialog), "GtkRadiant Preferences"); - gtk_widget_realize(dialog); - - mainvbox = gtk_vbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(dialog), mainvbox); - gtk_container_set_border_width(GTK_CONTAINER(mainvbox), 5); - gtk_widget_show(mainvbox); - - hbox = gtk_hbox_new(FALSE, 5); - gtk_widget_show(hbox); - gtk_box_pack_end(GTK_BOX(mainvbox), hbox, FALSE, TRUE, 0); - - button = gtk_button_new_with_label("OK"); - gtk_widget_show(button); - gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0); - gtk_widget_set_usize(button, 60, -2); - AddModalButton(button, IDOK); - - button = gtk_button_new_with_label("Cancel"); - gtk_widget_show(button); - gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0); - gtk_widget_set_usize(button, 60, -2); - AddModalButton (button, IDCANCEL); - - button = gtk_button_new_with_label ("Clean"); - gtk_widget_show(button); - gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(OnButtonClean), this); - gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); - gtk_widget_set_usize (button, 60, -2); - - hbox = gtk_hbox_new(FALSE, 5); - gtk_box_pack_start(GTK_BOX(mainvbox), hbox, TRUE, TRUE, 0); - gtk_widget_show(hbox); - - sc_win = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sc_win), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_box_pack_start(GTK_BOX(hbox), sc_win, FALSE, FALSE, 0); - gtk_widget_show(sc_win); - - // prefs pages notebook - notebook = gtk_notebook_new(); - // hide the notebook tabs since its not supposed to look like a notebook - gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE); - gtk_box_pack_start(GTK_BOX(hbox), notebook, TRUE, TRUE, 0); - gtk_widget_show(notebook); - - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sc_win), GTK_SHADOW_IN); - - { - GtkTreeStore* store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER); - - GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); - - { - GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); - GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Preferences", renderer, "text", 0, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); - } - - { - GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); - g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(treeSelection), this); - } - - gtk_widget_show(view); - - gtk_container_add(GTK_CONTAINER (sc_win), view); - - { - /********************************************************************/ - /* Add preference tree options */ - /********************************************************************/ - { - GtkTreeIter group; - gtk_tree_store_append(store, &group, NULL); - gtk_tree_store_set(store, &group, 0, "Globals", 1, PTAB_FRONT, -1); - { - GtkTreeIter tab; - gtk_tree_store_append(store, &tab, &group); - gtk_tree_store_set(store, &tab, 0, "Game settings", 1, (gpointer)PTAB_GAME_SETTINGS, -1); - } - } - - { - GtkTreeIter group; - gtk_tree_store_append(store, &group, NULL); - gtk_tree_store_set(store, &group, 0, "Display", 1, PTAB_FRONT, -1); - { - GtkTreeIter tab; - gtk_tree_store_append(store, &tab, &group); - gtk_tree_store_set(store, &tab, 0, "2D Display/Rendering", 1, (gpointer)PTAB_2D, -1); - } - { - GtkTreeIter tab; - gtk_tree_store_append(store, &tab, &group); - gtk_tree_store_set(store, &tab, 0, "3D View", 1, (gpointer)PTAB_CAMERA, -1); - } - { - GtkTreeIter tab; - gtk_tree_store_append(store, &tab, &group); - gtk_tree_store_set(store, &tab, 0, "Texture Settings", 1, (gpointer)PTAB_TEXTURE, -1); - } - } - - { - GtkTreeIter group; - gtk_tree_store_append(store, &group, NULL); - gtk_tree_store_set(store, &group, 0, "Interface", 1, PTAB_FRONT, -1); - { - GtkTreeIter tab; - gtk_tree_store_append(store, &tab, &group); - gtk_tree_store_set(store, &tab, 0, "Layout", 1, (gpointer)PTAB_LAYOUT, -1); - } - { - GtkTreeIter tab; - gtk_tree_store_append(store, &tab, &group); - gtk_tree_store_set(store, &tab, 0, "Mouse", 1, (gpointer)PTAB_MOUSE, -1); - } - { - GtkTreeIter tab; - gtk_tree_store_append(store, &tab, &group); - gtk_tree_store_set(store, &tab, 0, "Editing", 1, (gpointer)PTAB_EDITING, -1); - } - } - - { - GtkTreeIter group; - gtk_tree_store_append(store, &group, NULL); - gtk_tree_store_set(store, &group, 0, "Other", 1, PTAB_FRONT, -1); - { - GtkTreeIter tab; - gtk_tree_store_append(store, &tab, &group); - gtk_tree_store_set(store, &tab, 0, "Startup/Auto save", 1, (gpointer)PTAB_STARTUP, -1); - } - { - GtkTreeIter tab; - gtk_tree_store_append(store, &tab, &group); - gtk_tree_store_set(store, &tab, 0, "Paths", 1, (gpointer)PTAB_PATHS, -1); - } - { - GtkTreeIter tab; - gtk_tree_store_append(store, &tab, &group); - gtk_tree_store_set(store, &tab, 0, "Misc", 1, (gpointer)PTAB_MISC, -1); - } - if (!g_qeglobals.bBSPFrontendPlugin) - { - GtkTreeIter tab; - gtk_tree_store_append(store, &tab, &group); - gtk_tree_store_set(store, &tab, 0, "BSP Monitoring", 1, (gpointer)PTAB_BSPMONITOR, -1); - } - } - } - - gtk_tree_view_expand_all(GTK_TREE_VIEW(view)); - - g_object_unref(G_OBJECT(store)); - } - - /**********************************************************************/ - /* build the prefs pages */ - /**********************************************************************/ - - // Front page... - // todo : add something interesting here - // NOTE TTimo: tip of the day? or a logo? - preflabel = gtk_label_new("Front Page"); - gtk_widget_show(preflabel); - pageframe = gtk_frame_new(NULL); - gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); - gtk_widget_show(pageframe); - vbox = gtk_vbox_new(FALSE, 5); - gtk_widget_show(vbox); - gtk_widget_set_usize(GTK_WIDGET(vbox), 350, -2); - gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); - gtk_container_add(GTK_CONTAINER(pageframe), vbox); - - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); - - /******** global preferences group ****************************/ - preflabel = gtk_label_new("Globals"); - gtk_widget_show(preflabel); - - pageframe = mGamesDialog.GetGlobalFrame(); - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); - - /******** 2D prefs group (xy views/rendering options) *********/ - preflabel = gtk_label_new("2D Display"); - gtk_widget_show(preflabel); - pageframe = gtk_frame_new("2D Display"); - gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); - gtk_widget_show(pageframe); - vbox = gtk_vbox_new(FALSE, 5); - gtk_widget_show(vbox); - gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); - gtk_container_add(GTK_CONTAINER(pageframe), vbox); - - // OpenGL Display Lists - check = gtk_check_button_new_with_label("OpenGL Display Lists"); - gtk_widget_show(check); - gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); - AddDialogData(check, &m_bDisplayLists, DLG_CHECK_BOOL); - - // Antialiased points & lines - // Fishman - Add antialiazed points and lines support. 09/03/00 - check = gtk_check_button_new_with_label ("OpenGL antialiased points and lines"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bAntialiasedPointsAndLines, DLG_CHECK_BOOL); - - // Solid selection boxes - check = gtk_check_button_new_with_label ("Solid selection boxes"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bNoStipple, DLG_CHECK_BOOL); - - // Display size info - check = gtk_check_button_new_with_label ("Display size info"); - gtk_widget_show (check); - gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bSizePaint, DLG_CHECK_BOOL); - - // Alternate vertex/edge handles - // Gef: Kyro GL_POINT work around 25-aug-2001 - check = gtk_check_button_new_with_label ("Alternate vertex/edge handles"); - gtk_widget_show(check); - gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); - AddDialogData(check, &m_bGlPtWorkaround, DLG_CHECK_BOOL); - - g_list_free (combo_list); - -#ifdef ATIHACK_812 - // ATI bugs - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=812 - check = gtk_check_button_new_with_label ("ATI cards with broken drivers - bug #802"); - gtk_widget_show(check); - gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); - AddDialogData(check, &m_bGlATIHack, DLG_CHECK_BOOL); -#endif - - // Add the page to the notebook - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); - - /******** 3D Camera view group *********/ - preflabel = gtk_label_new("3D View"); - gtk_widget_show(preflabel); - pageframe = gtk_frame_new("3D View"); - gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); - gtk_widget_show(pageframe); - vbox = gtk_vbox_new(FALSE, 5); - gtk_widget_show(vbox); - gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); - gtk_container_add(GTK_CONTAINER(pageframe), vbox); - - // Directional velocity (Movement Velocity) - // label container - hbox2 = gtk_hbox_new (FALSE, 0); - gtk_widget_show (hbox2); - gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 0); - - // label - label = gtk_label_new("Movement Velocity"); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_widget_show(label); - gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0); - - // adjustment - adj = gtk_adjustment_new(100, 50, 300, 1, 10, 10); - AddDialogData(adj, &m_nMoveSpeed, DLG_ADJ_INT); - - // scale - scale = gtk_hscale_new(GTK_ADJUSTMENT(adj)); - gtk_widget_show(scale); - gtk_box_pack_start(GTK_BOX (vbox), scale, FALSE, TRUE, 2); - - gtk_scale_set_draw_value (GTK_SCALE (scale), TRUE); - - // Angular velocity (Rotational Velocity) - // label container - hbox2 = gtk_hbox_new (FALSE, 0); - gtk_widget_show (hbox2); - gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 0); - - // label - label = gtk_label_new ("Rotational Velocity"); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_widget_show (label); - gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0); - - // adjustment - adj = gtk_adjustment_new (3, 1, 180, 1, 10, 10); // value, low, high, step, page_step, page_size - AddDialogData (adj, &m_nAngleSpeed, DLG_ADJ_INT); - - // scale - scale = gtk_hscale_new (GTK_ADJUSTMENT (adj)); - gtk_widget_show (scale); - gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, TRUE, 2); - gtk_scale_set_draw_value (GTK_SCALE (scale), TRUE); - - // Text under the velocity sliders - // container - hbox2 = gtk_hbox_new (FALSE, 0); - gtk_widget_show (hbox2); - gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 0); - - // label - label = gtk_label_new ("slow"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); - - // label - label = gtk_label_new ("fast"); - gtk_widget_show (label); - gtk_box_pack_end (GTK_BOX (hbox2), label, FALSE, FALSE, 0); - - // Allow drag to select multiple faces/brushes - // container - table = gtk_table_new(2, 1, FALSE); - gtk_widget_show(table); - gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("Use paint-select in camera view:"); - gtk_widget_show (label); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - combo_list = NULL; - combo_list = g_list_append (combo_list, (void *)"No"); - combo_list = g_list_append (combo_list, (void *)"Yes"); - combo_list = g_list_append (combo_list, (void *)"Yes (Classic Key Setup)"); - - combo = gtk_combo_new (); - gtk_combo_set_popdown_strings (GTK_COMBO (combo), combo_list); - gtk_widget_show (combo); - gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE); - AddDialogData (combo, &m_nCamDragMultiSelect, DLG_COMBO_INT); - - // Freelook in Camera view - check = gtk_check_button_new_with_label ("Freelook in Camera view"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - gtk_label_set_justify (GTK_LABEL (GTK_BIN (check)->child), GTK_JUSTIFY_LEFT); - AddDialogData (check, &m_bCamFreeLook, DLG_CHECK_BOOL); - - // Freelook in Camera view w/ forward & back strafing instead of up and down looking - check = gtk_check_button_new_with_label ("Freelook strafes Forward and Back"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - gtk_label_set_justify (GTK_LABEL (GTK_BIN (check)->child), GTK_JUSTIFY_LEFT); - AddDialogData (check, &m_bCamFreeLookStrafe, DLG_CHECK_BOOL); - - // Invert mouse in freelook - check = gtk_check_button_new_with_label ("Invert mouse in freelook"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - gtk_label_set_justify (GTK_LABEL (GTK_BIN (check)->child), GTK_JUSTIFY_LEFT); - AddDialogData (check, &m_bCamInverseMouse, DLG_CHECK_BOOL); - - // Discrete movement - check = gtk_check_button_new_with_label ("Discrete movement"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - gtk_label_set_justify (GTK_LABEL (GTK_BIN (check)->child), GTK_JUSTIFY_LEFT); - AddDialogData (check, &m_bCamDiscrete, DLG_CHECK_BOOL); - - // Update XY views on camera move - check = gtk_check_button_new_with_label ("Update XY views on camera move"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - gtk_label_set_justify (GTK_LABEL (GTK_BIN (check)->child), GTK_JUSTIFY_LEFT); - AddDialogData (check, &m_bCamXYUpdate, DLG_CHECK_BOOL); - - // Add the page to the notebook - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); - - /******** Texture group *********/ - preflabel = gtk_label_new("Textures"); - gtk_widget_show(preflabel); - pageframe = gtk_frame_new("Textures"); - gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); - gtk_widget_show(pageframe); - vbox = gtk_vbox_new(FALSE, 6); - gtk_widget_show(vbox); - gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); - gtk_container_add(GTK_CONTAINER(pageframe), vbox); - - // Texture quality slider - // label - label = gtk_label_new ("Texture quality"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - - // adjustment - adj = gtk_adjustment_new (0, 0, 4, 1, 1, 1); - AddDialogData (adj, &m_nLatchedTextureQuality, DLG_ADJ_INT); - - // scale - scale = gtk_hscale_new (GTK_ADJUSTMENT (adj)); - gtk_widget_show (scale); - gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0); - gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE); - - // text under the texture slider - hbox2 = gtk_hbox_new (FALSE, 0); - gtk_widget_show (hbox2); - gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 0); - label = gtk_label_new ("low"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); - label = gtk_label_new ("high"); - gtk_widget_show (label); - gtk_box_pack_end (GTK_BOX (hbox2), label, FALSE, FALSE, 0); - - // texture subsets - check = gtk_check_button_new_with_label ("Texture subsets"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bTextureWindow, DLG_CHECK_BOOL); - - // texture scrollbar - check = gtk_check_button_new_with_label ("Texture scrollbar"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bTextureScrollbar, DLG_CHECK_BOOL); - - // texture increment matches grid - check = gtk_check_button_new_with_label ("Tex increment matches grid"); - gtk_widget_show (check); - gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bSnapTToGrid, DLG_CHECK_BOOL); - - // RIANT - // Texture compression choice label - // container - table = gtk_table_new(2, 1, FALSE); - gtk_widget_show(table); - gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("Texture Compression (if available):"); - gtk_widget_show (label); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - // Texture compression choice label - combo_list = NULL; - // NONE will always be in pos 0 - combo_list = g_list_append (combo_list, (void *)"None"); - - // if OpenGL compression is enabled it will always be - // in pos 1 - if (g_qeglobals.m_bOpenGLCompressionSupported) - { - combo_list = g_list_append (combo_list, (void *)"OpenGL ARB"); - } - - // If S3 is enabled offer all 3 valid compression schemes in RGBA - if (g_qeglobals.m_bS3CompressionSupported) - { - combo_list = g_list_append (combo_list, (void *)"S3TC DXT1"); - combo_list = g_list_append (combo_list, (void *)"S3TC DXT3"); - combo_list = g_list_append (combo_list, (void *)"S3TC DXT5"); - } - - combo = gtk_combo_new (); - gtk_combo_set_popdown_strings (GTK_COMBO (combo), combo_list); - gtk_widget_show (combo); - gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE); - AddDialogData (combo, &m_nTextureCompressionFormat, DLG_COMBO_INT); - g_list_free (combo_list); - - // container - table = gtk_table_new(2, 1, FALSE); - gtk_widget_show(table); - gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - // Startup shaders - // label - label = gtk_label_new ("Startup Shaders:"); - gtk_widget_show (label); - gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT); - gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - - // combo list - combo_list = NULL; - combo_list = g_list_append (combo_list, (void *)"None"); - if (g_pGameDescription->mGameFile == "jk2.game" || g_pGameDescription->mGameFile == "ja.game") - combo_list = g_list_append (combo_list, (void *)"System"); - else if (g_pGameDescription->mGameFile == "sof2.game") - combo_list = g_list_append (combo_list, (void *)"Tools"); - else - combo_list = g_list_append (combo_list, (void *)"Common"); - combo_list = g_list_append (combo_list, (void *)"All"); - combo = gtk_combo_new (); - gtk_combo_set_popdown_strings (GTK_COMBO (combo), combo_list); - gtk_widget_show (combo); - gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE); - AddDialogData (combo, &m_nLatchedShader, DLG_COMBO_INT); - g_list_free (combo_list); - - // Add the page to the notebook - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); - - /******** Layout group *********/ - preflabel = gtk_label_new("Layout"); - gtk_widget_show(preflabel); - pageframe = gtk_frame_new("Layout"); - gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); - gtk_widget_show(pageframe); - vbox = gtk_vbox_new(FALSE, 5); - gtk_widget_show(vbox); - gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); - gtk_container_add(GTK_CONTAINER(pageframe), vbox); - - // View types - // table - table = gtk_table_new (2, 4, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - // view type 1 - pixmap = new_pixmap (g_pParentWnd->m_pWidget, "window1.bmp"); - gtk_widget_show (pixmap); - gtk_table_attach (GTK_TABLE (table), pixmap, 0, 1, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - // view type 2 - pixmap = new_pixmap (g_pParentWnd->m_pWidget, "window2.bmp"); - gtk_widget_show (pixmap); - gtk_table_attach (GTK_TABLE (table), pixmap, 1, 2, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - // view type 3 - pixmap = new_pixmap (g_pParentWnd->m_pWidget, "window3.bmp"); - gtk_widget_show (pixmap); - gtk_table_attach (GTK_TABLE (table), pixmap, 2, 3, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - // view type 4 - pixmap = new_pixmap (g_pParentWnd->m_pWidget, "window4.bmp"); - gtk_widget_show (pixmap); - gtk_table_attach (GTK_TABLE (table), pixmap, 3, 4, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - // view type 1 selector - radio = gtk_radio_button_new (NULL); - gtk_widget_show (radio); - gtk_table_attach (GTK_TABLE (table), radio, 0, 1, 1, 2, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - // view type 2 selector - radio = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (radio)); - gtk_widget_show (radio); - gtk_table_attach (GTK_TABLE (table), radio, 1, 2, 1, 2, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - // view type 3 selector - radio = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (radio)); - gtk_widget_show (radio); - gtk_table_attach (GTK_TABLE (table), radio, 2, 3, 1, 2, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - // view type 4 selector - radio = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (radio)); - gtk_widget_show (radio); - gtk_table_attach (GTK_TABLE (table), radio, 3, 4, 1, 2, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - AddDialogData (radio, &m_nLatchedView, DLG_RADIO_INT); - - // Floating Z window - check = gtk_check_button_new_with_label ("Floating Z Window"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bLatchedFloatingZ, DLG_CHECK_BOOL); - - // show menu tear-off seperators - check = gtk_check_button_new_with_label ("Detachable Menus"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bLatchedDetachableMenus, DLG_CHECK_BOOL); - - if (!g_pGameDescription->mNoPatch) - { - // show patch toolbar - check = gtk_check_button_new_with_label ("Patch Toolbar"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - g_object_set_data (G_OBJECT (dialog), "check_patchtoolbar", check); // Allow to be disabled for Q1/Q2 - AddDialogData (check, &m_bLatchedPatchToolbar, DLG_CHECK_BOOL); - } - - // use wide toolbar - check = gtk_check_button_new_with_label ("Wide Toolbar"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bLatchedWideToolbar, DLG_CHECK_BOOL); - - // use plugin toolbar - check = gtk_check_button_new_with_label ("Plugin Toolbar"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bLatchedPluginToolbar, DLG_CHECK_BOOL); - -#ifdef _WIN32 - // win32 file dialog - check = gtk_check_button_new_with_label ("Use win32 file load dialog"); - gtk_widget_show (check); - // gtk_container_add (GTK_CONTAINER (vbox), check); - gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bNativeGUI, DLG_CHECK_BOOL); - - // position on primary monitor - check = gtk_check_button_new_with_label ("Start on Primary Monitor"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - g_object_set_data (G_OBJECT (dialog), "check_startonprimary", check); - gtk_signal_connect( GTK_OBJECT (check), "clicked", GTK_SIGNAL_FUNC(UpdateSensitivity), this ); - AddDialogData (check, &m_bStartOnPrimMon, DLG_CHECK_BOOL); -#endif - - // Add the page to the notebook - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); - - /******** Mouse group *********/ - preflabel = gtk_label_new("Mouse"); - gtk_widget_show(preflabel); - pageframe = gtk_frame_new("Mouse"); - gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); - gtk_widget_show(pageframe); - vbox = gtk_vbox_new(FALSE, 5); - gtk_widget_show(vbox); - gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); - gtk_container_add(GTK_CONTAINER(pageframe), vbox); - - // Buttons - // container - hbox2 = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox2); - gtk_box_pack_start(GTK_BOX(vbox), hbox2, FALSE, FALSE, 0); - - // 2 button radio - radio = gtk_radio_button_new_with_label (NULL, "2 button"); - gtk_widget_show (radio); - gtk_box_pack_start (GTK_BOX (hbox2), radio, FALSE, FALSE, 0); - - // 3 button radio - radio = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (radio), "3 button"); - gtk_widget_show (radio); - gtk_box_pack_start (GTK_BOX (hbox2), radio, FALSE, FALSE, 0); - AddDialogData (radio, &m_nMouse, DLG_RADIO_INT); - - // right click to drop entity - check = gtk_check_button_new_with_label ("Right click to drop entities"); - gtk_widget_show (check); - gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bRightClick, DLG_CHECK_BOOL); - - // Mouse chaser (and this does what?) - check = gtk_check_button_new_with_label ("Mouse chaser"); - gtk_widget_show (check); - gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bChaseMouse, DLG_CHECK_BOOL); - - // Alt + multi-drag - check = gtk_check_button_new_with_label ("ALT + multi-drag"); - gtk_widget_show (check); - gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bALTEdge, DLG_CHECK_BOOL); - - // Mouse wheel increments - // container - hbox2 = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox2); - gtk_box_pack_start(GTK_BOX(vbox), hbox2, FALSE, FALSE, 0); - - // label - label = gtk_label_new ("Wheel Mouse inc:"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); - - // entry - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_widget_set_usize (entry, 40, -2); - gtk_box_pack_start (GTK_BOX (hbox2), entry, FALSE, FALSE, 0); - AddDialogData (entry, &m_nWheelInc, DLG_ENTRY_INT); - - // Add the page to the notebook - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); - - /******** Editing group *********/ - preflabel = gtk_label_new("Editing"); - gtk_widget_show(preflabel); - pageframe = gtk_frame_new("Editing"); - gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); - gtk_widget_show(pageframe); - vbox = gtk_vbox_new(FALSE, 5); - gtk_widget_show(vbox); - gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); - gtk_container_add(GTK_CONTAINER(pageframe), vbox); - - // Vertex editing splits faces - check = gtk_check_button_new_with_label ("Vertex editing splits face"); - gtk_widget_show (check); - gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bVertexSplit, DLG_CHECK_BOOL); - - // Fix target/targetname collisions - check = gtk_check_button_new_with_label ("Fix target/targetname collisions"); - gtk_widget_show (check); - gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bDoTargetFix, DLG_CHECK_BOOL); - - // Clipper tool uses caulk - check = gtk_check_button_new_with_label ("Clipper tool uses caulk"); - gtk_widget_show (check); - gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bClipCaulk, DLG_CHECK_BOOL); - - // Don't clamp plane points - check = gtk_check_button_new_with_label ("Don't clamp plane points"); - gtk_widget_show (check); - gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bNoClamp, DLG_CHECK_BOOL); - - // Select patch by bounding box - check = gtk_check_button_new_with_label ("Select patches by bounding box"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bPatchBBoxSelect, DLG_CHECK_BOOL); - - // Rotation increment - // container - table = gtk_table_new (2, 3, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - // label - label = gtk_label_new ("Rotation increment:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - // entry - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_widget_set_usize (entry, 60, -2); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - AddDialogData (entry, &m_nRotation, DLG_ENTRY_INT); - - // Undo levels - // label - label = gtk_label_new ("Undo Levels:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - // spinner (allows undo levels to be set to zero) - spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (1, 0, 64, 1, 10, 10)), 1, 0); - gtk_widget_show (spin); - gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (spin, 60, -2); - AddDialogData (spin, &m_nUndoLevels, DLG_SPIN_INT); - - // Patch subdivisions - // label - label = gtk_label_new ("Patch subdivisions:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - // entry (spinner perhaps? [2-16]) - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_widget_set_usize (entry, 60, -2); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - AddDialogData (entry, &m_nSubdivisions, DLG_ENTRY_INT); - - // Add the page to the notebook - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); - - /******** Save/Load group *********/ - preflabel = gtk_label_new("Startup/Auto save"); - gtk_widget_show(preflabel); - pageframe = gtk_frame_new("Startup/Auto save"); - gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); - gtk_widget_show(pageframe); - vbox = gtk_vbox_new(FALSE, 5); - gtk_widget_show(vbox); - gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); - gtk_container_add(GTK_CONTAINER(pageframe), vbox); - - // Snapshots - check = gtk_check_button_new_with_label ("Snapshots"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bSnapShots, DLG_CHECK_BOOL); - - // load last project on open - check = gtk_check_button_new_with_label ("Load last project on open"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bLoadLast, DLG_CHECK_BOOL); - - // load last map on open - check = gtk_check_button_new_with_label ("Load last map on open"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bLoadLastMap, DLG_CHECK_BOOL); - - // Auto save.. - // container - hbox2 = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox2); - gtk_box_pack_start(GTK_BOX(vbox), hbox2, FALSE, FALSE, 0); - gtk_container_set_border_width (GTK_CONTAINER (hbox2), 0); - - // label - check = gtk_check_button_new_with_label ("Auto save every"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (hbox2), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bAutoSave, DLG_CHECK_BOOL); - - // spinner - spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (1, 1, 60, 1, 10, 10)), 1, 0); - gtk_widget_show (spin); - gtk_box_pack_start (GTK_BOX (hbox2), spin, FALSE, FALSE, 0); - gtk_widget_set_usize (spin, 60, -2); - AddDialogData (spin, &m_nAutoSave, DLG_SPIN_INT); - - // label - label = gtk_label_new ("minutes"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); - - // Add the page to the notebook - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); - - /******** Paths group *********/ - preflabel = gtk_label_new("Paths"); - gtk_widget_show(preflabel); - pageframe = gtk_frame_new("Paths"); - gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); - gtk_widget_show(pageframe); - vbox = gtk_vbox_new(FALSE, 5); - gtk_widget_show(vbox); - gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); - gtk_container_add(GTK_CONTAINER(pageframe), vbox); - - // prefab path - // table - table = gtk_table_new (3, 3, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - // label - label = gtk_label_new ("Prefab path:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - // path entry - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_widget_set_usize(GTK_WIDGET(entry), 240, -2); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 1, 0); - AddDialogData (entry, &m_strPrefabPath, DLG_ENTRY_TEXT); - - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=805 -#if 0 - // browse button - button = gtk_button_new_with_label ("..."); - gtk_widget_show (button); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnBrowseprefab), this); - gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); -#endif - - // User ini path - // label - label = gtk_label_new ("User INI path:"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - - // user ini path entry - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 1, 0); - AddDialogData (entry, &m_strUserPath, DLG_ENTRY_TEXT); - - // user ini browse button - button = gtk_button_new_with_label ("..."); - gtk_widget_show (button); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnBrowseuserini), this); - gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - // Add the page to the notebook - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); - - /******** Misc group *********/ - preflabel = gtk_label_new("Misc"); - gtk_widget_show(preflabel); - pageframe = gtk_frame_new("Misc"); - gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); - gtk_widget_show(pageframe); - vbox = gtk_vbox_new(FALSE, 5); - gtk_widget_show(vbox); - gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); - gtk_container_add(GTK_CONTAINER(pageframe), vbox); - - // Light drawing - check = gtk_check_button_new_with_label ("Light drawing"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &m_bNewLightDraw, DLG_CHECK_BOOL); - - // Light radiuses - // container - table = gtk_table_new(2, 1, FALSE); - gtk_widget_show(table); - gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("Light radiuses:"); - gtk_widget_show (label); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - - combo_list = NULL; - combo_list = g_list_append (combo_list, (void *)"Disabled"); - combo_list = g_list_append (combo_list, (void *)"True Q3Map2 Style"); - combo_list = g_list_append (combo_list, (void *)"Classic Style"); - - combo = gtk_combo_new (); - gtk_combo_set_popdown_strings (GTK_COMBO (combo), combo_list); - gtk_widget_show (combo); - gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE); - AddDialogData (combo, &m_nLightRadiuses, DLG_COMBO_INT); - -#ifdef _WIN32 - check = gtk_check_button_new_with_label ("Use win32 file associations to open text files instead of builtin editor"); - gtk_widget_show(check); - gtk_box_pack_start(GTK_BOX (vbox), check, FALSE, FALSE, 0); - AddDialogData (check, &g_PrefsDlg.m_bUseWin32Editor, DLG_CHECK_BOOL); -#else - // use custom shader editor - check = gtk_check_button_new_with_label ("Use Custom Shader Editor"); - gtk_widget_show(check); - gtk_box_pack_start(GTK_BOX (vbox), check, FALSE, FALSE, 0); - gtk_signal_connect( GTK_OBJECT (check), "clicked", GTK_SIGNAL_FUNC(UpdateEditorSensitivity), this); - g_object_set_data (G_OBJECT(dialog), "check_customeditor", check); - AddDialogData (check, &g_PrefsDlg.m_bUseCustomEditor, DLG_CHECK_BOOL); - - // custom shader editor executable - // table - table = gtk_table_new (3, 1, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - // label - label = gtk_label_new("Custom Editor Command"); - gtk_widget_show(label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); - g_object_set_data (G_OBJECT(dialog), "label_customeditor", label); - gtk_widget_set_sensitive (label, g_PrefsDlg.m_bUseCustomEditor); - - // custom editor command entry - entry = gtk_entry_new (); - gtk_widget_show (entry); - gtk_widget_set_usize(GTK_WIDGET(entry), 240, -2); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 1, 0); - AddDialogData (entry, &m_strEditorCommand, DLG_ENTRY_TEXT); - gtk_widget_set_sensitive (entry, g_PrefsDlg.m_bUseCustomEditor); - g_object_set_data (G_OBJECT(dialog), "entry_customeditor", entry); - - // browse button - button = gtk_button_new_with_label ("..."); - gtk_widget_show (button); - gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnBrowseEditor), this); - gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1, - (GtkAttachOptions) (0), - (GtkAttachOptions) (0), 0, 0); - g_object_set_data (G_OBJECT(dialog), "button_customeditor", button); - gtk_widget_set_sensitive (button, g_PrefsDlg.m_bUseCustomEditor); -#endif - - // Add the page to the notebook - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); - - /******** BSP Monitoring group *********/ - // this is never displayed if the plugin isn't available - preflabel = gtk_label_new("BSP Monitoring"); - gtk_widget_show(preflabel); - pageframe = gtk_frame_new("BSP Monitoring"); - gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); - gtk_widget_show(pageframe); - vbox = gtk_vbox_new(FALSE, 5); - gtk_widget_show(vbox); - gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); - gtk_container_add(GTK_CONTAINER(pageframe), vbox); - - // Enable BSP process monitoring - check = gtk_check_button_new_with_label ("Enable BSP process monitoring"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - g_object_set_data (G_OBJECT (dialog), "check_monitorbsp", check); - gtk_signal_connect( GTK_OBJECT (check), "clicked", GTK_SIGNAL_FUNC(UpdateSensitivity), this ); - AddDialogData (check, &g_PrefsDlg.m_bWatchBSP, DLG_CHECK_BOOL); - - // Stop on leak - check = gtk_check_button_new_with_label ("Stop compilation on leak"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - g_object_set_data (G_OBJECT (dialog), "check_leakstop", check); - AddDialogData (check, &g_PrefsDlg.m_bLeakStop, DLG_CHECK_BOOL); - - // engine after compile - check = gtk_check_button_new_with_label ("Run engine after compile"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - g_object_set_data (G_OBJECT (dialog), "check_runengine", check); - gtk_signal_connect( GTK_OBJECT (check), "clicked", GTK_SIGNAL_FUNC(UpdateSensitivity), this ); - AddDialogData( check, &g_PrefsDlg.m_bRunQuake, DLG_CHECK_BOOL ); - - // sleep mode when running engine - check = gtk_check_button_new_with_label ("Activate sleep mode when running the engine"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - g_object_set_data (G_OBJECT (dialog), "check_sleep", check); - AddDialogData( check, &g_PrefsDlg.m_bDoSleep, DLG_CHECK_BOOL ); - - // use q3map2's texture projection - check = gtk_check_button_new_with_label ("Texturing compatible with q3map2"); - gtk_widget_show (check); - gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); - g_object_set_data (G_OBJECT (dialog), "check_q3map2", check); - AddDialogData( check, &g_PrefsDlg.m_bQ3Map2Texturing, DLG_CHECK_BOOL ); - - // Add the page to the notebook - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); - - gtk_notebook_set_page(GTK_NOTEBOOK(notebook), PTAB_FRONT); - - return; -} - -// end new prefs dialog - -void PrefsDlg::LoadTexdefPref(texdef_t* pTexdef, char* pName) -{ - char buffer[256]; - - memset(pTexdef, 0, sizeof(texdef_t)); - - sprintf(buffer, "%s%s", pName, TD_SCALE1_KEY); - mLocalPrefs.GetPref(buffer, &pTexdef->scale[0], 0.5f); - - sprintf(buffer, "%s%s", pName, TD_SCALE2_KEY); - mLocalPrefs.GetPref(buffer, &pTexdef->scale[1], 0.5f); - - sprintf(buffer, "%s%s", pName, TD_SHIFT1_KEY); - mLocalPrefs.GetPref(buffer, &pTexdef->shift[0], 8.f); - - sprintf(buffer, "%s%s", pName, TD_SHIFT2_KEY); - mLocalPrefs.GetPref(buffer, &pTexdef->shift[1], 8.f); - - sprintf(buffer, "%s%s", pName, TD_ROTATE_KEY); - mLocalPrefs.GetPref(buffer, &pTexdef->rotate, 45); -} - -void PrefsDlg::UpdateTextureCompression() -{ - // if OpenGL is not ready yet, don't do anything - if (!g_qeglobals.m_bOpenGLReady) { - Sys_Printf("OpenGL not ready - postpone texture compression capability check\n"); - return; - } - - if (g_qeglobals.bTextureCompressionSupported) - { - if (m_nTextureCompressionFormat >= 2 && !g_qeglobals.m_bS3CompressionSupported) - { - Sys_Printf("Inconsistant pref setting for texture compression (%d), rolling back\n", m_nTextureCompressionFormat); - m_nTextureCompressionFormat = 1; // if this is not supported either, see below - } - if (m_nTextureCompressionFormat == 1 && !g_qeglobals.m_bOpenGLCompressionSupported) - { - Sys_Printf("Inconsistant pref setting for texture compression (GL_COMPRESSED_RGBA), rolling back\n"); - m_nTextureCompressionFormat = 0; - } - switch (m_nTextureCompressionFormat) - { - case (0): - { - g_qeglobals.texture_components = GL_RGBA; - Sys_Printf("texture compression disabled by preferences settings\n"); - break; - } - case (1): - { - g_qeglobals.texture_components = GL_COMPRESSED_RGBA; - Sys_Printf("OpenGL texture compression enabled\n"); - break; - } - case (2): - { - g_qeglobals.texture_components = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - Sys_Printf("S3TC DXT1 texture compression enabled\n"); - break; - } - case (3): - { - g_qeglobals.texture_components = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; - Sys_Printf("S3TC DXT3 texture compression enabled\n"); - break; - } - case (4): - { - g_qeglobals.texture_components = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - Sys_Printf("S3TC DXT5 texture compression enabled\n"); - break; - } - } - } - else - { - Sys_Printf("texture compression is not supported by your current graphic card/drivers\n"); - g_qeglobals.texture_components = GL_RGBA; - m_nTextureCompressionFormat = 0; - } -} - -#ifdef ATIHACK_812 -void PrefsDlg::UpdateATIHack() { - // if OpenGL is not ready yet, don't do anything - if (!g_qeglobals.m_bOpenGLReady) { - Sys_Printf("OpenGL not ready - postpone ATI bug workaround setup\n"); - return; - } - - if (m_bGlATIHack) { - qglCullFace = &qglCullFace_ATIHack; - qglDisable = &qglDisable_ATIHack; - qglEnable = &qglEnable_ATIHack; - qglPolygonMode = &qglPolygonMode_ATIHack; - Sys_Printf("ATI bug workaround enabled\n"); - } else { - qglCullFace = qglCullFace_real; - qglDisable = qglDisable_real; - qglEnable = qglEnable_real; - qglPolygonMode = qglPolygonMode_real; - Sys_Printf("ATI bug workaround disabled\n"); - } -} -#endif - -// TTimo: m_strEnginePath has a special status, if not found in registry we need to -// initiliaze it for sure. It is not totally failsafe but we can use the same -// code than in q3map, expecting to find some "quake" above us. If not, we prompt -// for the engine executable path -void PrefsDlg::LoadPrefs () -{ - int i; - - // first things first, load prefs from global prefs - mGamesDialog.LoadPrefs(); - - // if we already have a document loaded, we will free and reload from file - if (mLocalPrefs.InUse()) { - mLocalPrefs.Clear(); - } - - // load local.pref file - mLocalPrefs.ReadXMLFile(m_inipath->str); - - mLocalPrefs.GetPref(PATCHSHOWBOUNDS_KEY, &g_bPatchShowBounds, FALSE); - mLocalPrefs.GetPref(MOUSE_KEY, &m_nMouse, MOUSE_DEF); - m_nMouseButtons = m_nMouse ? 3 : 2; - - // project file - // if it's not found here, mainframe.cpp will take care of finding one - mLocalPrefs.GetPref(LASTPROJ_KEY, &m_strLastProject, ""); - mLocalPrefs.GetPref(LASTPROJVER_KEY, &m_nLastProjectVer, -1); - - // prefab path - // NOTE TTimo: I'm not sure why this is in prefs - // should probably be a project setting - // and I'm not sure that we really have a way to set this reliably either - CString strPrefab; - strPrefab = g_qeglobals.m_strHomeGame.GetBuffer(); - strPrefab += g_pGameDescription->mBaseGame.GetBuffer(); - strPrefab += "/prefabs/"; - mLocalPrefs.GetPref(PREFAB_KEY, &m_strPrefabPath, strPrefab); - - mLocalPrefs.GetPref(LASTLIGHTINTENSITY_KEY, &m_iLastLightIntensity, 300); - mLocalPrefs.GetPref(TLOCK_KEY, &m_bTextureLock, TLOCK_DEF); - mLocalPrefs.GetPref(RLOCK_KEY, &m_bRotateLock, TLOCK_DEF); - mLocalPrefs.GetPref(LASTMAP_KEY, &m_strLastMap, ""); - mLocalPrefs.GetPref(LOADLAST_KEY, &m_bLoadLast, LOADLAST_DEF); - mLocalPrefs.GetPref(BSP_KEY, &m_bInternalBSP, FALSE); - mLocalPrefs.GetPref(RCLICK_KEY, &m_bRightClick, TRUE); - mLocalPrefs.GetPref(AUTOSAVE_KEY, &m_bAutoSave, TRUE); - mLocalPrefs.GetPref(LOADLASTMAP_KEY, &m_bLoadLastMap, FALSE); - mLocalPrefs.GetPref(TINYBRUSH_KEY, &m_bCleanTiny, FALSE); - mLocalPrefs.GetPref(TINYSIZE_KEY, &m_fTinySize, 0.5f); - mLocalPrefs.GetPref(AUTOSAVETIME_KEY, &m_nAutoSave, 5); - mLocalPrefs.GetPref(SNAPSHOT_KEY, &m_bSnapShots, FALSE); - mLocalPrefs.GetPref(MOVESPEED_KEY, &m_nMoveSpeed, 100); - mLocalPrefs.GetPref(ANGLESPEED_KEY, &m_nAngleSpeed, 3); - mLocalPrefs.GetPref(SETGAME_KEY, &m_bSetGame, FALSE); - mLocalPrefs.GetPref(CAMXYUPDATE_KEY, &m_bCamXYUpdate, TRUE); - mLocalPrefs.GetPref(CAMDRAGMULTISELECT_KEY, &m_nCamDragMultiSelect, TRUE); - mLocalPrefs.GetPref(CAMFREELOOK_KEY, &m_bCamFreeLook, TRUE); - mLocalPrefs.GetPref(CAMINVERSEMOUSE_KEY, &m_bCamInverseMouse, FALSE); - mLocalPrefs.GetPref(CAMDISCRETE_KEY, &m_bCamDiscrete, TRUE); - mLocalPrefs.GetPref(LIGHTDRAW_KEY, &m_bNewLightDraw, TRUE); - mLocalPrefs.GetPref(CUBICCLIP_KEY, &m_bCubicClipping, TRUE); - mLocalPrefs.GetPref(CUBICSCALE_KEY, &m_nCubicScale, 13); - mLocalPrefs.GetPref(ALTEDGE_KEY, &m_bALTEdge, FALSE); - mLocalPrefs.GetPref(FACECOLORS_KEY, &m_bFaceColors, FALSE); - mLocalPrefs.GetPref(XZVIS_KEY, &m_bXZVis, FALSE); - mLocalPrefs.GetPref(YZVIS_KEY, &m_bYZVis, FALSE); - mLocalPrefs.GetPref(ZVIS_KEY, &m_bZVis, FALSE); - mLocalPrefs.GetPref(SIZEPAINT_KEY, &m_bSizePaint, FALSE); - mLocalPrefs.GetPref(DLLENTITIES_KEY, &m_bDLLEntities, FALSE); - - mLocalPrefs.GetPref(DETACHABLEMENUS_KEY, &m_bLatchedDetachableMenus, TRUE); - m_bDetachableMenus = m_bLatchedDetachableMenus; - - if (g_pGameDescription->mNoPatch) - { - m_bPatchToolbar = false; - } - else - { - mLocalPrefs.GetPref(PATCHTOOLBAR_KEY, &m_bLatchedPatchToolbar, TRUE); - m_bPatchToolbar = m_bLatchedPatchToolbar; - } - - mLocalPrefs.GetPref(WIDETOOLBAR_KEY, &m_bLatchedWideToolbar, TRUE); - m_bWideToolbar = m_bLatchedWideToolbar; - - mLocalPrefs.GetPref(PLUGINTOOLBAR_KEY, &m_bLatchedPluginToolbar, TRUE); - m_bPluginToolbar = m_bLatchedPluginToolbar; - - mLocalPrefs.GetPref(WINDOW_KEY, (int*)&m_nLatchedView, WINDOW_DEF); - m_nView = m_nLatchedView; - - mLocalPrefs.GetPref(FLOATINGZ_KEY, &m_bLatchedFloatingZ, FALSE); - m_bFloatingZ = m_bLatchedFloatingZ; - - mLocalPrefs.GetPref(TEXTUREQUALITY_KEY, &m_nLatchedTextureQuality, 3); - m_nTextureQuality = m_nLatchedTextureQuality; - - mLocalPrefs.GetPref(LOADSHADERS_KEY, &m_nLatchedShader, 0); - m_nShader = m_nLatchedShader; - - mLocalPrefs.GetPref(NOCLAMP_KEY, &m_bNoClamp, FALSE); - mLocalPrefs.GetPref(USERINI_KEY, &m_strUserPath, ""); - mLocalPrefs.GetPref(ROTATION_KEY, &m_nRotation, 45); - mLocalPrefs.GetPref(CHASEMOUSE_KEY, &m_bChaseMouse, TRUE); - mLocalPrefs.GetPref(ENTITYSHOW_KEY, &m_nEntityShowState, ENTITY_SKINNED_BOXED); - - // this will probably need to be 75 or 100 for Q1. - mLocalPrefs.GetPref(TEXTURESCALE_KEY, &m_nTextureScale, 50); - - // FIXME: Hydra - actually, this stuff is Q1,Q2 and HL specific. - if ( (g_pGameDescription->mGameFile == "hl.game") ) - { - // No BSP monitoring in the default compiler tools for Half-life (yet) - mLocalPrefs.GetPref(WATCHBSP_KEY, &m_bWatchBSP, FALSE); - - // Texture subset on by default (HL specific really, because of halflife.wad's size) - mLocalPrefs.GetPref(TEXTURE_KEY, &m_bTextureWindow, TRUE); - } - else if ( ( g_pGameDescription->mGameFile == "q2.game" ) || ( g_pGameDescription->mGameFile == "heretic2.game" ) ) - { - // BSP monitoring is implemented in Quake2 and Heretic2 tools - mLocalPrefs.GetPref(WATCHBSP_KEY, &m_bWatchBSP, TRUE); - - // Texture subset on by default (HL specific really, because of halflife.wad's size) - mLocalPrefs.GetPref(TEXTURE_KEY, &m_bTextureWindow, TRUE); - } - else - { - mLocalPrefs.GetPref(WATCHBSP_KEY, &m_bWatchBSP, WATCHBSP_DEF); - mLocalPrefs.GetPref(TEXTURE_KEY, &m_bTextureWindow, FALSE); - } - - - mLocalPrefs.GetPref(TEXTURESCROLLBAR_KEY, &m_bTextureScrollbar, TRUE); - mLocalPrefs.GetPref(DISPLAYLISTS_KEY, &m_bDisplayLists, TRUE); - mLocalPrefs.GetPref(ANTIALIASEDLINES_KEY, &m_bAntialiasedPointsAndLines, FALSE); - mLocalPrefs.GetPref(SWITCHCLIP_KEY, &m_bSwitchClip, TRUE); - mLocalPrefs.GetPref(SELWHOLEENTS_KEY, &m_bSelectWholeEntities, TRUE); - mLocalPrefs.GetPref(SHOWSHADERS_KEY, &m_bShowShaders, TRUE); - mLocalPrefs.GetPref(GLLIGHTING_KEY, &m_bGLLighting, FALSE); - mLocalPrefs.GetPref(NOSTIPPLE_KEY, &m_bNoStipple, FALSE); - mLocalPrefs.GetPref(UNDOLEVELS_KEY, &m_nUndoLevels, 30); - mLocalPrefs.GetPref(VERTEXMODE_KEY, &m_bVertexSplit, TRUE); - mLocalPrefs.GetPref(RUNQ2_KEY, &m_bRunQuake, RUNQ2_DEF); - mLocalPrefs.GetPref(LEAKSTOP_KEY, &m_bLeakStop, TRUE); - mLocalPrefs.GetPref(DOSLEEP_KEY, &m_bDoSleep, FALSE); - mLocalPrefs.GetPref(SELECTCURVES_KEY, &m_bSelectCurves, TRUE); - mLocalPrefs.GetPref(SELECTMODELS_KEY, &m_bSelectModels, TRUE); - mLocalPrefs.GetPref(SHADERLISTONLY_KEY, &m_bTexturesShaderlistOnly, FALSE); - mLocalPrefs.GetPref(SUBDIVISIONS_KEY, &m_nSubdivisions, SUBDIVISIONS_DEF); - mLocalPrefs.GetPref(CLIPCAULK_KEY, &m_bClipCaulk, FALSE); - mLocalPrefs.GetPref(SNAPTTOGRID_KEY, &m_bSnapTToGrid, FALSE); - mLocalPrefs.GetPref(TARGETFIX_KEY, &m_bDoTargetFix, TRUE); - mLocalPrefs.GetPref(WHEELINC_KEY, &m_nWheelInc, 64); - mLocalPrefs.GetPref(PATCHBBOXSEL_KEY, &m_bPatchBBoxSelect, FALSE); - - // Gef: Kyro GL_POINT workaround - mLocalPrefs.GetPref(GLPOINTWORKAROUND_KEY, &m_bGlPtWorkaround, FALSE); - - // window positioning - mLocalPrefs.GetPref(ENTITYSPLIT1_KEY, &mWindowInfo.nEntitySplit1, -1); - mLocalPrefs.GetPref(ENTITYSPLIT2_KEY, &mWindowInfo.nEntitySplit2, -1); - - mLocalPrefs.GetPref(POSITIONX_KEY, &mWindowInfo.position.x, -1); - mLocalPrefs.GetPref(POSITIONY_KEY, &mWindowInfo.position.y, -1); - mLocalPrefs.GetPref(WIDTH_KEY, &mWindowInfo.position.w, -1); - mLocalPrefs.GetPref(HEIGHT_KEY, &mWindowInfo.position.h, 450); - - const window_position_t default_window_pos = { 0, 0, 200, 200, }; - - mLocalPrefs.GetPref(ENTITYWND_KEY, &mWindowInfo.posEntityWnd, default_window_pos); - mLocalPrefs.GetPref(MAPINFOWND_KEY, &mWindowInfo.posMapInfoWnd, default_window_pos); - mLocalPrefs.GetPref(CAMWND_KEY, &mWindowInfo.posCamWnd, default_window_pos); - mLocalPrefs.GetPref(ZWND_KEY, &mWindowInfo.posZWnd, default_window_pos); - mLocalPrefs.GetPref(XYWND_KEY, &mWindowInfo.posXYWnd, default_window_pos); - mLocalPrefs.GetPref(YZWND_KEY, &mWindowInfo.posYZWnd, default_window_pos); - mLocalPrefs.GetPref(XZWND_KEY, &mWindowInfo.posXZWnd, default_window_pos); - mLocalPrefs.GetPref(PATCHWND_KEY, &mWindowInfo.posPatchWnd, default_window_pos); - mLocalPrefs.GetPref(SURFACEWND_KEY, &mWindowInfo.posSurfaceWnd, default_window_pos); - mLocalPrefs.GetPref(ENTITYINFOWND_KEY, &mWindowInfo.posEntityInfoWnd, default_window_pos); - - mLocalPrefs.GetPref(ZWIDTH_KEY, &mWindowInfo.nZWidth, 30); - mLocalPrefs.GetPref(XYHEIGHT_KEY, &mWindowInfo.nXYHeight, 300); - mLocalPrefs.GetPref(XYWIDTH_KEY, &mWindowInfo.nXYWidth, 300); - mLocalPrefs.GetPref(CAMWIDTH_KEY, &mWindowInfo.nCamWidth, 200); - mLocalPrefs.GetPref(CAMHEIGHT_KEY, &mWindowInfo.nCamHeight, 200); - mLocalPrefs.GetPref(ZFLOATWIDTH_KEY, &mWindowInfo.nZFloatWidth, 300); -#ifdef _WIN32 - mLocalPrefs.GetPref(STATE_KEY, &mWindowInfo.nState, SW_SHOW); -#endif - - // menu stuff - mLocalPrefs.GetPref(COUNT_KEY, &m_nMRUCount, 0); - for(i = 0; i < 4; i++) - { - char buf[64]; - sprintf (buf, "%s%d", FILE_KEY, i); - mLocalPrefs.GetPref(buf, &m_strMRUFiles[i], ""); - } - - // some platform specific prefs -#ifdef _WIN32 - mLocalPrefs.GetPref(NATIVEGUI_KEY, &m_bNativeGUI, TRUE); - mLocalPrefs.GetPref(STARTONPRIMMON_KEY, &m_bStartOnPrimMon, FALSE); -#endif - - mLocalPrefs.GetPref(SI_TEXMENU_KEY, &g_qeglobals.d_savedinfo.iTexMenu, ID_VIEW_BILINEARMIPMAP); - mLocalPrefs.GetPref(SI_GAMMA_KEY, &g_qeglobals.d_savedinfo.fGamma, 1.0f); - mLocalPrefs.GetPref(SI_EXCLUDE_KEY, &g_qeglobals.d_savedinfo.exclude, 0); // nothing filtered by default - mLocalPrefs.GetPref(SI_INCLUDE_KEY, &g_qeglobals.d_savedinfo.include, INCLUDE_NAMES | INCLUDE_COORDS | INCLUDE_ANGLES | INCLUDE_CAMERATINT); - mLocalPrefs.GetPref(SI_SHOWNAMES_KEY, &g_qeglobals.d_savedinfo.show_names, FALSE); - mLocalPrefs.GetPref(SI_SHOWCOORDS_KEY, &g_qeglobals.d_savedinfo.show_coordinates, TRUE); - mLocalPrefs.GetPref(SI_SHOWANGLES_KEY, &g_qeglobals.d_savedinfo.show_angles, TRUE); - mLocalPrefs.GetPref(SI_SHOWOUTLINES_KEY, &g_qeglobals.d_savedinfo.show_outline, FALSE); - mLocalPrefs.GetPref(SI_SHOWAXIS_KEY, &g_qeglobals.d_savedinfo.show_axis, TRUE); - mLocalPrefs.GetPref(SI_NOSELOUTLINES_KEY, &g_qeglobals.d_savedinfo.bNoSelectedOutlines, FALSE); - - mLocalPrefs.GetPref(SI_OUTLINESTYLE_KEY, &g_qeglobals.d_savedinfo.iSelectedOutlinesStyle, OUTLINE_ZBUF|OUTLINE_BSEL); - - LoadTexdefPref(&g_qeglobals.d_savedinfo.m_SIIncrement, SI_SURFACE_TEXDEF_KEY); - LoadTexdefPref(&g_qeglobals.d_savedinfo.m_PIIncrement, SI_PATCH_TEXDEF_KEY); - - // text editor binding -#ifdef _WIN32 - mLocalPrefs.GetPref(CUSTOMSHADEREDITOR_KEY, &m_bUseWin32Editor, TRUE); -#else - mLocalPrefs.GetPref(CUSTOMSHADEREDITOR_KEY, &m_bUseCustomEditor, FALSE); - mLocalPrefs.GetPref(CUSTOMSHADEREDITORCOMMAND_KEY, &m_strEditorCommand, ""); -#endif - - - vec3_t vDefaultAxisColours[3] = { - {0.f, 0.5f, 0.f}, - {0.f, 0.f, 1.f}, - {1.f, 0.f, 0.f}, - }; - - for(i = 0; i < 3; i++) { - char buf[64]; - sprintf(buf, "%s%d", SI_AXISCOLORS_KEY, i); - mLocalPrefs.GetPref(buf, g_qeglobals.d_savedinfo.AxisColors[i], vDefaultAxisColours[i]); - } - - vec3_t vDefaultColours[COLOR_LAST] = { - {0.25f, 0.25f, 0.25f}, - {1.f, 1.f, 1.f}, - {0.75f, 0.75f, 0.75f}, - {0.5f, 0.5f, 0.5f}, - {0.25f, 0.25f, 0.25f}, - {0.0f, 0.0f, 0.0f}, - {0.f, 0.f, 1.f}, - {0.f, 0.f, 0.f}, - {0.f, 0.f, 0.f}, - {1.f, 0.f, 0.f}, - {0.f, 0.f, 1.f}, - {0.5f, 0.f, 0.75f}, - {1.0f, 0.f, 0.f}, - {0.f, 0.f, 0.f}, - {0.f, 0.f, 0.f}, - }; - - for(i = 0; i < COLOR_LAST; i++) { - char buf[64]; - sprintf(buf, "%s%d", SI_COLORS_KEY, i); - mLocalPrefs.GetPref(buf, g_qeglobals.d_savedinfo.colors[i], vDefaultColours[i]); - } - - mLocalPrefs.GetPref(TEXTURECOMPRESSIONFORMAT_KEY, &m_nTextureCompressionFormat, 1); - - mLocalPrefs.GetPref(LIGHTRADIUS_KEY, &m_nLightRadiuses, TRUE); - - mLocalPrefs.GetPref(Q3MAP2TEX_KEY, &m_bQ3Map2Texturing, TRUE); - -#ifdef ATIHACK_812 - mLocalPrefs.GetPref(ATIHACK_KEY, &m_bGlATIHack, FALSE); -#endif - - Undo_SetMaxSize(m_nUndoLevels); // set it internally as well / FIXME: why not just have one global value? - - UpdateTextureCompression(); - -#ifdef ATIHACK_812 - UpdateATIHack(); -#endif - - if (mLocalPrefs.mbEmpty) - { - mLocalPrefs.mbEmpty = false; - Sys_Printf("Saving local.pref with default pref values\n"); - SavePrefs(); - } -} - -void PrefsDlg::SavePrefs () -{ - if (g_qeglobals.disable_ini) - return; - -#ifdef _DEBUG - Sys_Printf("PrefsDlg::SavePrefs\n"); -#endif - - // this will take care of copying back from the dialog to the variables - // NOTE: it may be overkill to call systematically before a SavePrefs, but it's safer - // this will also cause an UpdateData for the mGamesDialog - UpdateData(TRUE); - - mGamesDialog.SavePrefs(); - - // update the tree and save it - mLocalPrefs.UpdatePrefTree(); - if (!mLocalPrefs.WriteXMLFile(m_inipath->str)) - Sys_FPrintf(SYS_ERR, "Error occured while saving local prefs file '%s'\n", m_inipath->str); - - if (m_nMouse == 0) - m_nMouseButtons = 2; - else - m_nMouseButtons = 3; - -} - -void PrefsDlg::PostModal (int code) -{ - if (code == IDOK) - { - SavePrefs(); - // make sure the logfile is ok - Sys_LogFile(); - #ifdef ATIHACK_812 - UpdateATIHack(); - #endif - if (g_pParentWnd) - g_pParentWnd->SetGridStatus(); - Sys_UpdateWindows(W_ALL); - if (m_nUndoLevels != 0) - Undo_SetMaxSize(m_nUndoLevels); - } -} - -void PrefsDlg::DoEditorSensitivity() -{ - if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g_object_get_data (G_OBJECT(m_pWidget), "check_customeditor")))) - { - gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data (G_OBJECT(m_pWidget), "label_customeditor")), TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data (G_OBJECT(m_pWidget), "entry_customeditor")), TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data (G_OBJECT(m_pWidget), "button_customeditor")), TRUE); - } - else - { - gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data (G_OBJECT(m_pWidget), "label_customeditor")), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data (G_OBJECT(m_pWidget), "entry_customeditor")), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data (G_OBJECT(m_pWidget), "button_customeditor")), FALSE); - } -} - -void PrefsDlg::DoSensitivity() -{ -#if 0 - // first, look at the project file version ... will monitoring work? - // project files now XML, guaranteed to be at least version 2 - if (0)//IntForKey( g_qeglobals.d_project_entity, "version" ) < 2) - { - if (m_bWarn) - { - Str Msg; - Msg = "The current project file ("; - Msg += g_PrefsDlg.m_strLastProject; - Msg += ") is not at least version 2.\nI need version 2 or above to setup BSP monitoring correctly."; - gtk_MessageBox(m_pWidget, Msg.GetBuffer(), MB_OK ); - - m_bWarn = false; - } - - // go ahead, disable everybuddy - gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_leakstop" )), FALSE ); - gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_monitorbsp" )), FALSE ); - gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_runengine" )), FALSE ); - gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_sleep" )), FALSE ); - } - else - { -#endif -// m_bWarn = true; - - gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_leakstop" )), TRUE ); - gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_monitorbsp" )), TRUE ); - gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_runengine" )), TRUE ); - gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_sleep" )), TRUE ); - - if ( ! gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( g_object_get_data( G_OBJECT(m_pWidget), "check_monitorbsp" ) ) ) ) - { - gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_leakstop" )), FALSE ); - gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_runengine" )), FALSE ); - gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_sleep" )), FALSE ); - } else if (! gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( g_object_get_data( G_OBJECT(m_pWidget), "check_runengine" ) ) ) ) - { - gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_sleep" )), FALSE ); - } -} +/* +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 +*/ + +// +// User preferences +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" +#include +#if defined (__linux__) || defined (__APPLE__) +#include +#include +#include +#include +#include +#endif +#include "missing.h" +#include "gtkmisc.h" + +#ifdef _WIN32 +#include +#define X_OK 0 +#include +#endif + +#define PREF_SECTION "Prefs" +#define INTERNAL_SECTION "Internals" +#define MOUSE_KEY "MouseButtons" +#define WINDOW_KEY "QE4StyleWindows" +#define LAYOUT_KEY "WindowLayout" +#define RUNQ2_KEY "RunQuake2Run" +#define TLOCK_KEY "TextureLock" +#define RLOCK_KEY "RotateLock" +#define LOADLAST_KEY "LoadLast" +#define LOADLASTMAP_KEY "LoadLastMap" +#define LASTPROJ_KEY "LastProject" +#define LASTPROJVER_KEY "LastProjectKey" +#define LASTMAP_KEY "LastMap" +#define FACE_KEY "NewFaceGrab" +#define BSP_KEY "InternalBSP" +#define RCLICK_KEY "NewRightClick" +#define VERTEX_KEY "NewVertex" +#define AUTOSAVE_KEY "Autosave" +#define AUTOSAVETIME_KEY "AutosaveMinutes" +#define PAK_KEY "UsePAK" +#define NEWAPPLY_KEY "ApplyDismissesSurface" +#define HACK_KEY "Gatewayescapehack" +#define TEXTURE_KEY "NewTextureWindowStuff" +#define TINYBRUSH_KEY "CleanTinyBrushes" +#define TINYSIZE_KEY "CleanTinyBrusheSize" +#define SNAPSHOT_KEY "Snapshots" +#define MOVESPEED_KEY "MoveSpeed" +#define ANGLESPEED_KEY "AngleSpeed" +#define SETGAME_KEY "UseSetGame" +#define CAMXYUPDATE_KEY "CamXYUpdate" +#define CAMDRAGMULTISELECT_KEY "CamDragMultiSelect" +#define CAMFREELOOK_KEY "CamFreeLook" +#define CAMINVERSEMOUSE_KEY "CamInverseMouse" +#define CAMDISCRETE_KEY "CamDiscrete" +#define LIGHTDRAW_KEY "NewLightStyle" +#define WHATGAME_KEY "WhichGame" +#define CUBICCLIP_KEY "CubicClipping" +#define CUBICSCALE_KEY "CubicScale" +#define ALTEDGE_KEY "ALTEdgeDrag" +#define FACECOLORS_KEY "FaceColors" +#define SNAPT_KEY "SnapT" +#define XZVIS_KEY "XZVIS" +#define YZVIS_KEY "YZVIS" +#define ZVIS_KEY "ZVIS" +#define SIZEPAINT_KEY "SizePainting" +#define DLLENTITIES_KEY "DLLEntities" +#define DETACHABLEMENUS_KEY "DetachableMenus" +#define PATCHTOOLBAR_KEY "PatchToolBar" +#define WIDETOOLBAR_KEY "WideToolBar" +#define PLUGINTOOLBAR_KEY "PluginToolBar" +#define NOCLAMP_KEY "NoClamp" +#define PREFAB_KEY "PrefabPath" +#define USERINI_KEY "UserINIPath" +#define ROTATION_KEY "Rotation" +#define BUGGYICD_KEY "BuggyICD" +#define CHASEMOUSE_KEY "ChaseMouse" +#define ENTITYSHOW_KEY "EntityShow" +#define TEXTURESCALE_KEY "TextureScale" +#define TEXTURESCROLLBAR_KEY "TextureScrollbar" +#define DISPLAYLISTS_KEY "UseDisplayLists" +#define ANTIALIASEDLINES_KEY "UseAntialiasedPointsAndLines" // Fishman - Add antialiazed points and lines support. 09/03/00 +#define NORMALIZECOLORS_KEY "NormalizeColors" +#define SHADERS_KEY "UseShaders" +#define SWITCHCLIP_KEY "SwitchClipKey" +#define SELWHOLEENTS_KEY "SelectWholeEntitiesKey" +#define TEXTURESUBSET_KEY "UseTextureSubsetLoading" +#define TEXTUREQUALITY_KEY "TextureQuality" +#define SHOWSHADERS_KEY "ShowShaders" +#define SHADERTEST_KEY "ShaderTest" +#define GLLIGHTING_KEY "UseGLLighting" +#define LOADSHADERS_KEY "LoadShaders" +#define NOSTIPPLE_KEY "NoStipple" +#define UNDOLEVELS_KEY "UndoLevels" +#define VERTEXMODE_KEY "VertexSplit" +#define ENGINEPATH_KEY "EnginePath" +#define ENGINE_KEY "Engine" +#define LOGCONSOLE_KEY "LogConsole" +#define SELECTCURVES_KEY "SelectCurves" +#define SELECTMODELS_KEY "SelectModels" +#define SHADERLISTONLY_KEY "ShowShaderlistOnly" +#define WATCHBSP_KEY "WatchBSP" +#define LEAKSTOP_KEY "LeakStop" +#define DOSLEEP_KEY "SleepMode" +#define SUBDIVISIONS_KEY "Subdivisions" +#define CLIPCAULK_KEY "ClipCaulk" +#define PATCHSHOWBOUNDS_KEY "PatchShowBounds" +#define NATIVEGUI_KEY "NativeGUI" +#define STARTONPRIMMON_KEY "StartOnPrimMon" +#define NOSYSMENUPOPUPS_KEY "NoSysMenuPopups" +#define SNAPTTOGRID_KEY "SnapTToGrid" +#define FLOATINGZ_KEY "FloatingZ" +#define TARGETFIX_KEY "TargetFix" +#define GLPOINTWORKAROUND_KEY "GlPointWorkaround" // Gef: Workaround for broken Kyro * gl driver 25-aug-2001 +#define WHEELINC_KEY "WheelMouseInc" +#define PATCHBBOXSEL_KEY "PatchBBoxSel" +#define LASTLIGHTINTENSITY_KEY "LastLightIntensity" +#define CUSTOMSHADEREDITOR_KEY "UseCustomShaderEditor" +#define CUSTOMSHADEREDITORCOMMAND_KEY "CustomShaderEditorCommand" +#define TEXTURECOMPRESSIONFORMAT_KEY "TextureCompressionFormat" +#define LIGHTRADIUS_KEY "LightRadiuses" +#define Q3MAP2TEX_KEY "Q3Map2Tex" +#define ATIHACK_KEY "ATIHack" + +// window stuff +#define ENTITYSPLIT1_KEY "EntitySplit1" +#define ENTITYSPLIT2_KEY "EntitySplit2" +#define POSITIONX_KEY "PositionX" +#define POSITIONY_KEY "PositionY" +#define ENTITYWND_KEY "EntityWnd" +#define MAPINFOWND_KEY "MapInfoDlg" +#define CAMWND_KEY "CamWnd" +#define ZWND_KEY "ZWnd" +#define XYWND_KEY "XYWnd" +#define XZWND_KEY "XZWnd" +#define YZWND_KEY "YZWnd" +#define PATCHWND_KEY "PatchWnd" +#define SURFACEWND_KEY "SurfaceWnd" +#define ENTITYINFOWND_KEY "EntityInfoDlg" +#define WIDTH_KEY "Width" +#define HEIGHT_KEY "Height" +#define ZWIDTH_KEY "ZWidth" +#define XYHEIGHT_KEY "XYHeight" +#define XYWIDTH_KEY "XYWidth" +#define CAMWIDTH_KEY "CamWidth" +#define CAMHEIGHT_KEY "CamHeight" +#define ZFLOATWIDTH_KEY "ZWidthFloating" +#define STATE_KEY "State" + +// menu stuff +#define COUNT_KEY "Count" +#define FILE_KEY "File" + +//saved info +#define SI_TEXMENU_KEY "SI_TexMenu" +#define SI_GAMMA_KEY "SI_Gamma" +#define SI_COLORS_KEY "SI_Colors" +#define SI_EXCLUDE_KEY "SI_Exclude" +#define SI_INCLUDE_KEY "SI_Include" +#define SI_SURFACE_TEXDEF_KEY "SI_SurfaceTexdef" +#define SI_PATCH_TEXDEF_KEY "SI_PatchTexdef" +#define SI_AXISCOLORS_KEY "SI_AxisColors" +#define SI_SHOWNAMES_KEY "SI_ShowNames" +#define SI_SHOWCOORDS_KEY "SI_ShowCoords" +#define SI_SHOWANGLES_KEY "SI_ShowAngles" +#define SI_SHOWOUTLINES_KEY "SI_ShowOutlines" +#define SI_SHOWAXIS_KEY "SI_ShowAxis" +#define SI_NOSELOUTLINES_KEY "SI_NoSelectedOutlines" +#define SI_OUTLINESTYLE_KEY "SI_OutLineStyle" + +//for texdefs +#define TD_SCALE1_KEY "_Scale1" +#define TD_SCALE2_KEY "_Scale2" +#define TD_SHIFT1_KEY "_Shift1" +#define TD_SHIFT2_KEY "_Shift2" +#define TD_ROTATE_KEY "_Rotate" + +#define MOUSE_DEF 1 +#define WINDOW_DEF 0 +#define RUNQ2_DEF 0 +#define WATCHBSP_DEF 1 +#define TLOCK_DEF 1 +#define LOADLAST_DEF 1 +#define RUN_DEF 0 +#define SUBDIVISIONS_DEF 4 + +void WindowPosition_Parse(window_position_t& m_value, const CString& value) +{ + if(sscanf(value.GetBuffer(), "%d %d %d %d", &m_value.x, &m_value.y, &m_value.w, &m_value.h) != 4) + m_value.x = m_value.y = m_value.w = m_value.h = -1; +} + +void WindowPosition_Write(const window_position_t& m_value, CString& value) +{ + char buffer[64]; + sprintf(buffer, "%d %d %d %d", m_value.x, m_value.y, m_value.w, m_value.h); + value = buffer; +} + + +CXMLPropertyBag::CXMLPropertyBag() { + mStrFilename = ""; + mpDoc = NULL; + mbEmpty = false; +} + +// generic preference functions + +void CXMLPropertyBag::PushAssignment(char *name, PrefTypes_t type, void *pV) +{ + list::iterator iAssign; + for(iAssign=mPrefAssignments.begin(); iAssign!=mPrefAssignments.end(); iAssign++) + { + if ((*iAssign).mName == name) + { + // we have it already, check anyway + if (pV != (*iAssign).mVal) + { + Sys_FPrintf(SYS_ERR, "PushAssignment, '%s' has different mVal\n", name); + return; + } + } + } + // ok, it's not in our list yet + mPrefAssignments.push_front(CPrefAssignment(name, type, pV)); +} + +xmlNodePtr CXMLPropertyBag::EpairForName(const char *name) +{ + xmlNodePtr ret = NULL; + + xmlNodePtr pNode = mpDocNode->children; + while (pNode != NULL) + { + if(pNode->type == XML_ELEMENT_NODE) + { + xmlAttrPtr tmp_attr_ptr = xmlHasProp(pNode, (xmlChar *)"name"); + if (tmp_attr_ptr != NULL && !strcmp(name, (char *)tmp_attr_ptr->children->content)) + { + if ( ret ) { + Sys_FPrintf( SYS_WRN, "WARNING: dupe property in CXMLPropertyBag::EpairForName '%s'\n", name ); + } else { + ret = pNode; + } + } + } + pNode = pNode->next; + } + return ret; +} + +void CXMLPropertyBag::GetPref(char *name, Str *pV, char *V) +{ + xmlNodePtr pNode = EpairForName( name ); + if ( pNode ) + { + if ( pNode->children && pNode->children->content ) { + *pV = pNode->children->content; + } else { + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=427 + // means the pref exists, and that the value is "" + *pV = ""; + } + } + else + { + pNode = xmlNewChild(mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)V); + xmlSetProp(pNode, (xmlChar *)"name", (xmlChar *)name); + } + // push the pref assignment if needed + PushAssignment(name, PREF_STR, pV); +} + +void CXMLPropertyBag::GetPref(char *name, int *pV, int V) +{ + xmlNodePtr pNode; + if ((pNode = EpairForName(name)) && pNode->children && pNode->children->content) + { + *pV = atoi((char *)pNode->children->content); + } + else + { + char s[10]; + sprintf(s, "%d", V); + pNode = xmlNewChild(mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)s); + xmlSetProp(pNode, (xmlChar *)"name", (xmlChar *)name); + *pV=V; + } + // push the pref assignment if needed + PushAssignment(name, PREF_INT, pV); +} + +void CXMLPropertyBag::GetPref(char *name, bool *pV, bool V) +{ + xmlNodePtr pNode; + if ((pNode = EpairForName(name)) && pNode->children && pNode->children->content) + { + if (!strcmp((char *)pNode->children->content, "true")) + { + *pV = true; + } + else + { + *pV = false; + } + } + else + { + char s[10]; + V ? strcpy(s, "true") : strcpy(s, "false"); + pNode = xmlNewChild(mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)s); + xmlSetProp(pNode, (xmlChar *)"name", (xmlChar *)name); + *pV=V; + } + // push the pref assignment + PushAssignment(name, PREF_BOOL, pV); +} + +void CXMLPropertyBag::GetPref(char *name, float *pV, float V) +{ + xmlNodePtr pNode; + if ((pNode = EpairForName(name)) && pNode->children && pNode->children->content) + { + *pV = atof((char *)pNode->children->content); + } + else + { + char s[10]; + sprintf(s, "%f", V); + pNode = xmlNewChild(mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)s); + xmlSetProp(pNode, (xmlChar *)"name", (xmlChar *)name); + *pV=V; + } + // push the pref assignment if needed + PushAssignment(name, PREF_FLOAT, pV); +} + +void CXMLPropertyBag::GetPref(char *name, float* pV, float* V) +{ + xmlNodePtr pNode; + if ((pNode = EpairForName(name)) && pNode->children && pNode->children->content) + { + sscanf((char *)pNode->children->content, "%f %f %f", &pV[0], &pV[1], &pV[2]); + } + else + { + char s[128]; + sprintf(s, "%f %f %f", V[0], V[1], V[2]); + pNode = xmlNewChild(mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)s); + xmlSetProp(pNode, (xmlChar *)"name", (xmlChar *)name); + pV[0] = V[0]; + pV[1] = V[1]; + pV[2] = V[2]; + } + // push the pref assignment if needed + PushAssignment(name, PREF_VEC3, pV); +} + +void CXMLPropertyBag::GetPref(char *name, window_position_t* pV, window_position_t V) +{ + xmlNodePtr pNode; + if ((pNode = EpairForName(name)) && pNode->children && pNode->children->content) + { + WindowPosition_Parse(*pV, CString((xmlChar *)pNode->children->content)); + } + else + { + CString str; + WindowPosition_Write(V, str); + pNode = xmlNewChild(mpDocNode, NULL, (xmlChar *)"epair", (xmlChar *)str.GetBuffer()); + xmlSetProp(pNode, (xmlChar *)"name", (xmlChar *)name); + *pV = V; + } + // push the pref assignment if needed + PushAssignment(name, PREF_WNDPOS, pV); +} + +void CXMLPropertyBag::UpdatePrefTree() +{ + // read the assignments and update the tree + list::iterator iPref; + for(iPref = mPrefAssignments.begin(); iPref != mPrefAssignments.end(); iPref++) + { + CPrefAssignment *pPref = &(*iPref); + // look for the node + xmlNodePtr pNode; + char s[64]; + + pNode = EpairForName(pPref->mName.GetBuffer()); + // we never expect that the node could not be found, because this is supposed to happen + // after the tree was built with GetPref calls, never on a blank tree + if (!pNode) + { + Sys_FPrintf(SYS_ERR, "Unexpected EpairForName '%s' not found in UpdatePrefTree\n", pPref->mName.GetBuffer()); + return; + } + switch ((*iPref).mType) + { + case PREF_STR: + xmlNodeSetContent(pNode, (const xmlChar *)((Str *)pPref->mVal)->GetBuffer()); + break; + case PREF_INT: + sprintf(s, "%d", *(int *)pPref->mVal); + xmlNodeSetContent(pNode, (xmlChar *)s); + break; + case PREF_FLOAT: + sprintf(s, "%f", *(float *)pPref->mVal); + xmlNodeSetContent(pNode, (xmlChar *)s); + break; + case PREF_BOOL: + *(bool *)pPref->mVal ? strcpy(s, "true") : strcpy(s, "false"); + xmlNodeSetContent(pNode, (xmlChar *)s); + break; + case PREF_VEC3: + { + float* v = (float*)pPref->mVal; + sprintf(s, "%f %f %f", v[0], v[1], v[2]); + xmlNodeSetContent(pNode, (xmlChar *)s); + } + break; + case PREF_WNDPOS: + { + CString str; + WindowPosition_Write(*(window_position_t*)pPref->mVal, str); + xmlNodeSetContent(pNode, (xmlChar*)str.GetBuffer()); + } + break; + } + } +} + +void CXMLPropertyBag::Clear() +{ + if(!InUse()) + return; + + xmlFreeDoc(mpDoc); + mpDoc = NULL; + mpDocNode = NULL; + mbEmpty = false; +} + +void CXMLPropertyBag::ReadXMLFile(const char* pFilename) +{ + mpDoc = xmlParseFile(pFilename); + + // basic checks + if (mpDoc) + { + mpDocNode = mpDoc->children; + xmlAttrPtr tmp_attr_ptr = xmlHasProp(mpDocNode, (xmlChar *)"version"); + if (strcmp((char *)mpDocNode->name, "qpref")) + { + Sys_FPrintf(SYS_ERR, "Unrecognized node '%s' in '%s'\n", mpDocNode->name, mpDoc->URL); + xmlFreeDoc(mpDoc); + mpDoc = NULL; + } + else if (tmp_attr_ptr != NULL && strcmp((char*)tmp_attr_ptr->children->content, "1")) + { + Sys_FPrintf(SYS_ERR, "Wrong version '%s' in node for '%s'\n", (char*)tmp_attr_ptr->children->content, mpDoc->URL); + xmlFreeDoc(mpDoc); + mpDoc = NULL; + } + Sys_Printf("Opened XML property file: '%s'\n", pFilename); + } + + if (!mpDoc) + { + mbEmpty = true; + // no document, create one + mpDoc = xmlNewDoc((xmlChar *)"1.0"); + mpDocNode = xmlNewDocNode(mpDoc, NULL, (xmlChar *)"qpref", NULL); + xmlDocSetRootElement(mpDoc, mpDocNode); + xmlSetProp(mpDocNode, (xmlChar *)"version", (xmlChar *)"1"); + Sys_Printf("XML property file '%s' invalid/not found, creating blank properties tree\n", pFilename); + } +} + +qboolean CXMLPropertyBag::WriteXMLFile(const char* pFilename) +{ + int res = xmlSaveFormatFile(pFilename, mpDoc, 1); + + if(res == -1) + return false; + + Sys_Printf("Wrote XML property file '%s'\n", pFilename); + return true; +} + +// ============================================================================= +// Widget callbacks for PrefsDlg + +#if !defined(WIN32) +// browse for custom editor executable +static void OnBtnBrowseEditor (GtkWidget *widget, gpointer data) +{ + PrefsDlg *dlg = (PrefsDlg*)data; + + const char *filename = file_dialog(g_PrefsDlg.GetWidget(), TRUE, "Executable for Custom Editor"); + + if(filename != NULL) + { + dlg->m_strEditorCommand = filename; + dlg->UpdateData(FALSE); + } +} +#endif + +static void OnBtnBrowseprefab (GtkWidget *widget, gpointer data) +{ + PrefsDlg *dlg = (PrefsDlg*)data; + char *path = dlg->m_strPrefabPath; + if (strlen (path) == 0) + path = g_strGameToolsPath; + char *dir = dir_dialog (g_PrefsDlg.GetWidget (), "Set prefab path", path); + dlg->UpdateData(TRUE); + + if (dir != NULL) + { + CString strPath; + strPath = dir; + AddSlash(strPath); + dlg->m_strPrefabPath = strPath; + dlg->UpdateData(FALSE); + free (dir); + } +} + +static void OnBtnBrowseuserini (GtkWidget *widget, gpointer data) +{ + PrefsDlg *dlg = (PrefsDlg*)data; + char *path = dlg->m_strUserPath; + if (strlen (path) == 0) + path = g_strGameToolsPath; + // TODO: INI filter? + const char *filename = file_dialog (g_PrefsDlg.GetWidget(), TRUE, "Find INI file", path); + + if (filename != NULL) + { + dlg->UpdateData(TRUE); + dlg->m_strUserPath = filename; + dlg->UpdateData(FALSE); + } +} + +static void OnButtonClean (GtkWidget *widget, gpointer data) +{ + // make sure this is what the user wants + if (gtk_MessageBox (g_PrefsDlg.GetWidget (), "This will close Radiant and clean the corresponding registry entries.\n" + "Next time you start Radiant it will be good as new. Do you wish to continue?", + "Reset Registry", MB_YESNO) == IDYES) + { + PrefsDlg *dlg = (PrefsDlg*)data; + dlg->EndModal (IDCANCEL); + + g_qeglobals.disable_ini = true; + remove (dlg->m_inipath->str); + char buf[PATH_MAX]; + sprintf(buf, "%sSavedInfo.bin", dlg->m_rc_path->str); + remove(buf); + HandleCommand (NULL, GINT_TO_POINTER (ID_FILE_EXIT)); + _exit (0); + } +} + +// ============================================================================= +// PrefsDlg class + +// IMPORTANT NOTE: the values here don't matter very much +// the actual intialization if you start with an empty .ini is done when loading the prefs for the first time +// profile_load_int takes an argument to use if the value is not found +PrefsDlg::PrefsDlg () +{ + m_bWarn = TRUE; + m_nMouse = 1; + m_nView = MainFrame::eRegular; + m_bLoadLast = FALSE; + m_bInternalBSP = FALSE; + m_bRightClick = FALSE; + m_bSetGame = FALSE; + m_bAutoSave = TRUE; + m_nAutoSave = 5; + m_bLoadLastMap = FALSE; + m_bTextureWindow = FALSE; + m_bSnapShots = FALSE; + m_fTinySize = 0.5; + m_bCleanTiny = FALSE; + m_bCamXYUpdate = TRUE; + m_bCamDragMultiSelect = FALSE; + m_bCamFreeLook = TRUE; + m_bCamFreeLookStrafe = FALSE; + m_bCamInverseMouse = FALSE; + m_bCamDiscrete = TRUE; + m_bNewLightDraw = FALSE; + m_strPrefabPath = ""; + m_nWhatGame = 0; + m_bALTEdge = FALSE; + m_bFaceColors = FALSE; + m_bXZVis = FALSE; + m_bYZVis = FALSE; + m_bZVis = FALSE; + m_bSizePaint = FALSE; + m_bDLLEntities = FALSE; +#ifdef _WIN32 + m_bDetachableMenus = FALSE; // Most win32 users will find detachable menus annoying +#else + m_bDetachableMenus = TRUE; // Linux/Apple users are used to them... +#endif + m_bPatchToolbar = TRUE; + m_bWideToolbar = TRUE; + m_bPluginToolbar = TRUE; + m_bNoClamp = FALSE; + m_strUserPath = ""; + m_nRotation = 0; + m_bChaseMouse = FALSE; + m_bTextureScrollbar = TRUE; + m_bDisplayLists = TRUE; + m_bAntialiasedPointsAndLines = FALSE; // Fishman - Add antialiazed points and lines support. 09/03/00 + m_bShowShaders = FALSE; + m_nShader = -1; + m_bNoStipple = FALSE; + m_bVertexSplit = FALSE; + m_bSelectCurves = TRUE; + m_bSelectModels = TRUE; + m_nEntityShowState = ENTITY_SKINNED_BOXED; + m_nTextureScale = 2; + m_bSwitchClip = FALSE; + m_bSelectWholeEntities = TRUE; + m_nTextureQuality = 3; + m_bShowShaders = TRUE; + m_bGLLighting = FALSE; + m_nShader = 0; + m_nUndoLevels = 30; + m_bTexturesShaderlistOnly = FALSE; + // paths to ini files + m_rc_path = NULL; + m_inipath = NULL; + m_bWatchBSP = TRUE; + m_bLeakStop = TRUE; + m_iTimeout = 15; + m_bRunQuake = TRUE; + m_bDoSleep = FALSE; + m_nSubdivisions = 4; + // not prefs + m_bFloatingZ = FALSE; + m_bGlPtWorkaround = FALSE; // Gef: Kyro/GL_POINTS workaround 25-aug-2001 +#ifdef _WIN32 + m_bNativeGUI = FALSE; + m_bStartOnPrimMon = FALSE; +#endif + m_global_rc_path = NULL; +#ifdef _WIN32 + m_bUseWin32Editor = TRUE; +#else + // custom shader editor options + m_bUseCustomEditor = FALSE; + m_strEditorCommand = ""; +#endif + m_nLightRadiuses = 1; + m_bQ3Map2Texturing = TRUE; +#ifdef ATIHACK_812 + m_bGlATIHack = FALSE; +#endif +} + +/*! +========================================================= +Games selection dialog +========================================================= +*/ + +CGameDescription::CGameDescription(xmlDocPtr pDoc, const Str &GameFile) +{ + char *p, *prop; + mpDoc = pDoc; + // read the user-friendly game name + xmlNodePtr pNode = mpDoc->children; + + while (strcmp((const char*)pNode->name, "game") && pNode != NULL) pNode=pNode->next; + if (!pNode) + { + ///< \todo add the file name (this node and gametools should all be part of CGameDescription anyway) + Error("Didn't find 'game' node in the game description file '%s'\n", pDoc->URL); + } + // on win32, game tools path can now be specified relative to the exe's cwd + prop = (char*)xmlGetProp( pNode, (xmlChar*)"gametools" ); + if ( prop == NULL ) { + Error( "Didn't find 'gametools' node in the game description file '%s'\n", pDoc->URL ); + } + { + char full[PATH_MAX]; +#ifdef _WIN32 + _fullpath( full, prop, PATH_MAX ); +#else + strncpy( full, prop, PATH_MAX ); +#endif + xmlFree( prop ); + prop = NULL; + for ( p = full; *p != '\0'; p++ ) { + if ( *p == '\\' ) { + *p = '/'; + } + mGameToolsPath = full; + if ( p != full && *(p-1) != '/' ) { + mGameToolsPath += "/"; + } + } + } + + prop = (char*)xmlGetProp(pNode, (xmlChar*)"name"); + if (prop == NULL) + { + Sys_FPrintf(SYS_WRN, "Warning, 'name' attribute not found in '%s'\n", pDoc->URL); + mGameName = pDoc->URL; + } + else + { + mGameName = prop; + xmlFree(prop); + } + + mGameFile = GameFile; + + prop = (char*)xmlGetProp(pNode, (xmlChar*)"basegame"); + if (prop == NULL) + { + // default + mBaseGame = "baseq3"; + } + else + { + mBaseGame = prop; + xmlFree(prop); + } + + // on win32, engine path can now be specified relative to the exe's cwd + prop = (char*)xmlGetProp(pNode, (const xmlChar *)"enginepath"); + if ( prop != NULL ) { + char full[PATH_MAX]; +#ifdef _WIN32 + _fullpath( full, prop, PATH_MAX ); +#else + strncpy( full, prop, PATH_MAX ); +#endif + xmlFree( prop ); + prop = NULL; + // process seperators + for ( p = full; *p != '\0'; p++ ) { + if ( *p == '\\' ) { + *p = '/'; + } + } + mEnginePath = full; + if ( p != full && *(p-1) != '/' ) { + mEnginePath += "/"; + } + } + else + { + // if engine path was not specified in the .game, it implies we can guess it from the gametools path + // on win32, and for most game package, the gametools are installed with the game + char aux_path[PATH_MAX]; // aux + strcpy( aux_path, mGameToolsPath.GetBuffer() ); + if ( ( aux_path[ strlen(aux_path)-1 ] == '/' ) || ( aux_path[ strlen(aux_path)-1 ] == '\\' ) ) { + aux_path[strlen(aux_path)-1] = '\0'; // strip ending '/' if any + } + char up_path[PATH_MAX]; // up one level + ExtractFilePath( aux_path, up_path ); + mEnginePath = up_path; + } + + prop = (char*)xmlGetProp(pNode, (xmlChar*)"engine"); + if (prop == NULL) + { +#ifdef _WIN32 + mEngine = "quake3.exe"; +#elif __linux__ + mEngine = "quake3"; +#elif __APPLE__ + mEngine = "Quake3.app"; +#endif + } + else + { + mEngine = prop; + xmlFree(prop); + } + +#if defined (__linux__) || defined (__APPLE__) + // *nix specific + prop = (char*)xmlGetProp(pNode, (const xmlChar *)"prefix"); + if(prop != NULL) + { + mUserPathPrefix = prop; + xmlFree(prop); + } +#endif + mShaderPath = xmlGetProp(pNode, (const xmlChar *)"shaderpath"); + if (!mShaderPath.GetLength()) + { + mShaderPath = "scripts/"; + mShaderlist = "scripts/shaderlist.txt"; + } + else + { + AddSlash(mShaderPath); + mShaderlist = mShaderPath; + mShaderlist += "shaderlist.txt"; + } + xmlChar* default_scale = xmlGetProp(pNode, (const xmlChar *)"default_scale"); + if (default_scale) + { + mTextureDefaultScale = atof((const char *)default_scale); + xmlFree(default_scale); + } + else + mTextureDefaultScale = 0.5f; + xmlChar* eclass_singleload = xmlGetProp(pNode, (const xmlChar*)"eclass_singleload"); + if (eclass_singleload) + { + mEClassSingleLoad = true; + xmlFree(eclass_singleload); + } + else + mEClassSingleLoad = false; + xmlChar* no_patch = xmlGetProp(pNode, (const xmlChar *)"no_patch"); + if (no_patch) + { + mNoPatch = true; + xmlFree(no_patch); + } + else + mNoPatch = false; + xmlChar* caulk_shader = xmlGetProp(pNode, (const xmlChar *)"caulk_shader"); + if (caulk_shader) + { + mCaulkShader = caulk_shader; + xmlFree(caulk_shader); + } + else + mCaulkShader = "textures/common/caulk"; +} + +void CGameDescription::Dump() +{ +#ifdef _WIN32 + if (CGameDialog::GetNetrun()) + Sys_Printf("Running in network mode, prefs path set to '%s'\n", g_strTempPath.GetBuffer()); +#endif + Sys_Printf("game name : '%s'\n", mGameName.GetBuffer()); + Sys_Printf("game file : '%s'\n", mGameFile.GetBuffer()); + Sys_Printf("game path : '%s'\n", mGameToolsPath.GetBuffer()); + Sys_Printf("base game : '%s'\n", mBaseGame.GetBuffer()); + Sys_Printf("engine path : '%s'\n", mEnginePath.GetBuffer()); + Sys_Printf("engine : '%s'\n", mEngine.GetBuffer()); + Sys_Printf("shaderlist : '%s'\n", mShaderlist.GetBuffer()); + Sys_Printf("caulk shader: '%s'\n", mCaulkShader.GetBuffer()); +#if defined (__linux__) || defined (__APPLE__) + Sys_Printf("prefix : '%s'\n", mUserPathPrefix.GetBuffer()); +#endif + Sys_Printf("default texture scale: %g\n", mTextureDefaultScale); + Sys_Printf("single eclass load : %s\n", mEClassSingleLoad ? "Yes" : "No"); + Sys_Printf("patches supported : %s\n", mNoPatch ? "No" : "Yes"); +} + +CPrefAssignment& CPrefAssignment::operator = (const CPrefAssignment& ass) +{ + if (&ass != this) + { + mName = ass.mName; + mType = ass.mType; + mVal = ass.mVal; + } + return *this; +} + +CPrefAssignment::CPrefAssignment(const CPrefAssignment& ass) +{ + *this = ass; +} + +void CGameDialog::LoadPrefs() +{ + bool bEmpty = false; + + // if we already have a document loaded, we will free and reload from file + if (mGlobalPrefs.InUse()) + { + Sys_Printf("Reloading global prefs from file\n"); + mGlobalPrefs.Clear(); + } + + // load global .pref file + CString strGlobalPref = g_PrefsDlg.m_global_rc_path->str; + strGlobalPref += "global.pref"; + + mGlobalPrefs.ReadXMLFile(strGlobalPref.GetBuffer()); + + mGlobalPrefs.GetPref("gamefile", &m_sGameFile, ""); // NOTE: there's no default, user HAS to select something + mGlobalPrefs.GetPref("autoload", &m_bAutoLoadGame, false); + mGlobalPrefs.GetPref("log console", &m_bLogConsole, false); + // in a very particular post-.pid startup + // we may have the console turned on and want to keep it that way + // so we use a latching system + if (m_bForceLogConsole) + { + m_bLogConsole = true; + Sys_Printf("console logging has been latched on, saving prefs\n"); + SavePrefs(); + m_bForceLogConsole = false; + } + + // console logging: call Sys_LogConsole to check console logging status + // it is important that we would log console as early as possible to make it useful + Sys_LogFile(); + + if (mGlobalPrefs.mbEmpty) + { + Sys_Printf("Saving global.pref with default pref values\n"); + SavePrefs(); + } +} + +void CGameDialog::SavePrefs() +{ + // update the tree and save it + mGlobalPrefs.UpdatePrefTree(); + + CString strGlobalPref = g_PrefsDlg.m_global_rc_path->str; + strGlobalPref += "global.pref"; + + if (!mGlobalPrefs.WriteXMLFile(strGlobalPref.GetBuffer())) + Sys_FPrintf(SYS_ERR, "Error occured while saving global prefs file '%s'\n", strGlobalPref.GetBuffer()); +} + +void CGameDialog::DoGameDialog() +{ + // show the UI + DoModal(); + + // unhook so we can use in other places + // we manually incref'ed it when creating, it won't be freed (destructor) + gtk_container_remove (GTK_CONTAINER (mTopBox), GetGlobalFrame()); + + // we save the prefs file + SavePrefs(); +} + +GtkWidget* CGameDialog::GetGlobalFrame() +{ + GtkWidget *vbox, *text, *combo, *check; + + if (mFrame) + return mFrame; + + mFrame = gtk_frame_new(NULL); + gtk_container_set_border_width(GTK_CONTAINER(mFrame), 5); + gtk_widget_show(mFrame); + + vbox = gtk_vbox_new (FALSE, 6); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (mFrame), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + text = gtk_label_new("Select the game:"); + gtk_widget_show(text); + gtk_box_pack_start (GTK_BOX(vbox), text, FALSE, FALSE, 0); + + combo = gtk_combo_new(); + gtk_widget_show(combo); + gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0); + + // fill in with the game descriptions + GList *combo_list = (GList*)NULL; + list::iterator iGame; + for(iGame=mGames.begin(); iGame!=mGames.end(); iGame++) + { + combo_list = g_list_append (combo_list, (void *)(*iGame)->mGameName.GetBuffer()); + } + gtk_combo_set_popdown_strings (GTK_COMBO (combo), combo_list); + g_list_free (combo_list); + + AddDialogData (combo, &m_nComboSelect, DLG_COMBO_INT); + + check = gtk_check_button_new_with_label("Auto load selected game on startup"); + gtk_widget_show(check); + gtk_box_pack_start (GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bAutoLoadGame, DLG_CHECK_BOOL); + + text = gtk_label_new("(this frame is available in the prefs menu if you set auto-select)"); + gtk_widget_show(text); + gtk_box_pack_start (GTK_BOX(vbox), text, FALSE, FALSE, 0); + +#ifdef _WIN32 + check = gtk_check_button_new_with_label("Networked install - per-user settings"); + gtk_widget_show(check); + gtk_box_pack_start (GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bNetRun, DLG_CHECK_BOOL); +#endif + + check = gtk_check_button_new_with_label("Log the console to radiant.log"); + gtk_widget_show(check); + gtk_box_pack_start (GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bLogConsole, DLG_CHECK_BOOL); + + // incref it so we can pass it around + gtk_widget_ref (GTK_WIDGET(mFrame)); + + return mFrame; +} + +void CGameDialog::UpdateData (bool retrieve) +{ + if (!retrieve) + { + // use m_sGameFile to set m_nComboSelect + list::iterator iGame; + int i = 0; + for(iGame=mGames.begin(); iGame!=mGames.end(); iGame++) + { + if ((*iGame)->mGameFile == m_sGameFile) + { + m_nComboSelect = i; + break; + } + i++; + } +#ifdef _WIN32 + UpdateNetrun(false); +#endif + } + Dialog::UpdateData(retrieve); + if (retrieve) + { + // use m_nComboSelect to set m_sGameFile + list::iterator iGame = mGames.begin(); + int i; + for(i=0; imGameFile; +#ifdef _WIN32 + UpdateNetrun(true); +#endif + } +} + +void CGameDialog::BuildDialog() +{ + GtkWidget *dlg, *vbox1, *button; + + dlg = m_pWidget; + gtk_window_set_title (GTK_WINDOW (dlg), "Select Game"); + + vbox1 = gtk_vbox_new (FALSE, 0); + gtk_widget_show(vbox1); + gtk_container_add (GTK_CONTAINER (dlg), vbox1); + + gtk_container_add (GTK_CONTAINER (vbox1), GetGlobalFrame()); + mTopBox = vbox1; + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox1), button, FALSE, FALSE, 0); + AddModalButton(button, IDOK); + gtk_widget_set_usize (button, 60, -2); +} + +void CGameDialog::ScanForGames() +{ + CString strPath; + char *dirlist; + GDir *dir; + CString strGamesPath = g_strAppPath.GetBuffer(); + strGamesPath += "games"; + const char *path = strGamesPath.GetBuffer(); + + Sys_Printf("Scanning for game description files: %s\n", path); + + /*! + \todo FIXME LINUX: + do we put game description files below g_strAppPath, or in ~/.radiant + i.e. read only or read/write? + my guess .. readonly cause it's an install + we will probably want to add ~/.radiant//games/ scanning on top of that for developers + (if that's really needed) + */ + + // FIXME need to catch the 'no game description' situation and exit with a clean error + + dir = g_dir_open(path, 0, NULL); + + if (dir != NULL) + { + while (1) + { + const gchar* name = g_dir_read_name(dir); + if(name == NULL) + break; + + dirlist = g_strdup(name); +#ifdef _WIN32 + strlwr (dirlist); +#endif + char *ext = strrchr (dirlist, '.'); + if ((ext == NULL) || (strcmp (ext, ".game") != 0)) + continue; + strPath.Format("%s/%s", path, dirlist); + Sys_Printf("%s\n", strPath.GetBuffer()); + // got one, load it + xmlDocPtr pDoc = xmlParseFile(strPath.GetBuffer()); + if (pDoc) + { + mGames.push_front(new CGameDescription(pDoc, dirlist)); + } + else + { + Sys_FPrintf(SYS_ERR, "XML parser failed on '%s'\n", strPath.GetBuffer()); + } + + g_free(dirlist); + } + g_dir_close (dir); + } +} + +CGameDescription* CGameDialog::GameDescriptionForComboItem() +{ + list::iterator iGame; + int i=0; + for(iGame=mGames.begin(); iGame!=mGames.end(); iGame++,i++) + { + if (i == m_nComboSelect) + { + return (*iGame); + } + } + return NULL; // not found +} + +/*GString* CGameDialog::InitGlobalPrefPath() +{ + GString* global_rc_path; + // configure m_global_rc_path +#if defined (__linux__) || defined (__APPLE__) + global_rc_path = g_string_new (g_get_home_dir ()); + + if (global_rc_path->str[global_rc_path->len-1] != '/') + g_string_append (global_rc_path, "/"); + + g_string_append (global_rc_path, ".radiant/"); + mkdir (global_rc_path->str, 0775); + g_string_append (global_rc_path, RADIANT_VERSION); + g_string_append (global_rc_path, "/"); + mkdir (global_rc_path->str, 0775); +#elif WIN32 + global_rc_path = g_string_new (g_strAppPath.GetBuffer() ); +#else +#error "WTF are you compiling under" +#endif + return global_rc_path; +}*/ + +void CGameDialog::InitGlobalPrefPath() +{ + GString *global_rc_path; + // configure m_global_rc_path + // this is the g_strTempPath, and it has already been mkdir'ed + global_rc_path = g_string_new(g_strTempPath.GetBuffer()); + g_PrefsDlg.m_global_rc_path = global_rc_path; +} + +void CGameDialog::Reset() +{ + if (!g_PrefsDlg.m_global_rc_path) + InitGlobalPrefPath(); + CString strGlobalPref = g_PrefsDlg.m_global_rc_path->str; + strGlobalPref += "global.pref"; + remove(strGlobalPref.GetBuffer()); +} + +void CGameDialog::Init() +{ + InitGlobalPrefPath(); + ScanForGames(); + if (mGames.empty()) + { + Error("Didn't find any valid game file descriptions, aborting\n"); + } + LoadPrefs(); + if (m_bAutoLoadGame) + { + // search by .game name + list::iterator iGame; + for(iGame=mGames.begin(); iGame!=mGames.end(); iGame++) + { + if ((*iGame)->mGameFile == m_sGameFile) + { + m_pCurrentGameDescription = (*iGame); + break; + } + } + } + if (!m_bAutoLoadGame || !m_pCurrentGameDescription) + { + DoGameDialog(); + // use m_nComboSelect to identify the game to run as and set the globals + m_pCurrentGameDescription = GameDescriptionForComboItem(); + if (!m_pCurrentGameDescription) + Error("Lookup of game description object failed, can't continue\n"); + } + g_pGameDescription = m_pCurrentGameDescription; + + g_strGameToolsPath = g_pGameDescription->mGameToolsPath; + + // NOTE TTimo: this is moved from QE_LoadProject in 1.2 + // (probably broken) + // NOTE Hydra: was broken for win32, we don't use m_strHomeGame or m_strFSBasePath +#if defined (__linux__) || defined (__APPLE__) + g_qeglobals.m_strHomeGame = g_get_home_dir(); + g_qeglobals.m_strHomeGame += "/"; + g_qeglobals.m_strHomeGame += m_pCurrentGameDescription->mUserPathPrefix.GetBuffer(); + g_qeglobals.m_strHomeGame += "/"; +#else + g_qeglobals.m_strHomeGame = g_pGameDescription->mEnginePath.GetBuffer(); +#endif + + g_pGameDescription->Dump(); +} + +CGameDialog::~CGameDialog() +{ + if (mFrame) + { + // NOTE I'm not too sure how reliable this is + gtk_widget_unref(GTK_WIDGET(mFrame)); + } + // free all the game descriptions + list::iterator iGame; + for(iGame=mGames.begin(); iGame!=mGames.end(); iGame++) + { + delete (*iGame); + *iGame = NULL; + } +} + +void CGameDialog::AddPacksURL(Str &URL) +{ + // add the URLs for the list of game packs installed + // FIXME: this is kinda hardcoded for now.. + list::iterator iGame; + for(iGame=mGames.begin(); iGame!=mGames.end(); iGame++) + { + if ((*iGame)->mGameFile == "q3.game") + URL += "&Games_dlup%5B%5D=1"; + else if ((*iGame)->mGameFile == "wolf.game") + URL += "&Games_dlup%5B%5D=2"; + else if ((*iGame)->mGameFile == "wolf.game") + URL += "&Games_dlup%5B%5D=3"; + else if ((*iGame)->mGameFile == "jk2.game") + URL += "&Games_dlup%5B%5D=4"; + else if ((*iGame)->mGameFile == "stvef.game") + URL += "&Games_dlup%5B%5D=5"; + else if ((*iGame)->mGameFile == "sof2.game") + URL += "&Games_dlup%5B%5D=6"; + else if ((*iGame)->mGameFile == "ja.game") + URL += "&Games_dlup%5B%5D=7"; + } +} + +#ifdef _WIN32 + +#define NETRUN_FILENAME "netrun.conf" + +bool CGameDialog::m_bNetRun; + +void CGameDialog::UpdateNetrun(bool retrieve) +{ + FILE *f_netrun; + CString strNetrun; + strNetrun = g_strAppPath; strNetrun += NETRUN_FILENAME; + if (!retrieve) + { + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=639 + // now check if we are running from a network installation + // use a dummy file as the flag + f_netrun = fopen(strNetrun.GetBuffer(), "r"); + if (f_netrun) + { + fclose(f_netrun); + m_bNetRun = true; + } + else + m_bNetRun = false; + } + else + { + if (m_bNetRun) + { + f_netrun = fopen(strNetrun.GetBuffer(), "w"); + if (!f_netrun) + { + Sys_FPrintf(SYS_ERR, "ERROR: Failed to create netrun file '%s'\n", strNetrun.GetBuffer()); + m_bNetRun = false; + } + else + { + fclose(f_netrun); + Sys_Printf("Created/Checked '%s'\n", strNetrun.GetBuffer()); + } + } + else + { + if (remove(strNetrun.GetBuffer()) == -1) + { + if (errno != ENOENT) + Sys_FPrintf(SYS_ERR, "Failed to remove netrun file '%s'\n", strNetrun.GetBuffer()); + m_bNetRun = true; + } + else + { + Sys_Printf("Netrun mode is disabled\n"); + } + } + } +} + +bool CGameDialog::GetNetrun() +{ + return m_bNetRun; +} +#endif + +/* +======== + +very first prefs init deals with selecting the game and the game tools path +then we can load .ini stuff + +using prefs / ini settings: +those are per-game + +win32: +look in g_strGameToolsPath for .ini + +linux: +look in ~/.radiant//gamename +======== +*/ + +#define PREFS_LOCAL_FILENAME "local.pref" + +void PrefsDlg::Init() +{ + mGamesDialog.Init(); + + // m_global_rc_path has been set above, do m_rc_path with game specific stuff now + // the win32 and linux versions have been unified for network mode +#ifdef _WIN32 + if (!CGameDialog::GetNetrun()) + { + // legacy prefs settings, this goes where the game pack is installed + m_rc_path = g_string_new (g_strGameToolsPath.GetBuffer() ); + m_inipath = g_string_new (m_rc_path->str); + g_string_append (m_inipath, PREFS_LOCAL_FILENAME); + return; + } +#endif + // this is common to win32 and Linux init now + m_rc_path = g_string_new (m_global_rc_path->str); + + // game sub-dir + g_string_append (m_rc_path, g_pGameDescription->mGameFile.GetBuffer()); + g_string_append (m_rc_path, "/"); + Q_mkdir (m_rc_path->str, 0775); + + // then the ini file + m_inipath = g_string_new (m_rc_path->str); + g_string_append (m_inipath, PREFS_LOCAL_FILENAME); + +} + +void PrefsDlg::UpdateData (bool retrieve) +{ + // leo: the "changed" signal confuses the update function + if (m_pWidget == NULL) + return; + mGamesDialog.UpdateData (retrieve); + Dialog::UpdateData (retrieve); +} + +#ifdef _WIN32 +#define PREFSHSPACE 5 +#else +#define PREFSHSPACE 0 +#endif + +static void UpdateSensitivity( GtkWidget *widget, gpointer data ) +{ + PrefsDlg *dlg = (PrefsDlg*)data; + dlg->DoSensitivity(); +} + +static void UpdateEditorSensitivity(GtkWidget *widget, gpointer data) +{ + PrefsDlg *dlg = (PrefsDlg*)data; + dlg->DoEditorSensitivity(); +} + +// start new prefs dialog + +/*! Utility function for swapping notebook pages for tree list selections */ +void PrefsDlg::showPrefPage(int prefpage) +{ + if(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)) != prefpage) + gtk_notebook_set_page(GTK_NOTEBOOK(notebook), prefpage); + + return; +} + +static void treeSelection(GtkTreeSelection* selection, gpointer data) +{ + PrefsDlg *dlg = (PrefsDlg*)data; + + GtkTreeModel* model; + GtkTreeIter selected; + if(gtk_tree_selection_get_selected(selection, &model, &selected)) + { + int prefpage; + gtk_tree_model_get(model, &selected, 1, (gpointer*)&prefpage, -1); + dlg->showPrefPage(prefpage); + } +} + +void PrefsDlg::BuildDialog () +{ + // Main Preferences dialog + GtkWidget *dialog, *mainvbox, *hbox, *sc_win, *preflabel; + + // Widgets on notebook pages + GtkWidget *check, *label, *scale, *hbox2, *combo, + *table, *spin, *entry, *pixmap, + *radio, *button, *pageframe, *vbox; + + GList *combo_list = (GList*)NULL; + + GtkObject *adj; + + dialog = m_pWidget; + gtk_window_set_title(GTK_WINDOW(dialog), "GtkRadiant Preferences"); + gtk_widget_realize(dialog); + + mainvbox = gtk_vbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(dialog), mainvbox); + gtk_container_set_border_width(GTK_CONTAINER(mainvbox), 5); + gtk_widget_show(mainvbox); + + hbox = gtk_hbox_new(FALSE, 5); + gtk_widget_show(hbox); + gtk_box_pack_end(GTK_BOX(mainvbox), hbox, FALSE, TRUE, 0); + + button = gtk_button_new_with_label("OK"); + gtk_widget_show(button); + gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0); + gtk_widget_set_usize(button, 60, -2); + AddModalButton(button, IDOK); + + button = gtk_button_new_with_label("Cancel"); + gtk_widget_show(button); + gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0); + gtk_widget_set_usize(button, 60, -2); + AddModalButton (button, IDCANCEL); + + button = gtk_button_new_with_label ("Clean"); + gtk_widget_show(button); + gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(OnButtonClean), this); + gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); + gtk_widget_set_usize (button, 60, -2); + + hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(mainvbox), hbox, TRUE, TRUE, 0); + gtk_widget_show(hbox); + + sc_win = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sc_win), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_box_pack_start(GTK_BOX(hbox), sc_win, FALSE, FALSE, 0); + gtk_widget_show(sc_win); + + // prefs pages notebook + notebook = gtk_notebook_new(); + // hide the notebook tabs since its not supposed to look like a notebook + gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE); + gtk_box_pack_start(GTK_BOX(hbox), notebook, TRUE, TRUE, 0); + gtk_widget_show(notebook); + + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sc_win), GTK_SHADOW_IN); + + { + GtkTreeStore* store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER); + + GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); + + { + GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Preferences", renderer, "text", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); + } + + { + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); + g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(treeSelection), this); + } + + gtk_widget_show(view); + + gtk_container_add(GTK_CONTAINER (sc_win), view); + + { + /********************************************************************/ + /* Add preference tree options */ + /********************************************************************/ + { + GtkTreeIter group; + gtk_tree_store_append(store, &group, NULL); + gtk_tree_store_set(store, &group, 0, "Globals", 1, PTAB_FRONT, -1); + { + GtkTreeIter tab; + gtk_tree_store_append(store, &tab, &group); + gtk_tree_store_set(store, &tab, 0, "Game settings", 1, (gpointer)PTAB_GAME_SETTINGS, -1); + } + } + + { + GtkTreeIter group; + gtk_tree_store_append(store, &group, NULL); + gtk_tree_store_set(store, &group, 0, "Display", 1, PTAB_FRONT, -1); + { + GtkTreeIter tab; + gtk_tree_store_append(store, &tab, &group); + gtk_tree_store_set(store, &tab, 0, "2D Display/Rendering", 1, (gpointer)PTAB_2D, -1); + } + { + GtkTreeIter tab; + gtk_tree_store_append(store, &tab, &group); + gtk_tree_store_set(store, &tab, 0, "3D View", 1, (gpointer)PTAB_CAMERA, -1); + } + { + GtkTreeIter tab; + gtk_tree_store_append(store, &tab, &group); + gtk_tree_store_set(store, &tab, 0, "Texture Settings", 1, (gpointer)PTAB_TEXTURE, -1); + } + } + + { + GtkTreeIter group; + gtk_tree_store_append(store, &group, NULL); + gtk_tree_store_set(store, &group, 0, "Interface", 1, PTAB_FRONT, -1); + { + GtkTreeIter tab; + gtk_tree_store_append(store, &tab, &group); + gtk_tree_store_set(store, &tab, 0, "Layout", 1, (gpointer)PTAB_LAYOUT, -1); + } + { + GtkTreeIter tab; + gtk_tree_store_append(store, &tab, &group); + gtk_tree_store_set(store, &tab, 0, "Mouse", 1, (gpointer)PTAB_MOUSE, -1); + } + { + GtkTreeIter tab; + gtk_tree_store_append(store, &tab, &group); + gtk_tree_store_set(store, &tab, 0, "Editing", 1, (gpointer)PTAB_EDITING, -1); + } + } + + { + GtkTreeIter group; + gtk_tree_store_append(store, &group, NULL); + gtk_tree_store_set(store, &group, 0, "Other", 1, PTAB_FRONT, -1); + { + GtkTreeIter tab; + gtk_tree_store_append(store, &tab, &group); + gtk_tree_store_set(store, &tab, 0, "Startup/Auto save", 1, (gpointer)PTAB_STARTUP, -1); + } + { + GtkTreeIter tab; + gtk_tree_store_append(store, &tab, &group); + gtk_tree_store_set(store, &tab, 0, "Paths", 1, (gpointer)PTAB_PATHS, -1); + } + { + GtkTreeIter tab; + gtk_tree_store_append(store, &tab, &group); + gtk_tree_store_set(store, &tab, 0, "Misc", 1, (gpointer)PTAB_MISC, -1); + } + if (!g_qeglobals.bBSPFrontendPlugin) + { + GtkTreeIter tab; + gtk_tree_store_append(store, &tab, &group); + gtk_tree_store_set(store, &tab, 0, "BSP Monitoring", 1, (gpointer)PTAB_BSPMONITOR, -1); + } + } + } + + gtk_tree_view_expand_all(GTK_TREE_VIEW(view)); + + g_object_unref(G_OBJECT(store)); + } + + /**********************************************************************/ + /* build the prefs pages */ + /**********************************************************************/ + + // Front page... + // todo : add something interesting here + // NOTE TTimo: tip of the day? or a logo? + preflabel = gtk_label_new("Front Page"); + gtk_widget_show(preflabel); + pageframe = gtk_frame_new(NULL); + gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); + gtk_widget_show(pageframe); + vbox = gtk_vbox_new(FALSE, 5); + gtk_widget_show(vbox); + gtk_widget_set_usize(GTK_WIDGET(vbox), 350, -2); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(pageframe), vbox); + + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + /******** global preferences group ****************************/ + preflabel = gtk_label_new("Globals"); + gtk_widget_show(preflabel); + + pageframe = mGamesDialog.GetGlobalFrame(); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + /******** 2D prefs group (xy views/rendering options) *********/ + preflabel = gtk_label_new("2D Display"); + gtk_widget_show(preflabel); + pageframe = gtk_frame_new("2D Display"); + gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); + gtk_widget_show(pageframe); + vbox = gtk_vbox_new(FALSE, 5); + gtk_widget_show(vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(pageframe), vbox); + + // OpenGL Display Lists + check = gtk_check_button_new_with_label("OpenGL Display Lists"); + gtk_widget_show(check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData(check, &m_bDisplayLists, DLG_CHECK_BOOL); + + // Antialiased points & lines + // Fishman - Add antialiazed points and lines support. 09/03/00 + check = gtk_check_button_new_with_label ("OpenGL antialiased points and lines"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bAntialiasedPointsAndLines, DLG_CHECK_BOOL); + + // Solid selection boxes + check = gtk_check_button_new_with_label ("Solid selection boxes"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bNoStipple, DLG_CHECK_BOOL); + + // Display size info + check = gtk_check_button_new_with_label ("Display size info"); + gtk_widget_show (check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bSizePaint, DLG_CHECK_BOOL); + + // Alternate vertex/edge handles + // Gef: Kyro GL_POINT work around 25-aug-2001 + check = gtk_check_button_new_with_label ("Alternate vertex/edge handles"); + gtk_widget_show(check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData(check, &m_bGlPtWorkaround, DLG_CHECK_BOOL); + + g_list_free (combo_list); + +#ifdef ATIHACK_812 + // ATI bugs + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=812 + check = gtk_check_button_new_with_label ("ATI cards with broken drivers - bug #802"); + gtk_widget_show(check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData(check, &m_bGlATIHack, DLG_CHECK_BOOL); +#endif + + // Add the page to the notebook + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + /******** 3D Camera view group *********/ + preflabel = gtk_label_new("3D View"); + gtk_widget_show(preflabel); + pageframe = gtk_frame_new("3D View"); + gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); + gtk_widget_show(pageframe); + vbox = gtk_vbox_new(FALSE, 5); + gtk_widget_show(vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(pageframe), vbox); + + // Directional velocity (Movement Velocity) + // label container + hbox2 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 0); + + // label + label = gtk_label_new("Movement Velocity"); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_widget_show(label); + gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0); + + // adjustment + adj = gtk_adjustment_new(100, 50, 300, 1, 10, 10); + AddDialogData(adj, &m_nMoveSpeed, DLG_ADJ_INT); + + // scale + scale = gtk_hscale_new(GTK_ADJUSTMENT(adj)); + gtk_widget_show(scale); + gtk_box_pack_start(GTK_BOX (vbox), scale, FALSE, TRUE, 2); + + gtk_scale_set_draw_value (GTK_SCALE (scale), TRUE); + + // Angular velocity (Rotational Velocity) + // label container + hbox2 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 0); + + // label + label = gtk_label_new ("Rotational Velocity"); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_widget_show (label); + gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0); + + // adjustment + adj = gtk_adjustment_new (3, 1, 180, 1, 10, 10); // value, low, high, step, page_step, page_size + AddDialogData (adj, &m_nAngleSpeed, DLG_ADJ_INT); + + // scale + scale = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (scale); + gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, TRUE, 2); + gtk_scale_set_draw_value (GTK_SCALE (scale), TRUE); + + // Text under the velocity sliders + // container + hbox2 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 0); + + // label + label = gtk_label_new ("slow"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); + + // label + label = gtk_label_new ("fast"); + gtk_widget_show (label); + gtk_box_pack_end (GTK_BOX (hbox2), label, FALSE, FALSE, 0); + + // Allow drag to select multiple faces/brushes + // container + table = gtk_table_new(2, 1, FALSE); + gtk_widget_show(table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Use paint-select in camera view:"); + gtk_widget_show (label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + combo_list = NULL; + combo_list = g_list_append (combo_list, (void *)"No"); + combo_list = g_list_append (combo_list, (void *)"Yes"); + combo_list = g_list_append (combo_list, (void *)"Yes (Classic Key Setup)"); + + combo = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (combo), combo_list); + gtk_widget_show (combo); + gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE); + AddDialogData (combo, &m_nCamDragMultiSelect, DLG_COMBO_INT); + + // Freelook in Camera view + check = gtk_check_button_new_with_label ("Freelook in Camera view"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (GTK_BIN (check)->child), GTK_JUSTIFY_LEFT); + AddDialogData (check, &m_bCamFreeLook, DLG_CHECK_BOOL); + + // Freelook in Camera view w/ forward & back strafing instead of up and down looking + check = gtk_check_button_new_with_label ("Freelook strafes Forward and Back"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (GTK_BIN (check)->child), GTK_JUSTIFY_LEFT); + AddDialogData (check, &m_bCamFreeLookStrafe, DLG_CHECK_BOOL); + + // Invert mouse in freelook + check = gtk_check_button_new_with_label ("Invert mouse in freelook"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (GTK_BIN (check)->child), GTK_JUSTIFY_LEFT); + AddDialogData (check, &m_bCamInverseMouse, DLG_CHECK_BOOL); + + // Discrete movement + check = gtk_check_button_new_with_label ("Discrete movement"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (GTK_BIN (check)->child), GTK_JUSTIFY_LEFT); + AddDialogData (check, &m_bCamDiscrete, DLG_CHECK_BOOL); + + // Update XY views on camera move + check = gtk_check_button_new_with_label ("Update XY views on camera move"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (GTK_BIN (check)->child), GTK_JUSTIFY_LEFT); + AddDialogData (check, &m_bCamXYUpdate, DLG_CHECK_BOOL); + + // Add the page to the notebook + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + /******** Texture group *********/ + preflabel = gtk_label_new("Textures"); + gtk_widget_show(preflabel); + pageframe = gtk_frame_new("Textures"); + gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); + gtk_widget_show(pageframe); + vbox = gtk_vbox_new(FALSE, 6); + gtk_widget_show(vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(pageframe), vbox); + + // Texture quality slider + // label + label = gtk_label_new ("Texture quality"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + // adjustment + adj = gtk_adjustment_new (0, 0, 4, 1, 1, 1); + AddDialogData (adj, &m_nLatchedTextureQuality, DLG_ADJ_INT); + + // scale + scale = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (scale); + gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0); + gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE); + + // text under the texture slider + hbox2 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 0); + label = gtk_label_new ("low"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); + label = gtk_label_new ("high"); + gtk_widget_show (label); + gtk_box_pack_end (GTK_BOX (hbox2), label, FALSE, FALSE, 0); + + // texture subsets + check = gtk_check_button_new_with_label ("Texture subsets"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bTextureWindow, DLG_CHECK_BOOL); + + // texture scrollbar + check = gtk_check_button_new_with_label ("Texture scrollbar"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bTextureScrollbar, DLG_CHECK_BOOL); + + // texture increment matches grid + check = gtk_check_button_new_with_label ("Tex increment matches grid"); + gtk_widget_show (check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bSnapTToGrid, DLG_CHECK_BOOL); + + // RIANT + // Texture compression choice label + // container + table = gtk_table_new(2, 1, FALSE); + gtk_widget_show(table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Texture Compression (if available):"); + gtk_widget_show (label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + // Texture compression choice label + combo_list = NULL; + // NONE will always be in pos 0 + combo_list = g_list_append (combo_list, (void *)"None"); + + // if OpenGL compression is enabled it will always be + // in pos 1 + if (g_qeglobals.m_bOpenGLCompressionSupported) + { + combo_list = g_list_append (combo_list, (void *)"OpenGL ARB"); + } + + // If S3 is enabled offer all 3 valid compression schemes in RGBA + if (g_qeglobals.m_bS3CompressionSupported) + { + combo_list = g_list_append (combo_list, (void *)"S3TC DXT1"); + combo_list = g_list_append (combo_list, (void *)"S3TC DXT3"); + combo_list = g_list_append (combo_list, (void *)"S3TC DXT5"); + } + + combo = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (combo), combo_list); + gtk_widget_show (combo); + gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE); + AddDialogData (combo, &m_nTextureCompressionFormat, DLG_COMBO_INT); + g_list_free (combo_list); + + // container + table = gtk_table_new(2, 1, FALSE); + gtk_widget_show(table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + // Startup shaders + // label + label = gtk_label_new ("Startup Shaders:"); + gtk_widget_show (label); + gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + // combo list + combo_list = NULL; + combo_list = g_list_append (combo_list, (void *)"None"); + if (g_pGameDescription->mGameFile == "jk2.game" || g_pGameDescription->mGameFile == "ja.game") + combo_list = g_list_append (combo_list, (void *)"System"); + else if (g_pGameDescription->mGameFile == "sof2.game") + combo_list = g_list_append (combo_list, (void *)"Tools"); + else + combo_list = g_list_append (combo_list, (void *)"Common"); + combo_list = g_list_append (combo_list, (void *)"All"); + combo = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (combo), combo_list); + gtk_widget_show (combo); + gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE); + AddDialogData (combo, &m_nLatchedShader, DLG_COMBO_INT); + g_list_free (combo_list); + + // Add the page to the notebook + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + /******** Layout group *********/ + preflabel = gtk_label_new("Layout"); + gtk_widget_show(preflabel); + pageframe = gtk_frame_new("Layout"); + gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); + gtk_widget_show(pageframe); + vbox = gtk_vbox_new(FALSE, 5); + gtk_widget_show(vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(pageframe), vbox); + + // View types + // table + table = gtk_table_new (2, 4, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + // view type 1 + pixmap = new_pixmap (g_pParentWnd->m_pWidget, "window1.bmp"); + gtk_widget_show (pixmap); + gtk_table_attach (GTK_TABLE (table), pixmap, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + // view type 2 + pixmap = new_pixmap (g_pParentWnd->m_pWidget, "window2.bmp"); + gtk_widget_show (pixmap); + gtk_table_attach (GTK_TABLE (table), pixmap, 1, 2, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + // view type 3 + pixmap = new_pixmap (g_pParentWnd->m_pWidget, "window3.bmp"); + gtk_widget_show (pixmap); + gtk_table_attach (GTK_TABLE (table), pixmap, 2, 3, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + // view type 4 + pixmap = new_pixmap (g_pParentWnd->m_pWidget, "window4.bmp"); + gtk_widget_show (pixmap); + gtk_table_attach (GTK_TABLE (table), pixmap, 3, 4, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + // view type 1 selector + radio = gtk_radio_button_new (NULL); + gtk_widget_show (radio); + gtk_table_attach (GTK_TABLE (table), radio, 0, 1, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + // view type 2 selector + radio = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (radio)); + gtk_widget_show (radio); + gtk_table_attach (GTK_TABLE (table), radio, 1, 2, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + // view type 3 selector + radio = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (radio)); + gtk_widget_show (radio); + gtk_table_attach (GTK_TABLE (table), radio, 2, 3, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + // view type 4 selector + radio = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (radio)); + gtk_widget_show (radio); + gtk_table_attach (GTK_TABLE (table), radio, 3, 4, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + AddDialogData (radio, &m_nLatchedView, DLG_RADIO_INT); + + // Floating Z window + check = gtk_check_button_new_with_label ("Floating Z Window"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bLatchedFloatingZ, DLG_CHECK_BOOL); + + // show menu tear-off seperators + check = gtk_check_button_new_with_label ("Detachable Menus"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bLatchedDetachableMenus, DLG_CHECK_BOOL); + + if (!g_pGameDescription->mNoPatch) + { + // show patch toolbar + check = gtk_check_button_new_with_label ("Patch Toolbar"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + g_object_set_data (G_OBJECT (dialog), "check_patchtoolbar", check); // Allow to be disabled for Q1/Q2 + AddDialogData (check, &m_bLatchedPatchToolbar, DLG_CHECK_BOOL); + } + + // use wide toolbar + check = gtk_check_button_new_with_label ("Wide Toolbar"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bLatchedWideToolbar, DLG_CHECK_BOOL); + + // use plugin toolbar + check = gtk_check_button_new_with_label ("Plugin Toolbar"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bLatchedPluginToolbar, DLG_CHECK_BOOL); + +#ifdef _WIN32 + // win32 file dialog + check = gtk_check_button_new_with_label ("Use win32 file load dialog"); + gtk_widget_show (check); + // gtk_container_add (GTK_CONTAINER (vbox), check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bNativeGUI, DLG_CHECK_BOOL); + + // position on primary monitor + check = gtk_check_button_new_with_label ("Start on Primary Monitor"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + g_object_set_data (G_OBJECT (dialog), "check_startonprimary", check); + gtk_signal_connect( GTK_OBJECT (check), "clicked", GTK_SIGNAL_FUNC(UpdateSensitivity), this ); + AddDialogData (check, &m_bStartOnPrimMon, DLG_CHECK_BOOL); +#endif + + // Add the page to the notebook + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + /******** Mouse group *********/ + preflabel = gtk_label_new("Mouse"); + gtk_widget_show(preflabel); + pageframe = gtk_frame_new("Mouse"); + gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); + gtk_widget_show(pageframe); + vbox = gtk_vbox_new(FALSE, 5); + gtk_widget_show(vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(pageframe), vbox); + + // Buttons + // container + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_box_pack_start(GTK_BOX(vbox), hbox2, FALSE, FALSE, 0); + + // 2 button radio + radio = gtk_radio_button_new_with_label (NULL, "2 button"); + gtk_widget_show (radio); + gtk_box_pack_start (GTK_BOX (hbox2), radio, FALSE, FALSE, 0); + + // 3 button radio + radio = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (radio), "3 button"); + gtk_widget_show (radio); + gtk_box_pack_start (GTK_BOX (hbox2), radio, FALSE, FALSE, 0); + AddDialogData (radio, &m_nMouse, DLG_RADIO_INT); + + // right click to drop entity + check = gtk_check_button_new_with_label ("Right click to drop entities"); + gtk_widget_show (check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bRightClick, DLG_CHECK_BOOL); + + // Mouse chaser (and this does what?) + check = gtk_check_button_new_with_label ("Mouse chaser"); + gtk_widget_show (check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bChaseMouse, DLG_CHECK_BOOL); + + // Alt + multi-drag + check = gtk_check_button_new_with_label ("ALT + multi-drag"); + gtk_widget_show (check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bALTEdge, DLG_CHECK_BOOL); + + // Mouse wheel increments + // container + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_box_pack_start(GTK_BOX(vbox), hbox2, FALSE, FALSE, 0); + + // label + label = gtk_label_new ("Wheel Mouse inc:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); + + // entry + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_widget_set_usize (entry, 40, -2); + gtk_box_pack_start (GTK_BOX (hbox2), entry, FALSE, FALSE, 0); + AddDialogData (entry, &m_nWheelInc, DLG_ENTRY_INT); + + // Add the page to the notebook + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + /******** Editing group *********/ + preflabel = gtk_label_new("Editing"); + gtk_widget_show(preflabel); + pageframe = gtk_frame_new("Editing"); + gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); + gtk_widget_show(pageframe); + vbox = gtk_vbox_new(FALSE, 5); + gtk_widget_show(vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(pageframe), vbox); + + // Vertex editing splits faces + check = gtk_check_button_new_with_label ("Vertex editing splits face"); + gtk_widget_show (check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bVertexSplit, DLG_CHECK_BOOL); + + // Fix target/targetname collisions + check = gtk_check_button_new_with_label ("Fix target/targetname collisions"); + gtk_widget_show (check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bDoTargetFix, DLG_CHECK_BOOL); + + // Clipper tool uses caulk + check = gtk_check_button_new_with_label ("Clipper tool uses caulk"); + gtk_widget_show (check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bClipCaulk, DLG_CHECK_BOOL); + + // Don't clamp plane points + check = gtk_check_button_new_with_label ("Don't clamp plane points"); + gtk_widget_show (check); + gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bNoClamp, DLG_CHECK_BOOL); + + // Select patch by bounding box + check = gtk_check_button_new_with_label ("Select patches by bounding box"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bPatchBBoxSelect, DLG_CHECK_BOOL); + + // Rotation increment + // container + table = gtk_table_new (2, 3, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + // label + label = gtk_label_new ("Rotation increment:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + // entry + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_widget_set_usize (entry, 60, -2); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + AddDialogData (entry, &m_nRotation, DLG_ENTRY_INT); + + // Undo levels + // label + label = gtk_label_new ("Undo Levels:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + // spinner (allows undo levels to be set to zero) + spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (1, 0, 64, 1, 10, 10)), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + AddDialogData (spin, &m_nUndoLevels, DLG_SPIN_INT); + + // Patch subdivisions + // label + label = gtk_label_new ("Patch subdivisions:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + // entry (spinner perhaps? [2-16]) + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_widget_set_usize (entry, 60, -2); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + AddDialogData (entry, &m_nSubdivisions, DLG_ENTRY_INT); + + // Add the page to the notebook + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + /******** Save/Load group *********/ + preflabel = gtk_label_new("Startup/Auto save"); + gtk_widget_show(preflabel); + pageframe = gtk_frame_new("Startup/Auto save"); + gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); + gtk_widget_show(pageframe); + vbox = gtk_vbox_new(FALSE, 5); + gtk_widget_show(vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(pageframe), vbox); + + // Snapshots + check = gtk_check_button_new_with_label ("Snapshots"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bSnapShots, DLG_CHECK_BOOL); + + // load last project on open + check = gtk_check_button_new_with_label ("Load last project on open"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bLoadLast, DLG_CHECK_BOOL); + + // load last map on open + check = gtk_check_button_new_with_label ("Load last map on open"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bLoadLastMap, DLG_CHECK_BOOL); + + // Auto save.. + // container + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_box_pack_start(GTK_BOX(vbox), hbox2, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbox2), 0); + + // label + check = gtk_check_button_new_with_label ("Auto save every"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (hbox2), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bAutoSave, DLG_CHECK_BOOL); + + // spinner + spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (1, 1, 60, 1, 10, 10)), 1, 0); + gtk_widget_show (spin); + gtk_box_pack_start (GTK_BOX (hbox2), spin, FALSE, FALSE, 0); + gtk_widget_set_usize (spin, 60, -2); + AddDialogData (spin, &m_nAutoSave, DLG_SPIN_INT); + + // label + label = gtk_label_new ("minutes"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); + + // Add the page to the notebook + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + /******** Paths group *********/ + preflabel = gtk_label_new("Paths"); + gtk_widget_show(preflabel); + pageframe = gtk_frame_new("Paths"); + gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); + gtk_widget_show(pageframe); + vbox = gtk_vbox_new(FALSE, 5); + gtk_widget_show(vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(pageframe), vbox); + + // prefab path + // table + table = gtk_table_new (3, 3, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + // label + label = gtk_label_new ("Prefab path:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + // path entry + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_widget_set_usize(GTK_WIDGET(entry), 240, -2); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 1, 0); + AddDialogData (entry, &m_strPrefabPath, DLG_ENTRY_TEXT); + + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=805 +#if 0 + // browse button + button = gtk_button_new_with_label ("..."); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnBrowseprefab), this); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); +#endif + + // User ini path + // label + label = gtk_label_new ("User INI path:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + // user ini path entry + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 1, 0); + AddDialogData (entry, &m_strUserPath, DLG_ENTRY_TEXT); + + // user ini browse button + button = gtk_button_new_with_label ("..."); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnBrowseuserini), this); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + // Add the page to the notebook + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + /******** Misc group *********/ + preflabel = gtk_label_new("Misc"); + gtk_widget_show(preflabel); + pageframe = gtk_frame_new("Misc"); + gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); + gtk_widget_show(pageframe); + vbox = gtk_vbox_new(FALSE, 5); + gtk_widget_show(vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(pageframe), vbox); + + // Light drawing + check = gtk_check_button_new_with_label ("Light drawing"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &m_bNewLightDraw, DLG_CHECK_BOOL); + + // Light radiuses + // container + table = gtk_table_new(2, 1, FALSE); + gtk_widget_show(table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Light radiuses:"); + gtk_widget_show (label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + + combo_list = NULL; + combo_list = g_list_append (combo_list, (void *)"Disabled"); + combo_list = g_list_append (combo_list, (void *)"True Q3Map2 Style"); + combo_list = g_list_append (combo_list, (void *)"Classic Style"); + + combo = gtk_combo_new (); + gtk_combo_set_popdown_strings (GTK_COMBO (combo), combo_list); + gtk_widget_show (combo); + gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (combo)->entry), FALSE); + AddDialogData (combo, &m_nLightRadiuses, DLG_COMBO_INT); + +#ifdef _WIN32 + check = gtk_check_button_new_with_label ("Use win32 file associations to open text files instead of builtin editor"); + gtk_widget_show(check); + gtk_box_pack_start(GTK_BOX (vbox), check, FALSE, FALSE, 0); + AddDialogData (check, &g_PrefsDlg.m_bUseWin32Editor, DLG_CHECK_BOOL); +#else + // use custom shader editor + check = gtk_check_button_new_with_label ("Use Custom Shader Editor"); + gtk_widget_show(check); + gtk_box_pack_start(GTK_BOX (vbox), check, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT (check), "clicked", GTK_SIGNAL_FUNC(UpdateEditorSensitivity), this); + g_object_set_data (G_OBJECT(dialog), "check_customeditor", check); + AddDialogData (check, &g_PrefsDlg.m_bUseCustomEditor, DLG_CHECK_BOOL); + + // custom shader editor executable + // table + table = gtk_table_new (3, 1, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + // label + label = gtk_label_new("Custom Editor Command"); + gtk_widget_show(label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + g_object_set_data (G_OBJECT(dialog), "label_customeditor", label); + gtk_widget_set_sensitive (label, g_PrefsDlg.m_bUseCustomEditor); + + // custom editor command entry + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_widget_set_usize(GTK_WIDGET(entry), 240, -2); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 1, 0); + AddDialogData (entry, &m_strEditorCommand, DLG_ENTRY_TEXT); + gtk_widget_set_sensitive (entry, g_PrefsDlg.m_bUseCustomEditor); + g_object_set_data (G_OBJECT(dialog), "entry_customeditor", entry); + + // browse button + button = gtk_button_new_with_label ("..."); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnBtnBrowseEditor), this); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1, + (GtkAttachOptions) (0), + (GtkAttachOptions) (0), 0, 0); + g_object_set_data (G_OBJECT(dialog), "button_customeditor", button); + gtk_widget_set_sensitive (button, g_PrefsDlg.m_bUseCustomEditor); +#endif + + // Add the page to the notebook + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + /******** BSP Monitoring group *********/ + // this is never displayed if the plugin isn't available + preflabel = gtk_label_new("BSP Monitoring"); + gtk_widget_show(preflabel); + pageframe = gtk_frame_new("BSP Monitoring"); + gtk_container_set_border_width(GTK_CONTAINER(pageframe), 5); + gtk_widget_show(pageframe); + vbox = gtk_vbox_new(FALSE, 5); + gtk_widget_show(vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(pageframe), vbox); + + // Enable BSP process monitoring + check = gtk_check_button_new_with_label ("Enable BSP process monitoring"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + g_object_set_data (G_OBJECT (dialog), "check_monitorbsp", check); + gtk_signal_connect( GTK_OBJECT (check), "clicked", GTK_SIGNAL_FUNC(UpdateSensitivity), this ); + AddDialogData (check, &g_PrefsDlg.m_bWatchBSP, DLG_CHECK_BOOL); + + // Stop on leak + check = gtk_check_button_new_with_label ("Stop compilation on leak"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + g_object_set_data (G_OBJECT (dialog), "check_leakstop", check); + AddDialogData (check, &g_PrefsDlg.m_bLeakStop, DLG_CHECK_BOOL); + + // engine after compile + check = gtk_check_button_new_with_label ("Run engine after compile"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + g_object_set_data (G_OBJECT (dialog), "check_runengine", check); + gtk_signal_connect( GTK_OBJECT (check), "clicked", GTK_SIGNAL_FUNC(UpdateSensitivity), this ); + AddDialogData( check, &g_PrefsDlg.m_bRunQuake, DLG_CHECK_BOOL ); + + // sleep mode when running engine + check = gtk_check_button_new_with_label ("Activate sleep mode when running the engine"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + g_object_set_data (G_OBJECT (dialog), "check_sleep", check); + AddDialogData( check, &g_PrefsDlg.m_bDoSleep, DLG_CHECK_BOOL ); + + // use q3map2's texture projection + check = gtk_check_button_new_with_label ("Texturing compatible with q3map2"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); + g_object_set_data (G_OBJECT (dialog), "check_q3map2", check); + AddDialogData( check, &g_PrefsDlg.m_bQ3Map2Texturing, DLG_CHECK_BOOL ); + + // Add the page to the notebook + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), pageframe, preflabel); + + gtk_notebook_set_page(GTK_NOTEBOOK(notebook), PTAB_FRONT); + + return; +} + +// end new prefs dialog + +void PrefsDlg::LoadTexdefPref(texdef_t* pTexdef, char* pName) +{ + char buffer[256]; + + memset(pTexdef, 0, sizeof(texdef_t)); + + sprintf(buffer, "%s%s", pName, TD_SCALE1_KEY); + mLocalPrefs.GetPref(buffer, &pTexdef->scale[0], 0.5f); + + sprintf(buffer, "%s%s", pName, TD_SCALE2_KEY); + mLocalPrefs.GetPref(buffer, &pTexdef->scale[1], 0.5f); + + sprintf(buffer, "%s%s", pName, TD_SHIFT1_KEY); + mLocalPrefs.GetPref(buffer, &pTexdef->shift[0], 8.f); + + sprintf(buffer, "%s%s", pName, TD_SHIFT2_KEY); + mLocalPrefs.GetPref(buffer, &pTexdef->shift[1], 8.f); + + sprintf(buffer, "%s%s", pName, TD_ROTATE_KEY); + mLocalPrefs.GetPref(buffer, &pTexdef->rotate, 45); +} + +void PrefsDlg::UpdateTextureCompression() +{ + // if OpenGL is not ready yet, don't do anything + if (!g_qeglobals.m_bOpenGLReady) { + Sys_Printf("OpenGL not ready - postpone texture compression capability check\n"); + return; + } + + if (g_qeglobals.bTextureCompressionSupported) + { + if (m_nTextureCompressionFormat >= 2 && !g_qeglobals.m_bS3CompressionSupported) + { + Sys_Printf("Inconsistant pref setting for texture compression (%d), rolling back\n", m_nTextureCompressionFormat); + m_nTextureCompressionFormat = 1; // if this is not supported either, see below + } + if (m_nTextureCompressionFormat == 1 && !g_qeglobals.m_bOpenGLCompressionSupported) + { + Sys_Printf("Inconsistant pref setting for texture compression (GL_COMPRESSED_RGBA), rolling back\n"); + m_nTextureCompressionFormat = 0; + } + switch (m_nTextureCompressionFormat) + { + case (0): + { + g_qeglobals.texture_components = GL_RGBA; + Sys_Printf("texture compression disabled by preferences settings\n"); + break; + } + case (1): + { + g_qeglobals.texture_components = GL_COMPRESSED_RGBA; + Sys_Printf("OpenGL texture compression enabled\n"); + break; + } + case (2): + { + g_qeglobals.texture_components = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + Sys_Printf("S3TC DXT1 texture compression enabled\n"); + break; + } + case (3): + { + g_qeglobals.texture_components = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + Sys_Printf("S3TC DXT3 texture compression enabled\n"); + break; + } + case (4): + { + g_qeglobals.texture_components = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + Sys_Printf("S3TC DXT5 texture compression enabled\n"); + break; + } + } + } + else + { + Sys_Printf("texture compression is not supported by your current graphic card/drivers\n"); + g_qeglobals.texture_components = GL_RGBA; + m_nTextureCompressionFormat = 0; + } +} + +#ifdef ATIHACK_812 +void PrefsDlg::UpdateATIHack() { + // if OpenGL is not ready yet, don't do anything + if (!g_qeglobals.m_bOpenGLReady) { + Sys_Printf("OpenGL not ready - postpone ATI bug workaround setup\n"); + return; + } + + if (m_bGlATIHack) { + qglCullFace = &qglCullFace_ATIHack; + qglDisable = &qglDisable_ATIHack; + qglEnable = &qglEnable_ATIHack; + qglPolygonMode = &qglPolygonMode_ATIHack; + Sys_Printf("ATI bug workaround enabled\n"); + } else { + qglCullFace = qglCullFace_real; + qglDisable = qglDisable_real; + qglEnable = qglEnable_real; + qglPolygonMode = qglPolygonMode_real; + Sys_Printf("ATI bug workaround disabled\n"); + } +} +#endif + +// TTimo: m_strEnginePath has a special status, if not found in registry we need to +// initiliaze it for sure. It is not totally failsafe but we can use the same +// code than in q3map, expecting to find some "quake" above us. If not, we prompt +// for the engine executable path +void PrefsDlg::LoadPrefs () +{ + int i; + + // first things first, load prefs from global prefs + mGamesDialog.LoadPrefs(); + + // if we already have a document loaded, we will free and reload from file + if (mLocalPrefs.InUse()) { + mLocalPrefs.Clear(); + } + + // load local.pref file + mLocalPrefs.ReadXMLFile(m_inipath->str); + + mLocalPrefs.GetPref(PATCHSHOWBOUNDS_KEY, &g_bPatchShowBounds, FALSE); + mLocalPrefs.GetPref(MOUSE_KEY, &m_nMouse, MOUSE_DEF); + m_nMouseButtons = m_nMouse ? 3 : 2; + + // project file + // if it's not found here, mainframe.cpp will take care of finding one + mLocalPrefs.GetPref(LASTPROJ_KEY, &m_strLastProject, ""); + mLocalPrefs.GetPref(LASTPROJVER_KEY, &m_nLastProjectVer, -1); + + // prefab path + // NOTE TTimo: I'm not sure why this is in prefs + // should probably be a project setting + // and I'm not sure that we really have a way to set this reliably either + CString strPrefab; + strPrefab = g_qeglobals.m_strHomeGame.GetBuffer(); + strPrefab += g_pGameDescription->mBaseGame.GetBuffer(); + strPrefab += "/prefabs/"; + mLocalPrefs.GetPref(PREFAB_KEY, &m_strPrefabPath, strPrefab); + + mLocalPrefs.GetPref(LASTLIGHTINTENSITY_KEY, &m_iLastLightIntensity, 300); + mLocalPrefs.GetPref(TLOCK_KEY, &m_bTextureLock, TLOCK_DEF); + mLocalPrefs.GetPref(RLOCK_KEY, &m_bRotateLock, TLOCK_DEF); + mLocalPrefs.GetPref(LASTMAP_KEY, &m_strLastMap, ""); + mLocalPrefs.GetPref(LOADLAST_KEY, &m_bLoadLast, LOADLAST_DEF); + mLocalPrefs.GetPref(BSP_KEY, &m_bInternalBSP, FALSE); + mLocalPrefs.GetPref(RCLICK_KEY, &m_bRightClick, TRUE); + mLocalPrefs.GetPref(AUTOSAVE_KEY, &m_bAutoSave, TRUE); + mLocalPrefs.GetPref(LOADLASTMAP_KEY, &m_bLoadLastMap, FALSE); + mLocalPrefs.GetPref(TINYBRUSH_KEY, &m_bCleanTiny, FALSE); + mLocalPrefs.GetPref(TINYSIZE_KEY, &m_fTinySize, 0.5f); + mLocalPrefs.GetPref(AUTOSAVETIME_KEY, &m_nAutoSave, 5); + mLocalPrefs.GetPref(SNAPSHOT_KEY, &m_bSnapShots, FALSE); + mLocalPrefs.GetPref(MOVESPEED_KEY, &m_nMoveSpeed, 100); + mLocalPrefs.GetPref(ANGLESPEED_KEY, &m_nAngleSpeed, 3); + mLocalPrefs.GetPref(SETGAME_KEY, &m_bSetGame, FALSE); + mLocalPrefs.GetPref(CAMXYUPDATE_KEY, &m_bCamXYUpdate, TRUE); + mLocalPrefs.GetPref(CAMDRAGMULTISELECT_KEY, &m_nCamDragMultiSelect, TRUE); + mLocalPrefs.GetPref(CAMFREELOOK_KEY, &m_bCamFreeLook, TRUE); + mLocalPrefs.GetPref(CAMINVERSEMOUSE_KEY, &m_bCamInverseMouse, FALSE); + mLocalPrefs.GetPref(CAMDISCRETE_KEY, &m_bCamDiscrete, TRUE); + mLocalPrefs.GetPref(LIGHTDRAW_KEY, &m_bNewLightDraw, TRUE); + mLocalPrefs.GetPref(CUBICCLIP_KEY, &m_bCubicClipping, TRUE); + mLocalPrefs.GetPref(CUBICSCALE_KEY, &m_nCubicScale, 13); + mLocalPrefs.GetPref(ALTEDGE_KEY, &m_bALTEdge, FALSE); + mLocalPrefs.GetPref(FACECOLORS_KEY, &m_bFaceColors, FALSE); + mLocalPrefs.GetPref(XZVIS_KEY, &m_bXZVis, FALSE); + mLocalPrefs.GetPref(YZVIS_KEY, &m_bYZVis, FALSE); + mLocalPrefs.GetPref(ZVIS_KEY, &m_bZVis, FALSE); + mLocalPrefs.GetPref(SIZEPAINT_KEY, &m_bSizePaint, FALSE); + mLocalPrefs.GetPref(DLLENTITIES_KEY, &m_bDLLEntities, FALSE); + + mLocalPrefs.GetPref(DETACHABLEMENUS_KEY, &m_bLatchedDetachableMenus, TRUE); + m_bDetachableMenus = m_bLatchedDetachableMenus; + + if (g_pGameDescription->mNoPatch) + { + m_bPatchToolbar = false; + } + else + { + mLocalPrefs.GetPref(PATCHTOOLBAR_KEY, &m_bLatchedPatchToolbar, TRUE); + m_bPatchToolbar = m_bLatchedPatchToolbar; + } + + mLocalPrefs.GetPref(WIDETOOLBAR_KEY, &m_bLatchedWideToolbar, TRUE); + m_bWideToolbar = m_bLatchedWideToolbar; + + mLocalPrefs.GetPref(PLUGINTOOLBAR_KEY, &m_bLatchedPluginToolbar, TRUE); + m_bPluginToolbar = m_bLatchedPluginToolbar; + + mLocalPrefs.GetPref(WINDOW_KEY, (int*)&m_nLatchedView, WINDOW_DEF); + m_nView = m_nLatchedView; + + mLocalPrefs.GetPref(FLOATINGZ_KEY, &m_bLatchedFloatingZ, FALSE); + m_bFloatingZ = m_bLatchedFloatingZ; + + mLocalPrefs.GetPref(TEXTUREQUALITY_KEY, &m_nLatchedTextureQuality, 3); + m_nTextureQuality = m_nLatchedTextureQuality; + + mLocalPrefs.GetPref(LOADSHADERS_KEY, &m_nLatchedShader, 0); + m_nShader = m_nLatchedShader; + + mLocalPrefs.GetPref(NOCLAMP_KEY, &m_bNoClamp, FALSE); + mLocalPrefs.GetPref(USERINI_KEY, &m_strUserPath, ""); + mLocalPrefs.GetPref(ROTATION_KEY, &m_nRotation, 45); + mLocalPrefs.GetPref(CHASEMOUSE_KEY, &m_bChaseMouse, TRUE); + mLocalPrefs.GetPref(ENTITYSHOW_KEY, &m_nEntityShowState, ENTITY_SKINNED_BOXED); + + // this will probably need to be 75 or 100 for Q1. + mLocalPrefs.GetPref(TEXTURESCALE_KEY, &m_nTextureScale, 50); + + // FIXME: Hydra - actually, this stuff is Q1,Q2 and HL specific. + if ( (g_pGameDescription->mGameFile == "hl.game") ) + { + // No BSP monitoring in the default compiler tools for Half-life (yet) + mLocalPrefs.GetPref(WATCHBSP_KEY, &m_bWatchBSP, FALSE); + + // Texture subset on by default (HL specific really, because of halflife.wad's size) + mLocalPrefs.GetPref(TEXTURE_KEY, &m_bTextureWindow, TRUE); + } + else if ( ( g_pGameDescription->mGameFile == "q2.game" ) || ( g_pGameDescription->mGameFile == "heretic2.game" ) ) + { + // BSP monitoring is implemented in Quake2 and Heretic2 tools + mLocalPrefs.GetPref(WATCHBSP_KEY, &m_bWatchBSP, TRUE); + + // Texture subset on by default (HL specific really, because of halflife.wad's size) + mLocalPrefs.GetPref(TEXTURE_KEY, &m_bTextureWindow, TRUE); + } + else + { + mLocalPrefs.GetPref(WATCHBSP_KEY, &m_bWatchBSP, WATCHBSP_DEF); + mLocalPrefs.GetPref(TEXTURE_KEY, &m_bTextureWindow, FALSE); + } + + + mLocalPrefs.GetPref(TEXTURESCROLLBAR_KEY, &m_bTextureScrollbar, TRUE); + mLocalPrefs.GetPref(DISPLAYLISTS_KEY, &m_bDisplayLists, TRUE); + mLocalPrefs.GetPref(ANTIALIASEDLINES_KEY, &m_bAntialiasedPointsAndLines, FALSE); + mLocalPrefs.GetPref(SWITCHCLIP_KEY, &m_bSwitchClip, TRUE); + mLocalPrefs.GetPref(SELWHOLEENTS_KEY, &m_bSelectWholeEntities, TRUE); + mLocalPrefs.GetPref(SHOWSHADERS_KEY, &m_bShowShaders, TRUE); + mLocalPrefs.GetPref(GLLIGHTING_KEY, &m_bGLLighting, FALSE); + mLocalPrefs.GetPref(NOSTIPPLE_KEY, &m_bNoStipple, FALSE); + mLocalPrefs.GetPref(UNDOLEVELS_KEY, &m_nUndoLevels, 30); + mLocalPrefs.GetPref(VERTEXMODE_KEY, &m_bVertexSplit, TRUE); + mLocalPrefs.GetPref(RUNQ2_KEY, &m_bRunQuake, RUNQ2_DEF); + mLocalPrefs.GetPref(LEAKSTOP_KEY, &m_bLeakStop, TRUE); + mLocalPrefs.GetPref(DOSLEEP_KEY, &m_bDoSleep, FALSE); + mLocalPrefs.GetPref(SELECTCURVES_KEY, &m_bSelectCurves, TRUE); + mLocalPrefs.GetPref(SELECTMODELS_KEY, &m_bSelectModels, TRUE); + mLocalPrefs.GetPref(SHADERLISTONLY_KEY, &m_bTexturesShaderlistOnly, FALSE); + mLocalPrefs.GetPref(SUBDIVISIONS_KEY, &m_nSubdivisions, SUBDIVISIONS_DEF); + mLocalPrefs.GetPref(CLIPCAULK_KEY, &m_bClipCaulk, FALSE); + mLocalPrefs.GetPref(SNAPTTOGRID_KEY, &m_bSnapTToGrid, FALSE); + mLocalPrefs.GetPref(TARGETFIX_KEY, &m_bDoTargetFix, TRUE); + mLocalPrefs.GetPref(WHEELINC_KEY, &m_nWheelInc, 64); + mLocalPrefs.GetPref(PATCHBBOXSEL_KEY, &m_bPatchBBoxSelect, FALSE); + + // Gef: Kyro GL_POINT workaround + mLocalPrefs.GetPref(GLPOINTWORKAROUND_KEY, &m_bGlPtWorkaround, FALSE); + + // window positioning + mLocalPrefs.GetPref(ENTITYSPLIT1_KEY, &mWindowInfo.nEntitySplit1, -1); + mLocalPrefs.GetPref(ENTITYSPLIT2_KEY, &mWindowInfo.nEntitySplit2, -1); + + mLocalPrefs.GetPref(POSITIONX_KEY, &mWindowInfo.position.x, -1); + mLocalPrefs.GetPref(POSITIONY_KEY, &mWindowInfo.position.y, -1); + mLocalPrefs.GetPref(WIDTH_KEY, &mWindowInfo.position.w, -1); + mLocalPrefs.GetPref(HEIGHT_KEY, &mWindowInfo.position.h, 450); + + const window_position_t default_window_pos = { 0, 0, 200, 200, }; + + mLocalPrefs.GetPref(ENTITYWND_KEY, &mWindowInfo.posEntityWnd, default_window_pos); + mLocalPrefs.GetPref(MAPINFOWND_KEY, &mWindowInfo.posMapInfoWnd, default_window_pos); + mLocalPrefs.GetPref(CAMWND_KEY, &mWindowInfo.posCamWnd, default_window_pos); + mLocalPrefs.GetPref(ZWND_KEY, &mWindowInfo.posZWnd, default_window_pos); + mLocalPrefs.GetPref(XYWND_KEY, &mWindowInfo.posXYWnd, default_window_pos); + mLocalPrefs.GetPref(YZWND_KEY, &mWindowInfo.posYZWnd, default_window_pos); + mLocalPrefs.GetPref(XZWND_KEY, &mWindowInfo.posXZWnd, default_window_pos); + mLocalPrefs.GetPref(PATCHWND_KEY, &mWindowInfo.posPatchWnd, default_window_pos); + mLocalPrefs.GetPref(SURFACEWND_KEY, &mWindowInfo.posSurfaceWnd, default_window_pos); + mLocalPrefs.GetPref(ENTITYINFOWND_KEY, &mWindowInfo.posEntityInfoWnd, default_window_pos); + + mLocalPrefs.GetPref(ZWIDTH_KEY, &mWindowInfo.nZWidth, 30); + mLocalPrefs.GetPref(XYHEIGHT_KEY, &mWindowInfo.nXYHeight, 300); + mLocalPrefs.GetPref(XYWIDTH_KEY, &mWindowInfo.nXYWidth, 300); + mLocalPrefs.GetPref(CAMWIDTH_KEY, &mWindowInfo.nCamWidth, 200); + mLocalPrefs.GetPref(CAMHEIGHT_KEY, &mWindowInfo.nCamHeight, 200); + mLocalPrefs.GetPref(ZFLOATWIDTH_KEY, &mWindowInfo.nZFloatWidth, 300); +#ifdef _WIN32 + mLocalPrefs.GetPref(STATE_KEY, &mWindowInfo.nState, SW_SHOW); +#endif + + // menu stuff + mLocalPrefs.GetPref(COUNT_KEY, &m_nMRUCount, 0); + for(i = 0; i < 4; i++) + { + char buf[64]; + sprintf (buf, "%s%d", FILE_KEY, i); + mLocalPrefs.GetPref(buf, &m_strMRUFiles[i], ""); + } + + // some platform specific prefs +#ifdef _WIN32 + mLocalPrefs.GetPref(NATIVEGUI_KEY, &m_bNativeGUI, TRUE); + mLocalPrefs.GetPref(STARTONPRIMMON_KEY, &m_bStartOnPrimMon, FALSE); +#endif + + mLocalPrefs.GetPref(SI_TEXMENU_KEY, &g_qeglobals.d_savedinfo.iTexMenu, ID_VIEW_BILINEARMIPMAP); + mLocalPrefs.GetPref(SI_GAMMA_KEY, &g_qeglobals.d_savedinfo.fGamma, 1.0f); + mLocalPrefs.GetPref(SI_EXCLUDE_KEY, &g_qeglobals.d_savedinfo.exclude, 0); // nothing filtered by default + mLocalPrefs.GetPref(SI_INCLUDE_KEY, &g_qeglobals.d_savedinfo.include, INCLUDE_NAMES | INCLUDE_COORDS | INCLUDE_ANGLES | INCLUDE_CAMERATINT); + mLocalPrefs.GetPref(SI_SHOWNAMES_KEY, &g_qeglobals.d_savedinfo.show_names, FALSE); + mLocalPrefs.GetPref(SI_SHOWCOORDS_KEY, &g_qeglobals.d_savedinfo.show_coordinates, TRUE); + mLocalPrefs.GetPref(SI_SHOWANGLES_KEY, &g_qeglobals.d_savedinfo.show_angles, TRUE); + mLocalPrefs.GetPref(SI_SHOWOUTLINES_KEY, &g_qeglobals.d_savedinfo.show_outline, FALSE); + mLocalPrefs.GetPref(SI_SHOWAXIS_KEY, &g_qeglobals.d_savedinfo.show_axis, TRUE); + mLocalPrefs.GetPref(SI_NOSELOUTLINES_KEY, &g_qeglobals.d_savedinfo.bNoSelectedOutlines, FALSE); + + mLocalPrefs.GetPref(SI_OUTLINESTYLE_KEY, &g_qeglobals.d_savedinfo.iSelectedOutlinesStyle, OUTLINE_ZBUF|OUTLINE_BSEL); + + LoadTexdefPref(&g_qeglobals.d_savedinfo.m_SIIncrement, SI_SURFACE_TEXDEF_KEY); + LoadTexdefPref(&g_qeglobals.d_savedinfo.m_PIIncrement, SI_PATCH_TEXDEF_KEY); + + // text editor binding +#ifdef _WIN32 + mLocalPrefs.GetPref(CUSTOMSHADEREDITOR_KEY, &m_bUseWin32Editor, TRUE); +#else + mLocalPrefs.GetPref(CUSTOMSHADEREDITOR_KEY, &m_bUseCustomEditor, FALSE); + mLocalPrefs.GetPref(CUSTOMSHADEREDITORCOMMAND_KEY, &m_strEditorCommand, ""); +#endif + + + vec3_t vDefaultAxisColours[3] = { + {0.f, 0.5f, 0.f}, + {0.f, 0.f, 1.f}, + {1.f, 0.f, 0.f}, + }; + + for(i = 0; i < 3; i++) { + char buf[64]; + sprintf(buf, "%s%d", SI_AXISCOLORS_KEY, i); + mLocalPrefs.GetPref(buf, g_qeglobals.d_savedinfo.AxisColors[i], vDefaultAxisColours[i]); + } + + vec3_t vDefaultColours[COLOR_LAST] = { + {0.25f, 0.25f, 0.25f}, + {1.f, 1.f, 1.f}, + {0.75f, 0.75f, 0.75f}, + {0.5f, 0.5f, 0.5f}, + {0.25f, 0.25f, 0.25f}, + {0.0f, 0.0f, 0.0f}, + {0.f, 0.f, 1.f}, + {0.f, 0.f, 0.f}, + {0.f, 0.f, 0.f}, + {1.f, 0.f, 0.f}, + {0.f, 0.f, 1.f}, + {0.5f, 0.f, 0.75f}, + {1.0f, 0.f, 0.f}, + {0.f, 0.f, 0.f}, + {0.f, 0.f, 0.f}, + }; + + for(i = 0; i < COLOR_LAST; i++) { + char buf[64]; + sprintf(buf, "%s%d", SI_COLORS_KEY, i); + mLocalPrefs.GetPref(buf, g_qeglobals.d_savedinfo.colors[i], vDefaultColours[i]); + } + + mLocalPrefs.GetPref(TEXTURECOMPRESSIONFORMAT_KEY, &m_nTextureCompressionFormat, 1); + + mLocalPrefs.GetPref(LIGHTRADIUS_KEY, &m_nLightRadiuses, TRUE); + + mLocalPrefs.GetPref(Q3MAP2TEX_KEY, &m_bQ3Map2Texturing, TRUE); + +#ifdef ATIHACK_812 + mLocalPrefs.GetPref(ATIHACK_KEY, &m_bGlATIHack, FALSE); +#endif + + Undo_SetMaxSize(m_nUndoLevels); // set it internally as well / FIXME: why not just have one global value? + + UpdateTextureCompression(); + +#ifdef ATIHACK_812 + UpdateATIHack(); +#endif + + if (mLocalPrefs.mbEmpty) + { + mLocalPrefs.mbEmpty = false; + Sys_Printf("Saving local.pref with default pref values\n"); + SavePrefs(); + } +} + +void PrefsDlg::SavePrefs () +{ + if (g_qeglobals.disable_ini) + return; + +#ifdef _DEBUG + Sys_Printf("PrefsDlg::SavePrefs\n"); +#endif + + // this will take care of copying back from the dialog to the variables + // NOTE: it may be overkill to call systematically before a SavePrefs, but it's safer + // this will also cause an UpdateData for the mGamesDialog + UpdateData(TRUE); + + mGamesDialog.SavePrefs(); + + // update the tree and save it + mLocalPrefs.UpdatePrefTree(); + if (!mLocalPrefs.WriteXMLFile(m_inipath->str)) + Sys_FPrintf(SYS_ERR, "Error occured while saving local prefs file '%s'\n", m_inipath->str); + + if (m_nMouse == 0) + m_nMouseButtons = 2; + else + m_nMouseButtons = 3; + +} + +void PrefsDlg::PostModal (int code) +{ + if (code == IDOK) + { + SavePrefs(); + // make sure the logfile is ok + Sys_LogFile(); + #ifdef ATIHACK_812 + UpdateATIHack(); + #endif + if (g_pParentWnd) + g_pParentWnd->SetGridStatus(); + Sys_UpdateWindows(W_ALL); + if (m_nUndoLevels != 0) + Undo_SetMaxSize(m_nUndoLevels); + } +} + +void PrefsDlg::DoEditorSensitivity() +{ + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g_object_get_data (G_OBJECT(m_pWidget), "check_customeditor")))) + { + gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data (G_OBJECT(m_pWidget), "label_customeditor")), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data (G_OBJECT(m_pWidget), "entry_customeditor")), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data (G_OBJECT(m_pWidget), "button_customeditor")), TRUE); + } + else + { + gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data (G_OBJECT(m_pWidget), "label_customeditor")), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data (G_OBJECT(m_pWidget), "entry_customeditor")), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data (G_OBJECT(m_pWidget), "button_customeditor")), FALSE); + } +} + +void PrefsDlg::DoSensitivity() +{ +#if 0 + // first, look at the project file version ... will monitoring work? + // project files now XML, guaranteed to be at least version 2 + if (0)//IntForKey( g_qeglobals.d_project_entity, "version" ) < 2) + { + if (m_bWarn) + { + Str Msg; + Msg = "The current project file ("; + Msg += g_PrefsDlg.m_strLastProject; + Msg += ") is not at least version 2.\nI need version 2 or above to setup BSP monitoring correctly."; + gtk_MessageBox(m_pWidget, Msg.GetBuffer(), MB_OK ); + + m_bWarn = false; + } + + // go ahead, disable everybuddy + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_leakstop" )), FALSE ); + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_monitorbsp" )), FALSE ); + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_runengine" )), FALSE ); + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_sleep" )), FALSE ); + } + else + { +#endif +// m_bWarn = true; + + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_leakstop" )), TRUE ); + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_monitorbsp" )), TRUE ); + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_runengine" )), TRUE ); + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_sleep" )), TRUE ); + + if ( ! gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( g_object_get_data( G_OBJECT(m_pWidget), "check_monitorbsp" ) ) ) ) + { + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_leakstop" )), FALSE ); + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_runengine" )), FALSE ); + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_sleep" )), FALSE ); + } else if (! gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( g_object_get_data( G_OBJECT(m_pWidget), "check_runengine" ) ) ) ) + { + gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data( G_OBJECT(m_pWidget), "check_sleep" )), FALSE ); + } +} diff --git a/radiant/profile.cpp b/radiant/profile.cpp index ed5357b6..bbd5bd24 100644 --- a/radiant/profile.cpp +++ b/radiant/profile.cpp @@ -1,293 +1,293 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -// -// Application settings load/save -// -// Leonardo Zide (leo@lokigames.com) -// - -#include "stdafx.h" -#include -#include -#include -#include -#include -#include "str.h" -#include "file.h" - -// ============================================================================= -// Static functions - -bool read_var (const char *filename, const char *section, const char *key, char *value) -{ - char line[1024], *ptr; - FILE *rc; - - rc = fopen (filename, "rt"); - - if (rc == NULL) - return false; - - while (fgets (line, 1024, rc) != 0) - { - // First we find the section - if (line[0] != '[') - continue; - - ptr = strchr (line, ']'); - *ptr = '\0'; - - if (strcmp (&line[1], section) == 0) - { - while (fgets (line, 1024, rc) != 0) - { - ptr = strchr (line, '='); - - if (ptr == NULL) - { - // reached the end of the section - fclose (rc); - return false; - } - *ptr = '\0'; - - // remove spaces - while (line[strlen(line)-1] == ' ') - line[strlen(line)-1] = '\0'; - - if (strcmp (line, key) == 0) - { - strcpy (value, ptr+1); - fclose (rc); - - if (value[strlen (value)-1] == 10 || value[strlen (value)-1] == 13 || value[strlen (value)-1] == 32) - value[strlen (value)-1] = 0; - - return true; - } - } - } - } - - fclose (rc); - return false; -} - -static bool save_var (const char *filename, const char *section, const char *key, const char *value) -{ - char line[1024], *ptr; - MemStream old_rc; - bool found; - FILE *rc; - - rc = fopen (filename, "rb"); - - if (rc != NULL) - { - guint32 len; - void *buf; - - fseek (rc, 0, SEEK_END); - len = ftell (rc); - rewind (rc); - buf = qmalloc (len); - fread (buf, len, 1, rc); - old_rc.Write (buf, len); - free (buf); - fclose (rc); - old_rc.Seek (0, SEEK_SET); - } - - // TTimo: changed to binary writing. It doesn't seem to affect linux version, and win32 version was happending a lot of '\n' - rc = fopen (filename, "wb"); - - if (rc == NULL) - return false; - - // First we need to find the section - found = false; - while (old_rc.ReadString (line, 1024) != NULL) - { - fputs (line, rc); - - if (line[0] == '[') - { - ptr = strchr (line, ']'); - *ptr = '\0'; - - if (strcmp (&line[1], section) == 0) - { - found = true; - break; - } - } - } - - if (!found) - { - fputs ("\n", rc); - fprintf (rc, "[%s]\n", section); - } - - fprintf (rc, "%s=%s\n", key, value); - - while (old_rc.ReadString (line, 1024) != NULL) - { - ptr = strchr (line, '='); - - if (ptr != NULL) - { - *ptr = '\0'; - - if (strcmp (line, key) == 0) - break; - - *ptr = '='; - fputs (line, rc); - } - else - { - fputs (line, rc); - break; - } - } - - while (old_rc.ReadString (line, 1024) != NULL) - fputs (line, rc); - - fclose (rc); - return true; -} - -// ============================================================================= -// Global functions - -bool WINAPI profile_save_int (const char *filename, const char *section, const char *key, int value) -{ - char buf[16]; - sprintf (buf, "%d", value); - return save_var (filename, section, key, buf); -} - -bool WINAPI profile_save_float (const char *filename, const char *section, const char *key, float value) -{ - char buf[16]; - sprintf (buf, "%f", value); - return save_var (filename, section, key, buf); -} - -bool WINAPI profile_save_string (const char * filename, const char *section, const char *key, const char *value) -{ - return save_var (filename, section, key, value); -} - -bool profile_save_buffer (const char * rc_path, const char *name, void *buffer, guint32 size) -{ - bool ret = false; - char filename[PATH_MAX]; - sprintf (filename, "%s/%s.bin", rc_path, name); - FILE *f; - - f = fopen (filename, "wb"); - - if (f != NULL) - { - if (fwrite (buffer, size, 1, f) == 1) - ret = true; - - fclose (f); - } - - return ret; -} - -bool profile_load_buffer (const char * rc_path, const char *name, void *buffer, guint32 *plSize) -{ - char filename[PATH_MAX]; - sprintf (filename, "%s/%s.bin", rc_path, name); - bool ret = false; - guint32 len; - FILE *f; - - f = fopen (filename, "rb"); - - if (f != NULL) - { - fseek (f, 0, SEEK_END); - len = ftell (f); - rewind (f); - - if (len > *plSize) - len = *plSize; - else - *plSize = len; - - if (fread (buffer, len, 1, f) == 1) - ret = true; - - fclose (f); - } - - return true; -} - -int WINAPI profile_load_int (const char *filename, const char *section, const char *key, int default_value) -{ - char value[1024]; - - if (read_var (filename, section, key, value)) - return atoi (value); - else - return default_value; -} - -float WINAPI profile_load_float (const char *filename, const char *section, const char *key, float default_value) -{ - char value[1024]; - - if (read_var (filename, section, key, value)) - return atof (value); - else - return default_value; -} - -char* WINAPI profile_load_string (const char *filename, const char *section, const char *key, const char *default_value) -{ - static Str ret; - char value[1024]; - - if (read_var (filename, section, key, value)) - ret = value; - else - ret = default_value; - - return (char*)ret.GetBuffer (); -} +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// +// Application settings load/save +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" +#include +#include +#include +#include +#include +#include "str.h" +#include "file.h" + +// ============================================================================= +// Static functions + +bool read_var (const char *filename, const char *section, const char *key, char *value) +{ + char line[1024], *ptr; + FILE *rc; + + rc = fopen (filename, "rt"); + + if (rc == NULL) + return false; + + while (fgets (line, 1024, rc) != 0) + { + // First we find the section + if (line[0] != '[') + continue; + + ptr = strchr (line, ']'); + *ptr = '\0'; + + if (strcmp (&line[1], section) == 0) + { + while (fgets (line, 1024, rc) != 0) + { + ptr = strchr (line, '='); + + if (ptr == NULL) + { + // reached the end of the section + fclose (rc); + return false; + } + *ptr = '\0'; + + // remove spaces + while (line[strlen(line)-1] == ' ') + line[strlen(line)-1] = '\0'; + + if (strcmp (line, key) == 0) + { + strcpy (value, ptr+1); + fclose (rc); + + if (value[strlen (value)-1] == 10 || value[strlen (value)-1] == 13 || value[strlen (value)-1] == 32) + value[strlen (value)-1] = 0; + + return true; + } + } + } + } + + fclose (rc); + return false; +} + +static bool save_var (const char *filename, const char *section, const char *key, const char *value) +{ + char line[1024], *ptr; + MemStream old_rc; + bool found; + FILE *rc; + + rc = fopen (filename, "rb"); + + if (rc != NULL) + { + guint32 len; + void *buf; + + fseek (rc, 0, SEEK_END); + len = ftell (rc); + rewind (rc); + buf = qmalloc (len); + fread (buf, len, 1, rc); + old_rc.Write (buf, len); + free (buf); + fclose (rc); + old_rc.Seek (0, SEEK_SET); + } + + // TTimo: changed to binary writing. It doesn't seem to affect linux version, and win32 version was happending a lot of '\n' + rc = fopen (filename, "wb"); + + if (rc == NULL) + return false; + + // First we need to find the section + found = false; + while (old_rc.ReadString (line, 1024) != NULL) + { + fputs (line, rc); + + if (line[0] == '[') + { + ptr = strchr (line, ']'); + *ptr = '\0'; + + if (strcmp (&line[1], section) == 0) + { + found = true; + break; + } + } + } + + if (!found) + { + fputs ("\n", rc); + fprintf (rc, "[%s]\n", section); + } + + fprintf (rc, "%s=%s\n", key, value); + + while (old_rc.ReadString (line, 1024) != NULL) + { + ptr = strchr (line, '='); + + if (ptr != NULL) + { + *ptr = '\0'; + + if (strcmp (line, key) == 0) + break; + + *ptr = '='; + fputs (line, rc); + } + else + { + fputs (line, rc); + break; + } + } + + while (old_rc.ReadString (line, 1024) != NULL) + fputs (line, rc); + + fclose (rc); + return true; +} + +// ============================================================================= +// Global functions + +bool WINAPI profile_save_int (const char *filename, const char *section, const char *key, int value) +{ + char buf[16]; + sprintf (buf, "%d", value); + return save_var (filename, section, key, buf); +} + +bool WINAPI profile_save_float (const char *filename, const char *section, const char *key, float value) +{ + char buf[16]; + sprintf (buf, "%f", value); + return save_var (filename, section, key, buf); +} + +bool WINAPI profile_save_string (const char * filename, const char *section, const char *key, const char *value) +{ + return save_var (filename, section, key, value); +} + +bool profile_save_buffer (const char * rc_path, const char *name, void *buffer, guint32 size) +{ + bool ret = false; + char filename[PATH_MAX]; + sprintf (filename, "%s/%s.bin", rc_path, name); + FILE *f; + + f = fopen (filename, "wb"); + + if (f != NULL) + { + if (fwrite (buffer, size, 1, f) == 1) + ret = true; + + fclose (f); + } + + return ret; +} + +bool profile_load_buffer (const char * rc_path, const char *name, void *buffer, guint32 *plSize) +{ + char filename[PATH_MAX]; + sprintf (filename, "%s/%s.bin", rc_path, name); + bool ret = false; + guint32 len; + FILE *f; + + f = fopen (filename, "rb"); + + if (f != NULL) + { + fseek (f, 0, SEEK_END); + len = ftell (f); + rewind (f); + + if (len > *plSize) + len = *plSize; + else + *plSize = len; + + if (fread (buffer, len, 1, f) == 1) + ret = true; + + fclose (f); + } + + return true; +} + +int WINAPI profile_load_int (const char *filename, const char *section, const char *key, int default_value) +{ + char value[1024]; + + if (read_var (filename, section, key, value)) + return atoi (value); + else + return default_value; +} + +float WINAPI profile_load_float (const char *filename, const char *section, const char *key, float default_value) +{ + char value[1024]; + + if (read_var (filename, section, key, value)) + return atof (value); + else + return default_value; +} + +char* WINAPI profile_load_string (const char *filename, const char *section, const char *key, const char *default_value) +{ + static Str ret; + char value[1024]; + + if (read_var (filename, section, key, value)) + ret = value; + else + ret = default_value; + + return (char*)ret.GetBuffer (); +} diff --git a/radiant/qe3.cpp b/radiant/qe3.cpp index e3f9cec6..3277bb01 100644 --- a/radiant/qe3.cpp +++ b/radiant/qe3.cpp @@ -1,1797 +1,1797 @@ -/* -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 -*/ - -// -// Linux stuff -// -// Leonardo Zide (leo@lokigames.com) -// - -#include "stdafx.h" -#include -#include -#include "gtkmisc.h" -#if defined (__linux__) || defined (__APPLE__) -#include -#include -#include -#include -#endif -// for the logging part -#include -#include - -QEGlobals_t g_qeglobals; -QEGlobals_GUI_t g_qeglobals_gui; - -// leo: Track memory allocations for debugging -// NOTE TTimo this was never used and probably not relevant -// there are tools to do that -#ifdef MEM_DEBUG - -static GList *memblocks; - -void* debug_malloc (size_t size, const char* file, int line) -{ - void *buf = g_malloc (size + 8); - - *((const char**)buf) = file; - buf = (char*)buf + 4; - *((int*)buf) = line; - buf = (char*)buf + 4; - - memblocks = g_list_append (memblocks, buf); - - return buf; -} - -void debug_free (void *buf, const char* file, int line) -{ - const char *f; - int l; - - if (g_list_find (memblocks, buf)) - { - memblocks = g_list_remove (memblocks, buf); - - buf = (char*)buf - 4; - l = *((int*)buf); - buf = (char*)buf - 4; - f = *((const char**)buf); - - Sys_FPrintf (SYS_DBG, "free: %s %d", file, line); - Sys_FPrintf (SYS_DBG, " allocated: %s %d\n", f, l); - - g_free (buf); - } -// else -// free (buf); // from qmalloc, will leak unless we add this same hack to cmdlib -} - -#endif - -vec_t Rad_rint (vec_t in) -{ - if (g_PrefsDlg.m_bNoClamp) - return in; - else - return (float)floor (in + 0.5); -} - -void WINAPI QE_CheckOpenGLForErrors(void) -{ - char strMsg[1024]; - int i = qglGetError(); - if (i != GL_NO_ERROR) - { - if (i == GL_OUT_OF_MEMORY) - { - sprintf(strMsg, "OpenGL out of memory error %s\nDo you wish to save before exiting?", qgluErrorString((GLenum)i)); - if (gtk_MessageBox(g_pParentWnd->m_pWidget, strMsg, "Radiant Error", MB_YESNO) == IDYES) - { - Map_SaveFile(NULL, false); - } - _exit(1); - } - else - { - Sys_Printf ("Warning: OpenGL Error %s\n", qgluErrorString((GLenum)i)); - } - } -} - -// NOTE: don't this function, use VFS instead -char *ExpandReletivePath (char *p) -{ - static char temp[1024]; - const char *base; - - if (!p || !p[0]) - return NULL; - if (p[0] == '/' || p[0] == '\\') - return p; - - base = ValueForKey(g_qeglobals.d_project_entity, "basepath"); - sprintf (temp, "%s/%s", base, p); - return temp; -} - -char *copystring (char *s) -{ - char *b; - b = (char*)malloc(strlen(s)+1); - strcpy (b,s); - return b; -} - - -bool DoesFileExist(const char* pBuff, long& lSize) -{ - FileStream file; - if (file.Open(pBuff, "r")) - { - lSize += file.GetLength(); - file.Close(); - return true; - } - return false; -} - - -void Map_Snapshot() -{ - CString strMsg; - - // I hope the modified flag is kept correctly up to date - if (!modified) - return; - - // we need to do the following - // 1. make sure the snapshot directory exists (create it if it doesn't) - // 2. find out what the lastest save is based on number - // 3. inc that and save the map - CString strOrgPath, strOrgFile; - ExtractPath_and_Filename(currentmap, strOrgPath, strOrgFile); - AddSlash(strOrgPath); - strOrgPath += "snapshots"; - bool bGo = true; - struct stat Stat; - if (stat(strOrgPath, &Stat) == -1) - { -#ifdef _WIN32 - bGo = (_mkdir(strOrgPath) != -1); -#endif - -#if defined (__linux__) || defined (__APPLE__) - bGo = (mkdir(strOrgPath,0755) != -1); -#endif - } - AddSlash(strOrgPath); - if (bGo) - { - int nCount = 0; - long lSize = 0; - CString strNewPath; - strNewPath = strOrgPath; - strNewPath += strOrgFile; - CString strFile; - while (bGo) - { - char buf[PATH_MAX]; - sprintf( buf, "%s.%i", strNewPath.GetBuffer(), nCount ); - strFile = buf; - bGo = DoesFileExist(strFile, lSize); - nCount++; - } - // strFile has the next available slot - Map_SaveFile(strFile, false); - // it is still a modified map (we enter this only if this is a modified map) - Sys_SetTitle (currentmap); - Sys_MarkMapModified(); - if (lSize > 12 * 1024 * 1024) // total size of saves > 4 mb - { - Sys_Printf("The snapshot files in %s total more than 4 megabytes. You might consider cleaning up.", strOrgPath.GetBuffer()); - } - } - else - { - strMsg.Format("Snapshot save failed.. unabled to create directory\n%s", strOrgPath.GetBuffer()); - gtk_MessageBox(g_pParentWnd->m_pWidget, strMsg); - } - strOrgPath = ""; - strOrgFile = ""; -} -/* -=============== -QE_CheckAutoSave - -If five minutes have passed since making a change -and the map hasn't been saved, save it out. -=============== -*/ - - -void QE_CheckAutoSave( void ) -{ - static time_t s_start; - time_t now; - time (&now); - - if (modified != 1 || !s_start) - { - s_start = now; - return; - } - - if ((now - s_start) > (60 * g_PrefsDlg.m_nAutoSave)) - { - if (g_PrefsDlg.m_bAutoSave) - { - CString strMsg; - strMsg = g_PrefsDlg.m_bSnapShots ? "Autosaving snapshot..." : "Autosaving..."; - Sys_Printf(strMsg); - Sys_Printf("\n"); - Sys_Status (strMsg,0); - - // only snapshot if not working on a default map - if (g_PrefsDlg.m_bSnapShots && stricmp(currentmap, "unnamed.map") != 0) - { - Map_Snapshot(); - } - else - { - Map_SaveFile (ValueForKey(g_qeglobals.d_project_entity, "autosave"), false); - } - - Sys_Status ("Autosaving...Saved.", 0 ); - modified = 2; - } - else - { - Sys_Printf ("Autosave skipped...\n"); - Sys_Status ("Autosave skipped...", 0 ); - } - s_start = now; - } -} - - -// NOTE TTimo we don't like that BuildShortPathName too much -// the VFS provides a vfsCleanFileName which should perform the cleanup tasks -// in the long run I'd like to completely get rid of this - -// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=144 -// used to be disabled, but caused problems - -// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=291 -// can't work with long win32 names until the BSP commands are not working differently -#ifdef _WIN32 -int BuildShortPathName(const char* pPath, char* pBuffer, int nBufferLen) -{ - char *pFile = NULL; - int nResult = GetFullPathName(pPath, nBufferLen, pBuffer, &pFile); - nResult = GetShortPathName(pPath, pBuffer, nBufferLen); - if (nResult == 0) - strcpy(pBuffer, pPath); // Use long filename - return nResult; -} -#endif - -#if defined (__linux__) || defined (__APPLE__) -int BuildShortPathName(const char* pPath, char* pBuffer, int nBufferLen) -{ - // remove /../ from directories - const char *scr = pPath; char *dst = pBuffer; - for (int i = 0; (i < nBufferLen) && (*scr != 0); i++) - { - if (*scr == '/' && *(scr+1) == '.' && *(scr+2) == '.') - { - scr += 3; - while (dst != pBuffer && *(--dst) != '/') - { - i--; - } - } - - *dst = *scr; - - scr++; dst++; - } - *dst = 0; - - return strlen (pBuffer); -} -#endif - -/* -const char *g_pPathFixups[]= -{ - "basepath", - "autosave", -}; - -const int g_nPathFixupCount = sizeof(g_pPathFixups) / sizeof(const char*); - -void QE_CheckProjectEntity() -{ - char *pFile; - char pBuff[PATH_MAX]; - char pNewPath[PATH_MAX]; - for (int i = 0; i < g_nPathFixupCount; i++) - { - char *pPath = ValueForKey (g_qeglobals.d_project_entity, g_pPathFixups[i]); - - strcpy (pNewPath, pPath); - if (pPath[0] != '\\' && pPath[0] != '/') - if (GetFullPathName(pPath, PATH_MAX, pBuff, &pFile)) - strcpy (pNewPath, pBuff); - - BuildShortPathName (pNewPath, pBuff, PATH_MAX); - - // check it's not ending with a filename seperator - if (pBuff[strlen(pBuff)-1] == '/' || pBuff[strlen(pBuff)-1] == '\\') - { - Sys_FPrintf(SYS_WRN, "WARNING: \"%s\" path in the project file has an ending file seperator, fixing.\n", g_pPathFixups[i]); - pBuff[strlen(pBuff)-1]=0; - } - - SetKeyValue(g_qeglobals.d_project_entity, g_pPathFixups[i], pBuff); - } -} -*/ - -void HandleXMLError( void* ctxt, const char* text, ... ) -{ - va_list argptr; - static char buf[32768]; - - va_start (argptr,text); - vsprintf (buf, text, argptr); - Sys_FPrintf (SYS_ERR, "XML %s\n", buf); - va_end (argptr); -} - -#define DTD_BUFFER_LENGTH 1024 -xmlDocPtr ParseXMLStream(IDataStream *stream, bool validate = false) -{ - xmlDocPtr doc = NULL; - bool wellFormed = false, valid = false; - int res, size = 1024; - char chars[1024]; - xmlParserCtxtPtr ctxt; - - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=433 - //if(validate) - // xmlDoValidityCheckingDefaultValue = 1; - //else - xmlDoValidityCheckingDefaultValue = 0; - xmlSetGenericErrorFunc(NULL, HandleXMLError); - - // SPoG - // HACK: use AppPath to resolve DTD location - // do a buffer-safe string copy and concatenate - int i; - char* w; - const char* r; - char buf[DTD_BUFFER_LENGTH]; - - w = buf; - i = 0; - // copy - //assert(g_strAppPath.GetBuffer() != NULL); - for(r = g_strAppPath.GetBuffer(); iRead(chars, 4); - if (res > 0) - { - ctxt = xmlCreatePushParserCtxt(NULL, NULL, chars, res, buf); - - while ((res = stream->Read(chars, size)) > 0) - { - xmlParseChunk(ctxt, chars, res, 0); - } - xmlParseChunk(ctxt, chars, 0, 1); - doc = ctxt->myDoc; - - wellFormed = (ctxt->wellFormed == 1); - valid = (ctxt->valid == 1); - - xmlFreeParserCtxt(ctxt); - } - - if(wellFormed && (!validate || (validate && valid))) - return doc; - - if(doc != NULL) - xmlFreeDoc(doc); - - return NULL; -} - -xmlDocPtr ParseXMLFile(const char* filename, bool validate = false) -{ - FileStream stream; - if (stream.Open(filename, "r")) - return ParseXMLStream(&stream, validate); - - Sys_FPrintf(SYS_ERR, "Failed to open file: %s\n",filename); - return NULL; -} - -// copy a string r to a buffer w -// replace $string as appropriate -void ReplaceTemplates(char* w, const char* r) -{ - const char *p; - const char *__ENGINEPATH = "TEMPLATEenginepath"; - const char *__USERHOMEPATH = "TEMPLATEuserhomepath"; - const char *__TOOLSPATH = "TEMPLATEtoolspath"; - const char *__BASEDIR = "TEMPLATEbasedir"; - const char *__APPPATH = "TEMPLATEapppath"; - - // iterate through string r - while(*r!='\0') - { - // check for special character - if(*r=='$') - { - if(strncmp(r+1, __ENGINEPATH, strlen(__ENGINEPATH)) == 0) - { - r+=strlen(__ENGINEPATH)+1; - p = g_pGameDescription->mEnginePath.GetBuffer(); - } - else if(strncmp(r+1, __USERHOMEPATH, strlen(__USERHOMEPATH)) == 0) - { - r+=strlen(__USERHOMEPATH)+1; - p = g_qeglobals.m_strHomeGame.GetBuffer(); - } - else if(strncmp(r+1, __BASEDIR, strlen(__BASEDIR)) == 0) - { - r+=strlen(__BASEDIR)+1; - p = g_pGameDescription->mBaseGame; - } - else if(strncmp(r+1, __TOOLSPATH, strlen(__TOOLSPATH)) == 0) - { - r+=strlen(__TOOLSPATH)+1; - p = g_strGameToolsPath.GetBuffer(); - } - else if(strncmp(r+1, __APPPATH, strlen(__APPPATH)) == 0) - { - r+=strlen(__APPPATH)+1; - p = g_strAppPath.GetBuffer(); - } - else - { - r++; - p = "$"; - } - - while(*p!='\0') *w++ = *p++; - } - else *w++ = *r++; - } - *w = '\0'; -} - -/* -=========== -QE_LoadProject -TODO TODO TODO (don't think this got fully merged in) -TTimo: added project file "version", version 2 adds '#' chars to the BSP command strings -version 3 was .. I don't remember .. version 4 adds q3map2 commands -TTimo: when QE_LoadProject is called, the prefs are updated with path to the latest project and saved on disk -=========== -*/ -/*\todo decide on a sensible location/name for project files.*/ -bool QE_LoadProject (const char *projectfile) -{ - char buf[1024]; - xmlDocPtr doc; - xmlNodePtr node, project; - - Sys_Printf("Loading project file: \"%s\"\n", projectfile); - doc = ParseXMLFile(projectfile, true); - - if(doc == NULL) return false; - - node=doc->children; - while(node != NULL && node->type != XML_DTD_NODE) node=node->next; - if(node == NULL || strcmp((char*)node->name, "project") != 0) - { - Sys_FPrintf(SYS_ERR, "ERROR: invalid file type\n"); - return false; - } - - while(node->type != XML_ELEMENT_NODE) node=node->next; - // - project = node; - - if(g_qeglobals.d_project_entity != NULL) Entity_Free(g_qeglobals.d_project_entity); - g_qeglobals.d_project_entity = Entity_Alloc(); - - for(node = project->children; node != NULL; node=node->next) - { - if(node->type != XML_ELEMENT_NODE) continue; - - // - ReplaceTemplates(buf, (char*)node->properties->next->children->content); - - SetKeyValue(g_qeglobals.d_project_entity, (char*)node->properties->children->content, buf); - } - - xmlFreeDoc(doc); - - // project file version checking - // add a version checking to avoid people loading later versions of the project file and bitching - int ver = IntForKey( g_qeglobals.d_project_entity, "version" ); - if (ver > PROJECT_VERSION) - { - char strMsg[1024]; - sprintf (strMsg, "This is a version %d project file. This build only supports <=%d project files.\n" - "Please choose another project file or upgrade your version of Radiant.", ver, PROJECT_VERSION); - gtk_MessageBox (g_pParentWnd->m_pWidget, strMsg, "Can't load project file", MB_ICONERROR | MB_OK); - // set the project file to nothing so we are sure we'll ask next time? - g_PrefsDlg.m_strLastProject = ""; - g_PrefsDlg.SavePrefs(); - return false; - } - - // set here some default project settings you need - if ( strlen( ValueForKey( g_qeglobals.d_project_entity, "brush_primit" ) ) == 0 ) - { - SetKeyValue( g_qeglobals.d_project_entity, "brush_primit", "0" ); - } - - g_qeglobals.m_bBrushPrimitMode = IntForKey( g_qeglobals.d_project_entity, "brush_primit" ); - - g_qeglobals.m_strHomeMaps = g_qeglobals.m_strHomeGame; - const char* str = ValueForKey(g_qeglobals.d_project_entity, "gamename"); - if(str[0] == '\0') str = g_pGameDescription->mBaseGame.GetBuffer(); - g_qeglobals.m_strHomeMaps += str; - g_qeglobals.m_strHomeMaps += '/'; - - // don't forget to create the dirs - Q_mkdir(g_qeglobals.m_strHomeGame.GetBuffer(), 0775); - Q_mkdir(g_qeglobals.m_strHomeMaps.GetBuffer(), 0775); - - // usefull for the log file and debuggin fucked up configurations from users: - // output the basic information of the .qe4 project file - // SPoG - // all these paths should be unix format, with a trailing slash at the end - // if not.. to debug, check that the project file paths are set up correctly - Sys_Printf("basepath : %s\n", ValueForKey( g_qeglobals.d_project_entity, "basepath") ); - Sys_Printf("entitypath : %s\n", ValueForKey( g_qeglobals.d_project_entity, "entitypath" ) ); - - - // check whether user_project key exists.. - // if not, save the current project under a new name - if (ValueForKey(g_qeglobals.d_project_entity, "user_project")[0] == '\0') - { - Sys_Printf("Loaded a template project file\n"); - - // create the user_project key - SetKeyValue( g_qeglobals.d_project_entity, "user_project", "1" ); - - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=672 - if (IntForKey( g_qeglobals.d_project_entity, "version" ) != PROJECT_VERSION) - { - char strMsg[2048]; - sprintf(strMsg, - "The template project '%s' has version %d. The editor binary is configured for version %d.\n" - "This indicates a problem in your setup. See http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=672\n" - "I will keep going with this project till you fix this", - projectfile, IntForKey( g_qeglobals.d_project_entity, "version" ), PROJECT_VERSION); - gtk_MessageBox (g_pParentWnd->m_pWidget, strMsg, "Can't load project file", MB_ICONERROR | MB_OK); - } - - // create the writable project file path - strcpy(buf, g_qeglobals.m_strHomeGame.GetBuffer()); - strcat(buf, g_pGameDescription->mBaseGame.GetBuffer()); - strcat(buf, "/scripts/"); - // while the filename is already in use, increment the number we add to the end - int counter = 0; - char pUser[PATH_MAX]; - while (1) - { - sprintf( pUser, "%suser%d." PROJECT_FILETYPE, buf, counter ); - counter++; - if (access( pUser, R_OK) != 0) - { - // this is the one - strcpy( buf, pUser ); - break; - } - } - // saving project will cause a save prefs - g_PrefsDlg.m_strLastProject = buf; - g_PrefsDlg.m_nLastProjectVer = IntForKey( g_qeglobals.d_project_entity, "version" ); - QE_SaveProject(buf); - } - else - { - // update preferences::LastProject with path of this successfully-loaded project - // save preferences - Sys_Printf("Setting current project in prefs to \"%s\"\n", g_PrefsDlg.m_strLastProject.GetBuffer() ); - g_PrefsDlg.m_strLastProject = projectfile; - g_PrefsDlg.SavePrefs(); - } - - return true; -} - -/* -=========== -QE_SaveProject -TTimo: whenever QE_SaveProject is called, prefs are updated and saved with the path to the project -=========== -*/ -qboolean QE_SaveProject (const char* filename) -{ - Sys_Printf("Save project file '%s'\n", filename); - - xmlNodePtr node; - xmlDocPtr doc = xmlNewDoc((xmlChar *)"1.0"); - // create DTD node - xmlCreateIntSubset(doc, (xmlChar *)"project", NULL, (xmlChar *)"project.dtd"); - // create project node - doc->children->next = xmlNewDocNode(doc, NULL, (xmlChar *)"project", NULL); - - for(epair_t* epair = g_qeglobals.d_project_entity->epairs; epair != NULL; epair = epair->next) - { - node = xmlNewChild(doc->children->next, NULL, (xmlChar *)"key", NULL); - xmlSetProp(node, (xmlChar*)"name", (xmlChar*)epair->key); - xmlSetProp(node, (xmlChar*)"value", (xmlChar*)epair->value); - } - - CreateDirectoryPath(filename); - if (xmlSaveFormatFile(filename, doc, 1) != -1) - { - xmlFreeDoc(doc); - Sys_Printf("Setting current project in prefs to \"%s\"\n", filename ); - g_PrefsDlg.m_strLastProject = filename; - g_PrefsDlg.SavePrefs(); - return TRUE; - } - else - { - xmlFreeDoc(doc); - Sys_FPrintf(SYS_ERR, "failed to save project file: \"%s\"\n", filename); - return FALSE; - } -} - - - -/* -=========== -QE_KeyDown -=========== -*/ -#define SPEED_MOVE 32 -#define SPEED_TURN 22.5 - - -/* -=============== -ConnectEntities - -Sets target / targetname on the two entities selected -from the first selected to the secon -=============== -*/ -void ConnectEntities (void) -{ - entity_t *e1, *e2; - const char *target; - char *newtarg = NULL; - - if (g_qeglobals.d_select_count != 2) - { - Sys_Status ("Must have two brushes selected", 0); - Sys_Beep (); - return; - } - - e1 = g_qeglobals.d_select_order[0]->owner; - e2 = g_qeglobals.d_select_order[1]->owner; - - if (e1 == world_entity || e2 == world_entity) - { - Sys_Status ("Can't connect to the world", 0); - Sys_Beep (); - return; - } - - if (e1 == e2) - { - Sys_Status ("Brushes are from same entity", 0); - Sys_Beep (); - return; - } - - target = ValueForKey (e1, "target"); - if (target && target[0]) - newtarg = g_strdup(target); - else - { - target = ValueForKey(e2, "targetname"); - if(target && target[0]) - newtarg = g_strdup(target); - else - Entity_Connect(e1, e2); - } - - if(newtarg != NULL) - { - SetKeyValue(e1, "target", newtarg); - SetKeyValue(e2, "targetname", newtarg); - g_free(newtarg); - } - - Sys_UpdateWindows (W_XY | W_CAMERA); - - Select_Deselect(); - Select_Brush (g_qeglobals.d_select_order[1]); -} - -qboolean QE_SingleBrush (bool bQuiet) -{ - if ( (selected_brushes.next == &selected_brushes) - || (selected_brushes.next->next != &selected_brushes) ) - { - if (!bQuiet) - { - Sys_Printf ("Error: you must have a single brush selected\n"); - } - return false; - } - if (selected_brushes.next->owner->eclass->fixedsize) - { - if (!bQuiet) - { - Sys_Printf ("Error: you cannot manipulate fixed size entities\n"); - } - return false; - } - - return true; -} - -void QE_InitVFS (void) -{ - // VFS initialization ----------------------- - // we will call vfsInitDirectory, giving the directories to look in (for files in pk3's and for standalone files) - // we need to call in order, the mod ones first, then the base ones .. they will be searched in this order - // *nix systems have a dual filesystem in ~/.q3a, which is searched first .. so we need to add that too - Str directory,prefabs; - - // TTimo: let's leave this to HL mode for now - if (g_pGameDescription->mGameFile == "hl.game") - { - // Hydra: we search the "gametools" path first so that we can provide editor - // specific pk3's wads and misc files for use by the editor. - // the relevant map compiler tools will NOT use this directory, so this helps - // to ensure that editor files are not used/required in release versions of maps - // it also helps keep your editor files all in once place, with the editor modules, - // plugins, scripts and config files. - // it also helps when testing maps, as you'll know your files won't/can't be used - // by the game engine itself. - - // - directory = g_pGameDescription->mGameToolsPath; - vfsInitDirectory(directory.GetBuffer()); - } - - // NOTE TTimo about the mymkdir calls .. this is a bit dirty, but a safe thing on *nix - - // if we have a mod dir - if (*ValueForKey(g_qeglobals.d_project_entity, "gamename") != '\0') - { - -#if defined (__linux__) || defined (__APPLE__) - // ~/./ - directory = g_qeglobals.m_strHomeGame.GetBuffer(); - Q_mkdir (directory.GetBuffer (), 0775); - directory += ValueForKey(g_qeglobals.d_project_entity, "gamename"); - Q_mkdir (directory.GetBuffer (), 0775); - vfsInitDirectory(directory.GetBuffer()); - AddSlash (directory); - prefabs = directory; - // also create the maps dir, it will be used as prompt for load/save - directory += "/maps"; - Q_mkdir (directory, 0775); - // and the prefabs dir - prefabs += "/prefabs"; - Q_mkdir (prefabs, 0775); - -#endif - - // / - directory = g_pGameDescription->mEnginePath; - directory += ValueForKey(g_qeglobals.d_project_entity, "gamename"); - Q_mkdir (directory.GetBuffer (), 0775); - vfsInitDirectory(directory.GetBuffer()); - AddSlash(directory); - prefabs = directory; - // also create the maps dir, it will be used as prompt for load/save - directory += "/maps"; - Q_mkdir (directory.GetBuffer (), 0775); - // and the prefabs dir - prefabs += "/prefabs"; - Q_mkdir (prefabs, 0775); - } - -#if defined (__linux__) || defined (__APPLE__) - // ~/./ - directory = g_qeglobals.m_strHomeGame.GetBuffer(); - directory += g_pGameDescription->mBaseGame; - vfsInitDirectory (directory.GetBuffer ()); -#endif - - // / - directory = g_pGameDescription->mEnginePath; - directory += g_pGameDescription->mBaseGame; - vfsInitDirectory(directory.GetBuffer()); -} - -void QE_Init (void) -{ - /* - ** initialize variables - */ - g_qeglobals.d_gridsize = 8; - g_qeglobals.d_showgrid = true; - - QE_InitVFS(); - - Eclass_Init(); - FillClassList(); // list in entity window - Map_Init(); - - FillTextureMenu(); - FillBSPMenu(); - - /* - ** other stuff - */ - Z_Init (); -} - -void WINAPI QE_ConvertDOSToUnixName( char *dst, const char *src ) -{ - while ( *src ) - { - if ( *src == '\\' ) - *dst = '/'; - else - *dst = *src; - dst++; src++; - } - *dst = 0; -} - -int g_numbrushes, g_numentities; - -void QE_CountBrushesAndUpdateStatusBar( void ) -{ - static int s_lastbrushcount, s_lastentitycount; - static qboolean s_didonce; - - //entity_t *e; - brush_t *b, *next; - - g_numbrushes = 0; - g_numentities = 0; - - if ( active_brushes.next != NULL ) - { - for ( b = active_brushes.next ; b != NULL && b != &active_brushes ; b=next) - { - next = b->next; - if (b->brush_faces ) - { - if ( !b->owner->eclass->fixedsize) - g_numbrushes++; - else - g_numentities++; - } - } - } -/* - if ( entities.next != NULL ) - { - for ( e = entities.next ; e != &entities && g_numentities != MAX_MAP_ENTITIES ; e = e->next) - { - g_numentities++; - } - } -*/ - if ( ( ( g_numbrushes != s_lastbrushcount ) || ( g_numentities != s_lastentitycount ) ) || ( !s_didonce ) ) - { - Sys_UpdateStatusBar(); - - s_lastbrushcount = g_numbrushes; - s_lastentitycount = g_numentities; - s_didonce = true; - } -} - -char com_token[1024]; -qboolean com_eof; - -/* -================ -I_FloatTime -================ -*/ -double I_FloatTime (void) -{ - time_t t; - - time (&t); - - return t; -#if 0 -// more precise, less portable - struct timeval tp; - struct timezone tzp; - static int secbase; - - gettimeofday(&tp, &tzp); - - if (!secbase) - { - secbase = tp.tv_sec; - return tp.tv_usec/1000000.0; - } - - return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0; -#endif -} - - -/* -============== -COM_Parse - -Parse a token out of a string -============== -*/ -char *COM_Parse (char *data) -{ - int c; - int len; - - len = 0; - com_token[0] = 0; - - if (!data) - return NULL; - -// skip whitespace -skipwhite: - while ( (c = *data) <= ' ') - { - if (c == 0) - { - com_eof = true; - return NULL; // end of file; - } - data++; - } - -// skip // comments - if (c=='/' && data[1] == '/') - { - while (*data && *data != '\n') - data++; - goto skipwhite; - } - - -// handle quoted strings specially - if (c == '\"') - { - data++; - do - { - c = *data++; - if (c=='\"') - { - com_token[len] = 0; - return data; - } - com_token[len] = c; - len++; - } while (1); - } - -// parse single characters - if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') - { - com_token[len] = c; - len++; - com_token[len] = 0; - return data+1; - } - -// parse a regular word - do - { - com_token[len] = c; - data++; - len++; - c = *data; - if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') - break; - } while (c>32); - - com_token[len] = 0; - return data; -} - -char* Get_COM_Token() -{ - return com_token; -} - -/* -============================================================================= - - MISC FUNCTIONS - -============================================================================= -*/ - - -int argc; -char *argv[MAX_NUM_ARGVS]; - -/* -============ -ParseCommandLine -============ -*/ -void ParseCommandLine (char *lpCmdLine) -{ - argc = 1; - argv[0] = "programname"; - - while (*lpCmdLine && (argc < MAX_NUM_ARGVS)) - { - while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126))) - lpCmdLine++; - - if (*lpCmdLine) - { - argv[argc] = lpCmdLine; - argc++; - - while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126))) - lpCmdLine++; - - if (*lpCmdLine) - { - *lpCmdLine = 0; - lpCmdLine++; - } - - } - } -} - - - -/* -================= -CheckParm - -Checks for the given parameter in the program's command line arguments -Returns the argument number (1 to argc-1) or 0 if not present -================= -*/ -int CheckParm (char *check) -{ - int i; - - for (i = 1;i= '0' && *str <= '9') - num += *str-'0'; - else if (*str >= 'a' && *str <= 'f') - num += 10 + *str-'a'; - else if (*str >= 'A' && *str <= 'F') - num += 10 + *str-'A'; - else - Error ("Bad hex number: %s",hex); - str++; - } - - return num; -} - - -int ParseNum (char *str) -{ - if (str[0] == '$') - return ParseHex (str+1); - if (str[0] == '0' && str[1] == 'x') - return ParseHex (str+2); - return atol (str); -} - -// BSP frontend plugin -// global flag for BSP frontend plugin is g_qeglobals.bBSPFrontendPlugin -_QERPlugBSPFrontendTable g_BSPFrontendTable; - -// ============================================================================= -// Sys_ functions - -bool Sys_AltDown () -{ -#ifdef _WIN32 - return (GetKeyState(VK_MENU) & 0x8000) != 0; -#endif - -#if defined (__linux__) || defined (__APPLE__) - char keys[32]; - int x; - - XQueryKeymap(GDK_DISPLAY(), keys); - - x = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_L); - if (keys[x/8] & (1 << (x % 8))) - return true; - - x = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_R); - if (keys[x/8] & (1 << (x % 8))) - return true; - - return false; -#endif -} - -bool Sys_ShiftDown () -{ -#ifdef _WIN32 - return (GetKeyState(VK_SHIFT) & 0x8000) != 0; -#endif - -#if defined (__linux__) || defined (__APPLE__) - char keys[32]; - int x; - - XQueryKeymap(GDK_DISPLAY(), keys); - - x = XKeysymToKeycode (GDK_DISPLAY(), XK_Shift_L); - if (keys[x/8] & (1 << (x % 8))) - return true; - - x = XKeysymToKeycode (GDK_DISPLAY(), XK_Shift_R); - if (keys[x/8] & (1 << (x % 8))) - return true; - - return false; -#endif -} - -void Sys_MarkMapModified (void) -{ - char title[PATH_MAX]; - - if (modified != 1) - { - modified = true; // mark the map as changed - sprintf (title, "%s *", currentmap); - - QE_ConvertDOSToUnixName( title, title ); - Sys_SetTitle (title); - } -} - -void Sys_SetTitle (const char *text) -{ - gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_main_window), text); -} - -bool g_bWaitCursor = false; - -void WINAPI Sys_BeginWait (void) -{ - GdkCursor *cursor = gdk_cursor_new (GDK_WATCH); - gdk_window_set_cursor (g_pParentWnd->m_pWidget->window, cursor); - gdk_cursor_unref (cursor); - g_bWaitCursor = true; -} - -void WINAPI Sys_EndWait (void) -{ - GdkCursor *cursor = gdk_cursor_new (GDK_LEFT_PTR); - gdk_window_set_cursor (g_pParentWnd->m_pWidget->window, cursor); - gdk_cursor_unref (cursor); - g_bWaitCursor = false; -} - -void Sys_GetCursorPos (int *x, int *y) -{ - // FIXME: not multihead safe - gdk_window_get_pointer (NULL, x, y, NULL); -} - -void Sys_SetCursorPos (int x, int y) -{ - // NOTE: coordinates are in GDK space, not OS space -#ifdef _WIN32 - int sys_x = x - g_pParentWnd->GetGDKOffsetX(); - int sys_y = y - g_pParentWnd->GetGDKOffsetY(); - - SetCursorPos (sys_x, sys_y); -#endif - -#if defined (__linux__) || defined (__APPLE__) - XWarpPointer (GDK_DISPLAY(), None, GDK_ROOT_WINDOW(), 0, 0, 0, 0, x, y); -#endif -} - -void Sys_Beep (void) -{ -#if defined (__linux__) || defined (__APPLE__) - gdk_beep (); -#else - MessageBeep (MB_ICONASTERISK); -#endif -} - -double Sys_DoubleTime (void) -{ - return clock()/ 1000.0; -} - -/* -=============================================================== - - STATUS WINDOW - -=============================================================== -*/ - -void Sys_UpdateStatusBar( void ) -{ - extern int g_numbrushes, g_numentities; - - char numbrushbuffer[100]=""; - - sprintf( numbrushbuffer, "Brushes: %d Entities: %d", g_numbrushes, g_numentities ); - g_pParentWnd->SetStatusText(2, numbrushbuffer); - //Sys_Status( numbrushbuffer, 2 ); -} - -void Sys_Status(const char *psz, int part ) -{ - g_pParentWnd->SetStatusText (part, psz); -} - -// ============================================================================= -// MRU - -#define MRU_MAX 4 -static GtkWidget *MRU_items[MRU_MAX]; -static int MRU_used; -typedef char MRU_filename_t[PATH_MAX]; -MRU_filename_t MRU_filenames[MRU_MAX]; - -static char* MRU_GetText (int index) -{ - return MRU_filenames[index]; -} - -void buffer_write_escaped_mnemonic(char* buffer, const char* string) -{ - while(*string != '\0') - { - if(*string == '_') - { - *buffer++ = '_'; - } - - *buffer++ = *string++; - } - *buffer = '\0'; -} - -static void MRU_SetText (int index, const char *filename) -{ - strcpy(MRU_filenames[index], filename); - - char mnemonic[PATH_MAX * 2 + 4]; - mnemonic[0] = '_'; - sprintf(mnemonic+1, "%d", index+1); - mnemonic[2] = '-'; - mnemonic[3] = ' '; - buffer_write_escaped_mnemonic(mnemonic+4, filename); - gtk_label_set_text_with_mnemonic(GTK_LABEL (GTK_BIN (MRU_items[index])->child), mnemonic); -} - -void MRU_Load () -{ - int i = g_PrefsDlg.m_nMRUCount; - - if(i > 4) - i = 4; //FIXME: make this a define - - for (; i > 0; i--) - MRU_AddFile (g_PrefsDlg.m_strMRUFiles[i-1].GetBuffer()); -} - -void MRU_Save () -{ - g_PrefsDlg.m_nMRUCount = MRU_used; - - for (int i = 0; i < MRU_used; i++) - g_PrefsDlg.m_strMRUFiles[i] = MRU_GetText (i); -} - -void MRU_AddWidget (GtkWidget *widget, int pos) -{ - if (pos < MRU_MAX) - MRU_items[pos] = widget; -} - -void MRU_AddFile (const char *str) -{ - int i; - char* text; - - // check if file is already in our list - for (i = 0; i < MRU_used; i++) - { - text = MRU_GetText (i); - - if (strcmp (text, str) == 0) - { - // reorder menu - for (; i > 0; i--) - MRU_SetText (i, MRU_GetText (i-1)); - - MRU_SetText (0, str); - - return; - } - } - - if (MRU_used < MRU_MAX) - MRU_used++; - - // move items down - for (i = MRU_used-1; i > 0; i--) - MRU_SetText (i, MRU_GetText (i-1)); - - MRU_SetText (0, str); - gtk_widget_set_sensitive (MRU_items[0], TRUE); - gtk_widget_show (MRU_items[MRU_used-1]); -} - -void MRU_Activate (int index) -{ - char *text = MRU_GetText (index); - - if (access (text, R_OK) == 0) - { - text = strdup (text); - MRU_AddFile (text); - Map_LoadFile (text); - free (text); - } - else - { - MRU_used--; - - for (int i = index; i < MRU_used; i++) - MRU_SetText (i, MRU_GetText (i+1)); - - if (MRU_used == 0) - { - gtk_label_set_text (GTK_LABEL (GTK_BIN (MRU_items[0])->child), "Recent Files"); - gtk_widget_set_sensitive (MRU_items[0], FALSE); - } - else - { - gtk_widget_hide (MRU_items[MRU_used]); - } - } -} - -/* -====================================================================== - -FILE DIALOGS - -====================================================================== -*/ - -qboolean ConfirmModified () -{ - if (!modified) - return true; - - if (gtk_MessageBox (g_pParentWnd->m_pWidget, "This will lose changes to the map", "warning", MB_OKCANCEL) == IDCANCEL) - return false; - return true; -} - -void ProjectDialog () -{ - const char *filename; - char buffer[NAME_MAX]; - - /* - * Obtain the system directory name and - * store it in buffer. - */ - - strcpy(buffer, g_qeglobals.m_strHomeGame.GetBuffer()); - strcat(buffer, g_pGameDescription->mBaseGame.GetBuffer()); - strcat (buffer, "/scripts/"); - - // Display the Open dialog box - filename = file_dialog (NULL, TRUE, "Open File", buffer, "project"); - - if (filename == NULL) - return; // canceled - - // Open the file. - // NOTE: QE_LoadProject takes care of saving prefs with new path to the project file - if (!QE_LoadProject(filename)) - Sys_Printf ("Failed to load project from file: %s\n", filename); - else - // FIXME TTimo QE_Init is probably broken if you don't call it during startup right now .. - QE_Init(); -} - -/* -======================================================= - -Menu modifications - -======================================================= -*/ - -/* -================== -FillBSPMenu - -================== -*/ -char *bsp_commands[256]; - -void FillBSPMenu () -{ - GtkWidget *item, *menu; // menu points to a GtkMenu (not an item) - epair_t *ep; - GList *lst; - int i; - - menu = GTK_WIDGET (g_object_get_data (G_OBJECT (g_qeglobals_gui.d_main_window), "menu_bsp")); - - while ((lst = gtk_container_children (GTK_CONTAINER (menu))) != NULL) - gtk_container_remove (GTK_CONTAINER (menu), GTK_WIDGET (lst->data)); - - if (g_PrefsDlg.m_bDetachableMenus) { - item = gtk_tearoff_menu_item_new (); - gtk_menu_append (GTK_MENU (menu), item); - gtk_widget_set_sensitive (item, TRUE); - gtk_widget_show (item); - } - - if (g_qeglobals.bBSPFrontendPlugin) - { - CString str = g_BSPFrontendTable.m_pfnGetBSPMenu(); - char cTemp[1024]; - strcpy(cTemp, str); - char* token = strtok(cTemp, ",;"); - if (token && *token == ' ') - { - while (*token == ' ') - token++; - } - i = 0; - - // first token is menu name - item = gtk_menu_get_attach_widget (GTK_MENU (menu)); - gtk_label_set_text (GTK_LABEL (GTK_BIN (item)->child), token); - - token = strtok(NULL, ",;"); - while (token != NULL) - { - g_BSPFrontendCommands = g_slist_append (g_BSPFrontendCommands, g_strdup (token)); - item = gtk_menu_item_new_with_label (token); - gtk_widget_show (item); - gtk_container_add (GTK_CONTAINER (menu), item); - gtk_signal_connect (GTK_OBJECT (item), "activate", - GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (CMD_BSPCOMMAND+i)); - token = strtok(NULL, ",;"); - i++; - } - } - else - { - i = 0; - for (ep = g_qeglobals.d_project_entity->epairs; ep; ep = ep->next) - { - if (strncmp(ep->key, "bsp_", 4)==0) - { - bsp_commands[i] = ep->key; - item = gtk_menu_item_new_with_label (ep->key+4); - gtk_widget_show (item); - gtk_container_add (GTK_CONTAINER (menu), item); - gtk_signal_connect (GTK_OBJECT (item), "activate", - GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (CMD_BSPCOMMAND+i)); - i++; - } - } - } -} - -//============================================== - -void AddSlash(CString& strPath) -{ - if (strPath.GetLength() > 0) - { - if ((strPath.GetAt(strPath.GetLength()-1) != '/') && - (strPath.GetAt(strPath.GetLength()-1) != '\\')) - strPath += '/'; - } -} - -bool ExtractPath_and_Filename(const char* pPath, CString& strPath, CString& strFilename) -{ - CString strPathName; - strPathName = pPath; - int nSlash = strPathName.ReverseFind('\\'); - if (nSlash == -1) - // TTimo: try forward slash, some are using forward - nSlash = strPathName.ReverseFind('/'); - if (nSlash >= 0) - { - strPath = strPathName.Left(nSlash+1); - strFilename = strPathName.Right(strPathName.GetLength() - nSlash - 1); - } - // TTimo: try forward slash, some are using forward - else - strFilename = pPath; - return true; -} - -//=========================================== - -//++timo FIXME: no longer used .. remove! -char *TranslateString (char *buf) -{ - static char buf2[32768]; - int i, l; - char *out; - - l = strlen(buf); - out = buf2; - for (i=0 ; i +#include +#include "gtkmisc.h" +#if defined (__linux__) || defined (__APPLE__) +#include +#include +#include +#include +#endif +// for the logging part +#include +#include + +QEGlobals_t g_qeglobals; +QEGlobals_GUI_t g_qeglobals_gui; + +// leo: Track memory allocations for debugging +// NOTE TTimo this was never used and probably not relevant +// there are tools to do that +#ifdef MEM_DEBUG + +static GList *memblocks; + +void* debug_malloc (size_t size, const char* file, int line) +{ + void *buf = g_malloc (size + 8); + + *((const char**)buf) = file; + buf = (char*)buf + 4; + *((int*)buf) = line; + buf = (char*)buf + 4; + + memblocks = g_list_append (memblocks, buf); + + return buf; +} + +void debug_free (void *buf, const char* file, int line) +{ + const char *f; + int l; + + if (g_list_find (memblocks, buf)) + { + memblocks = g_list_remove (memblocks, buf); + + buf = (char*)buf - 4; + l = *((int*)buf); + buf = (char*)buf - 4; + f = *((const char**)buf); + + Sys_FPrintf (SYS_DBG, "free: %s %d", file, line); + Sys_FPrintf (SYS_DBG, " allocated: %s %d\n", f, l); + + g_free (buf); + } +// else +// free (buf); // from qmalloc, will leak unless we add this same hack to cmdlib +} + +#endif + +vec_t Rad_rint (vec_t in) +{ + if (g_PrefsDlg.m_bNoClamp) + return in; + else + return (float)floor (in + 0.5); +} + +void WINAPI QE_CheckOpenGLForErrors(void) +{ + char strMsg[1024]; + int i = qglGetError(); + if (i != GL_NO_ERROR) + { + if (i == GL_OUT_OF_MEMORY) + { + sprintf(strMsg, "OpenGL out of memory error %s\nDo you wish to save before exiting?", qgluErrorString((GLenum)i)); + if (gtk_MessageBox(g_pParentWnd->m_pWidget, strMsg, "Radiant Error", MB_YESNO) == IDYES) + { + Map_SaveFile(NULL, false); + } + _exit(1); + } + else + { + Sys_Printf ("Warning: OpenGL Error %s\n", qgluErrorString((GLenum)i)); + } + } +} + +// NOTE: don't this function, use VFS instead +char *ExpandReletivePath (char *p) +{ + static char temp[1024]; + const char *base; + + if (!p || !p[0]) + return NULL; + if (p[0] == '/' || p[0] == '\\') + return p; + + base = ValueForKey(g_qeglobals.d_project_entity, "basepath"); + sprintf (temp, "%s/%s", base, p); + return temp; +} + +char *copystring (char *s) +{ + char *b; + b = (char*)malloc(strlen(s)+1); + strcpy (b,s); + return b; +} + + +bool DoesFileExist(const char* pBuff, long& lSize) +{ + FileStream file; + if (file.Open(pBuff, "r")) + { + lSize += file.GetLength(); + file.Close(); + return true; + } + return false; +} + + +void Map_Snapshot() +{ + CString strMsg; + + // I hope the modified flag is kept correctly up to date + if (!modified) + return; + + // we need to do the following + // 1. make sure the snapshot directory exists (create it if it doesn't) + // 2. find out what the lastest save is based on number + // 3. inc that and save the map + CString strOrgPath, strOrgFile; + ExtractPath_and_Filename(currentmap, strOrgPath, strOrgFile); + AddSlash(strOrgPath); + strOrgPath += "snapshots"; + bool bGo = true; + struct stat Stat; + if (stat(strOrgPath, &Stat) == -1) + { +#ifdef _WIN32 + bGo = (_mkdir(strOrgPath) != -1); +#endif + +#if defined (__linux__) || defined (__APPLE__) + bGo = (mkdir(strOrgPath,0755) != -1); +#endif + } + AddSlash(strOrgPath); + if (bGo) + { + int nCount = 0; + long lSize = 0; + CString strNewPath; + strNewPath = strOrgPath; + strNewPath += strOrgFile; + CString strFile; + while (bGo) + { + char buf[PATH_MAX]; + sprintf( buf, "%s.%i", strNewPath.GetBuffer(), nCount ); + strFile = buf; + bGo = DoesFileExist(strFile, lSize); + nCount++; + } + // strFile has the next available slot + Map_SaveFile(strFile, false); + // it is still a modified map (we enter this only if this is a modified map) + Sys_SetTitle (currentmap); + Sys_MarkMapModified(); + if (lSize > 12 * 1024 * 1024) // total size of saves > 4 mb + { + Sys_Printf("The snapshot files in %s total more than 4 megabytes. You might consider cleaning up.", strOrgPath.GetBuffer()); + } + } + else + { + strMsg.Format("Snapshot save failed.. unabled to create directory\n%s", strOrgPath.GetBuffer()); + gtk_MessageBox(g_pParentWnd->m_pWidget, strMsg); + } + strOrgPath = ""; + strOrgFile = ""; +} +/* +=============== +QE_CheckAutoSave + +If five minutes have passed since making a change +and the map hasn't been saved, save it out. +=============== +*/ + + +void QE_CheckAutoSave( void ) +{ + static time_t s_start; + time_t now; + time (&now); + + if (modified != 1 || !s_start) + { + s_start = now; + return; + } + + if ((now - s_start) > (60 * g_PrefsDlg.m_nAutoSave)) + { + if (g_PrefsDlg.m_bAutoSave) + { + CString strMsg; + strMsg = g_PrefsDlg.m_bSnapShots ? "Autosaving snapshot..." : "Autosaving..."; + Sys_Printf(strMsg); + Sys_Printf("\n"); + Sys_Status (strMsg,0); + + // only snapshot if not working on a default map + if (g_PrefsDlg.m_bSnapShots && stricmp(currentmap, "unnamed.map") != 0) + { + Map_Snapshot(); + } + else + { + Map_SaveFile (ValueForKey(g_qeglobals.d_project_entity, "autosave"), false); + } + + Sys_Status ("Autosaving...Saved.", 0 ); + modified = 2; + } + else + { + Sys_Printf ("Autosave skipped...\n"); + Sys_Status ("Autosave skipped...", 0 ); + } + s_start = now; + } +} + + +// NOTE TTimo we don't like that BuildShortPathName too much +// the VFS provides a vfsCleanFileName which should perform the cleanup tasks +// in the long run I'd like to completely get rid of this + +// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=144 +// used to be disabled, but caused problems + +// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=291 +// can't work with long win32 names until the BSP commands are not working differently +#ifdef _WIN32 +int BuildShortPathName(const char* pPath, char* pBuffer, int nBufferLen) +{ + char *pFile = NULL; + int nResult = GetFullPathName(pPath, nBufferLen, pBuffer, &pFile); + nResult = GetShortPathName(pPath, pBuffer, nBufferLen); + if (nResult == 0) + strcpy(pBuffer, pPath); // Use long filename + return nResult; +} +#endif + +#if defined (__linux__) || defined (__APPLE__) +int BuildShortPathName(const char* pPath, char* pBuffer, int nBufferLen) +{ + // remove /../ from directories + const char *scr = pPath; char *dst = pBuffer; + for (int i = 0; (i < nBufferLen) && (*scr != 0); i++) + { + if (*scr == '/' && *(scr+1) == '.' && *(scr+2) == '.') + { + scr += 3; + while (dst != pBuffer && *(--dst) != '/') + { + i--; + } + } + + *dst = *scr; + + scr++; dst++; + } + *dst = 0; + + return strlen (pBuffer); +} +#endif + +/* +const char *g_pPathFixups[]= +{ + "basepath", + "autosave", +}; + +const int g_nPathFixupCount = sizeof(g_pPathFixups) / sizeof(const char*); + +void QE_CheckProjectEntity() +{ + char *pFile; + char pBuff[PATH_MAX]; + char pNewPath[PATH_MAX]; + for (int i = 0; i < g_nPathFixupCount; i++) + { + char *pPath = ValueForKey (g_qeglobals.d_project_entity, g_pPathFixups[i]); + + strcpy (pNewPath, pPath); + if (pPath[0] != '\\' && pPath[0] != '/') + if (GetFullPathName(pPath, PATH_MAX, pBuff, &pFile)) + strcpy (pNewPath, pBuff); + + BuildShortPathName (pNewPath, pBuff, PATH_MAX); + + // check it's not ending with a filename seperator + if (pBuff[strlen(pBuff)-1] == '/' || pBuff[strlen(pBuff)-1] == '\\') + { + Sys_FPrintf(SYS_WRN, "WARNING: \"%s\" path in the project file has an ending file seperator, fixing.\n", g_pPathFixups[i]); + pBuff[strlen(pBuff)-1]=0; + } + + SetKeyValue(g_qeglobals.d_project_entity, g_pPathFixups[i], pBuff); + } +} +*/ + +void HandleXMLError( void* ctxt, const char* text, ... ) +{ + va_list argptr; + static char buf[32768]; + + va_start (argptr,text); + vsprintf (buf, text, argptr); + Sys_FPrintf (SYS_ERR, "XML %s\n", buf); + va_end (argptr); +} + +#define DTD_BUFFER_LENGTH 1024 +xmlDocPtr ParseXMLStream(IDataStream *stream, bool validate = false) +{ + xmlDocPtr doc = NULL; + bool wellFormed = false, valid = false; + int res, size = 1024; + char chars[1024]; + xmlParserCtxtPtr ctxt; + + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=433 + //if(validate) + // xmlDoValidityCheckingDefaultValue = 1; + //else + xmlDoValidityCheckingDefaultValue = 0; + xmlSetGenericErrorFunc(NULL, HandleXMLError); + + // SPoG + // HACK: use AppPath to resolve DTD location + // do a buffer-safe string copy and concatenate + int i; + char* w; + const char* r; + char buf[DTD_BUFFER_LENGTH]; + + w = buf; + i = 0; + // copy + //assert(g_strAppPath.GetBuffer() != NULL); + for(r = g_strAppPath.GetBuffer(); iRead(chars, 4); + if (res > 0) + { + ctxt = xmlCreatePushParserCtxt(NULL, NULL, chars, res, buf); + + while ((res = stream->Read(chars, size)) > 0) + { + xmlParseChunk(ctxt, chars, res, 0); + } + xmlParseChunk(ctxt, chars, 0, 1); + doc = ctxt->myDoc; + + wellFormed = (ctxt->wellFormed == 1); + valid = (ctxt->valid == 1); + + xmlFreeParserCtxt(ctxt); + } + + if(wellFormed && (!validate || (validate && valid))) + return doc; + + if(doc != NULL) + xmlFreeDoc(doc); + + return NULL; +} + +xmlDocPtr ParseXMLFile(const char* filename, bool validate = false) +{ + FileStream stream; + if (stream.Open(filename, "r")) + return ParseXMLStream(&stream, validate); + + Sys_FPrintf(SYS_ERR, "Failed to open file: %s\n",filename); + return NULL; +} + +// copy a string r to a buffer w +// replace $string as appropriate +void ReplaceTemplates(char* w, const char* r) +{ + const char *p; + const char *__ENGINEPATH = "TEMPLATEenginepath"; + const char *__USERHOMEPATH = "TEMPLATEuserhomepath"; + const char *__TOOLSPATH = "TEMPLATEtoolspath"; + const char *__BASEDIR = "TEMPLATEbasedir"; + const char *__APPPATH = "TEMPLATEapppath"; + + // iterate through string r + while(*r!='\0') + { + // check for special character + if(*r=='$') + { + if(strncmp(r+1, __ENGINEPATH, strlen(__ENGINEPATH)) == 0) + { + r+=strlen(__ENGINEPATH)+1; + p = g_pGameDescription->mEnginePath.GetBuffer(); + } + else if(strncmp(r+1, __USERHOMEPATH, strlen(__USERHOMEPATH)) == 0) + { + r+=strlen(__USERHOMEPATH)+1; + p = g_qeglobals.m_strHomeGame.GetBuffer(); + } + else if(strncmp(r+1, __BASEDIR, strlen(__BASEDIR)) == 0) + { + r+=strlen(__BASEDIR)+1; + p = g_pGameDescription->mBaseGame; + } + else if(strncmp(r+1, __TOOLSPATH, strlen(__TOOLSPATH)) == 0) + { + r+=strlen(__TOOLSPATH)+1; + p = g_strGameToolsPath.GetBuffer(); + } + else if(strncmp(r+1, __APPPATH, strlen(__APPPATH)) == 0) + { + r+=strlen(__APPPATH)+1; + p = g_strAppPath.GetBuffer(); + } + else + { + r++; + p = "$"; + } + + while(*p!='\0') *w++ = *p++; + } + else *w++ = *r++; + } + *w = '\0'; +} + +/* +=========== +QE_LoadProject +TODO TODO TODO (don't think this got fully merged in) +TTimo: added project file "version", version 2 adds '#' chars to the BSP command strings +version 3 was .. I don't remember .. version 4 adds q3map2 commands +TTimo: when QE_LoadProject is called, the prefs are updated with path to the latest project and saved on disk +=========== +*/ +/*\todo decide on a sensible location/name for project files.*/ +bool QE_LoadProject (const char *projectfile) +{ + char buf[1024]; + xmlDocPtr doc; + xmlNodePtr node, project; + + Sys_Printf("Loading project file: \"%s\"\n", projectfile); + doc = ParseXMLFile(projectfile, true); + + if(doc == NULL) return false; + + node=doc->children; + while(node != NULL && node->type != XML_DTD_NODE) node=node->next; + if(node == NULL || strcmp((char*)node->name, "project") != 0) + { + Sys_FPrintf(SYS_ERR, "ERROR: invalid file type\n"); + return false; + } + + while(node->type != XML_ELEMENT_NODE) node=node->next; + // + project = node; + + if(g_qeglobals.d_project_entity != NULL) Entity_Free(g_qeglobals.d_project_entity); + g_qeglobals.d_project_entity = Entity_Alloc(); + + for(node = project->children; node != NULL; node=node->next) + { + if(node->type != XML_ELEMENT_NODE) continue; + + // + ReplaceTemplates(buf, (char*)node->properties->next->children->content); + + SetKeyValue(g_qeglobals.d_project_entity, (char*)node->properties->children->content, buf); + } + + xmlFreeDoc(doc); + + // project file version checking + // add a version checking to avoid people loading later versions of the project file and bitching + int ver = IntForKey( g_qeglobals.d_project_entity, "version" ); + if (ver > PROJECT_VERSION) + { + char strMsg[1024]; + sprintf (strMsg, "This is a version %d project file. This build only supports <=%d project files.\n" + "Please choose another project file or upgrade your version of Radiant.", ver, PROJECT_VERSION); + gtk_MessageBox (g_pParentWnd->m_pWidget, strMsg, "Can't load project file", MB_ICONERROR | MB_OK); + // set the project file to nothing so we are sure we'll ask next time? + g_PrefsDlg.m_strLastProject = ""; + g_PrefsDlg.SavePrefs(); + return false; + } + + // set here some default project settings you need + if ( strlen( ValueForKey( g_qeglobals.d_project_entity, "brush_primit" ) ) == 0 ) + { + SetKeyValue( g_qeglobals.d_project_entity, "brush_primit", "0" ); + } + + g_qeglobals.m_bBrushPrimitMode = IntForKey( g_qeglobals.d_project_entity, "brush_primit" ); + + g_qeglobals.m_strHomeMaps = g_qeglobals.m_strHomeGame; + const char* str = ValueForKey(g_qeglobals.d_project_entity, "gamename"); + if(str[0] == '\0') str = g_pGameDescription->mBaseGame.GetBuffer(); + g_qeglobals.m_strHomeMaps += str; + g_qeglobals.m_strHomeMaps += '/'; + + // don't forget to create the dirs + Q_mkdir(g_qeglobals.m_strHomeGame.GetBuffer(), 0775); + Q_mkdir(g_qeglobals.m_strHomeMaps.GetBuffer(), 0775); + + // usefull for the log file and debuggin fucked up configurations from users: + // output the basic information of the .qe4 project file + // SPoG + // all these paths should be unix format, with a trailing slash at the end + // if not.. to debug, check that the project file paths are set up correctly + Sys_Printf("basepath : %s\n", ValueForKey( g_qeglobals.d_project_entity, "basepath") ); + Sys_Printf("entitypath : %s\n", ValueForKey( g_qeglobals.d_project_entity, "entitypath" ) ); + + + // check whether user_project key exists.. + // if not, save the current project under a new name + if (ValueForKey(g_qeglobals.d_project_entity, "user_project")[0] == '\0') + { + Sys_Printf("Loaded a template project file\n"); + + // create the user_project key + SetKeyValue( g_qeglobals.d_project_entity, "user_project", "1" ); + + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=672 + if (IntForKey( g_qeglobals.d_project_entity, "version" ) != PROJECT_VERSION) + { + char strMsg[2048]; + sprintf(strMsg, + "The template project '%s' has version %d. The editor binary is configured for version %d.\n" + "This indicates a problem in your setup. See http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=672\n" + "I will keep going with this project till you fix this", + projectfile, IntForKey( g_qeglobals.d_project_entity, "version" ), PROJECT_VERSION); + gtk_MessageBox (g_pParentWnd->m_pWidget, strMsg, "Can't load project file", MB_ICONERROR | MB_OK); + } + + // create the writable project file path + strcpy(buf, g_qeglobals.m_strHomeGame.GetBuffer()); + strcat(buf, g_pGameDescription->mBaseGame.GetBuffer()); + strcat(buf, "/scripts/"); + // while the filename is already in use, increment the number we add to the end + int counter = 0; + char pUser[PATH_MAX]; + while (1) + { + sprintf( pUser, "%suser%d." PROJECT_FILETYPE, buf, counter ); + counter++; + if (access( pUser, R_OK) != 0) + { + // this is the one + strcpy( buf, pUser ); + break; + } + } + // saving project will cause a save prefs + g_PrefsDlg.m_strLastProject = buf; + g_PrefsDlg.m_nLastProjectVer = IntForKey( g_qeglobals.d_project_entity, "version" ); + QE_SaveProject(buf); + } + else + { + // update preferences::LastProject with path of this successfully-loaded project + // save preferences + Sys_Printf("Setting current project in prefs to \"%s\"\n", g_PrefsDlg.m_strLastProject.GetBuffer() ); + g_PrefsDlg.m_strLastProject = projectfile; + g_PrefsDlg.SavePrefs(); + } + + return true; +} + +/* +=========== +QE_SaveProject +TTimo: whenever QE_SaveProject is called, prefs are updated and saved with the path to the project +=========== +*/ +qboolean QE_SaveProject (const char* filename) +{ + Sys_Printf("Save project file '%s'\n", filename); + + xmlNodePtr node; + xmlDocPtr doc = xmlNewDoc((xmlChar *)"1.0"); + // create DTD node + xmlCreateIntSubset(doc, (xmlChar *)"project", NULL, (xmlChar *)"project.dtd"); + // create project node + doc->children->next = xmlNewDocNode(doc, NULL, (xmlChar *)"project", NULL); + + for(epair_t* epair = g_qeglobals.d_project_entity->epairs; epair != NULL; epair = epair->next) + { + node = xmlNewChild(doc->children->next, NULL, (xmlChar *)"key", NULL); + xmlSetProp(node, (xmlChar*)"name", (xmlChar*)epair->key); + xmlSetProp(node, (xmlChar*)"value", (xmlChar*)epair->value); + } + + CreateDirectoryPath(filename); + if (xmlSaveFormatFile(filename, doc, 1) != -1) + { + xmlFreeDoc(doc); + Sys_Printf("Setting current project in prefs to \"%s\"\n", filename ); + g_PrefsDlg.m_strLastProject = filename; + g_PrefsDlg.SavePrefs(); + return TRUE; + } + else + { + xmlFreeDoc(doc); + Sys_FPrintf(SYS_ERR, "failed to save project file: \"%s\"\n", filename); + return FALSE; + } +} + + + +/* +=========== +QE_KeyDown +=========== +*/ +#define SPEED_MOVE 32 +#define SPEED_TURN 22.5 + + +/* +=============== +ConnectEntities + +Sets target / targetname on the two entities selected +from the first selected to the secon +=============== +*/ +void ConnectEntities (void) +{ + entity_t *e1, *e2; + const char *target; + char *newtarg = NULL; + + if (g_qeglobals.d_select_count != 2) + { + Sys_Status ("Must have two brushes selected", 0); + Sys_Beep (); + return; + } + + e1 = g_qeglobals.d_select_order[0]->owner; + e2 = g_qeglobals.d_select_order[1]->owner; + + if (e1 == world_entity || e2 == world_entity) + { + Sys_Status ("Can't connect to the world", 0); + Sys_Beep (); + return; + } + + if (e1 == e2) + { + Sys_Status ("Brushes are from same entity", 0); + Sys_Beep (); + return; + } + + target = ValueForKey (e1, "target"); + if (target && target[0]) + newtarg = g_strdup(target); + else + { + target = ValueForKey(e2, "targetname"); + if(target && target[0]) + newtarg = g_strdup(target); + else + Entity_Connect(e1, e2); + } + + if(newtarg != NULL) + { + SetKeyValue(e1, "target", newtarg); + SetKeyValue(e2, "targetname", newtarg); + g_free(newtarg); + } + + Sys_UpdateWindows (W_XY | W_CAMERA); + + Select_Deselect(); + Select_Brush (g_qeglobals.d_select_order[1]); +} + +qboolean QE_SingleBrush (bool bQuiet) +{ + if ( (selected_brushes.next == &selected_brushes) + || (selected_brushes.next->next != &selected_brushes) ) + { + if (!bQuiet) + { + Sys_Printf ("Error: you must have a single brush selected\n"); + } + return false; + } + if (selected_brushes.next->owner->eclass->fixedsize) + { + if (!bQuiet) + { + Sys_Printf ("Error: you cannot manipulate fixed size entities\n"); + } + return false; + } + + return true; +} + +void QE_InitVFS (void) +{ + // VFS initialization ----------------------- + // we will call vfsInitDirectory, giving the directories to look in (for files in pk3's and for standalone files) + // we need to call in order, the mod ones first, then the base ones .. they will be searched in this order + // *nix systems have a dual filesystem in ~/.q3a, which is searched first .. so we need to add that too + Str directory,prefabs; + + // TTimo: let's leave this to HL mode for now + if (g_pGameDescription->mGameFile == "hl.game") + { + // Hydra: we search the "gametools" path first so that we can provide editor + // specific pk3's wads and misc files for use by the editor. + // the relevant map compiler tools will NOT use this directory, so this helps + // to ensure that editor files are not used/required in release versions of maps + // it also helps keep your editor files all in once place, with the editor modules, + // plugins, scripts and config files. + // it also helps when testing maps, as you'll know your files won't/can't be used + // by the game engine itself. + + // + directory = g_pGameDescription->mGameToolsPath; + vfsInitDirectory(directory.GetBuffer()); + } + + // NOTE TTimo about the mymkdir calls .. this is a bit dirty, but a safe thing on *nix + + // if we have a mod dir + if (*ValueForKey(g_qeglobals.d_project_entity, "gamename") != '\0') + { + +#if defined (__linux__) || defined (__APPLE__) + // ~/./ + directory = g_qeglobals.m_strHomeGame.GetBuffer(); + Q_mkdir (directory.GetBuffer (), 0775); + directory += ValueForKey(g_qeglobals.d_project_entity, "gamename"); + Q_mkdir (directory.GetBuffer (), 0775); + vfsInitDirectory(directory.GetBuffer()); + AddSlash (directory); + prefabs = directory; + // also create the maps dir, it will be used as prompt for load/save + directory += "/maps"; + Q_mkdir (directory, 0775); + // and the prefabs dir + prefabs += "/prefabs"; + Q_mkdir (prefabs, 0775); + +#endif + + // / + directory = g_pGameDescription->mEnginePath; + directory += ValueForKey(g_qeglobals.d_project_entity, "gamename"); + Q_mkdir (directory.GetBuffer (), 0775); + vfsInitDirectory(directory.GetBuffer()); + AddSlash(directory); + prefabs = directory; + // also create the maps dir, it will be used as prompt for load/save + directory += "/maps"; + Q_mkdir (directory.GetBuffer (), 0775); + // and the prefabs dir + prefabs += "/prefabs"; + Q_mkdir (prefabs, 0775); + } + +#if defined (__linux__) || defined (__APPLE__) + // ~/./ + directory = g_qeglobals.m_strHomeGame.GetBuffer(); + directory += g_pGameDescription->mBaseGame; + vfsInitDirectory (directory.GetBuffer ()); +#endif + + // / + directory = g_pGameDescription->mEnginePath; + directory += g_pGameDescription->mBaseGame; + vfsInitDirectory(directory.GetBuffer()); +} + +void QE_Init (void) +{ + /* + ** initialize variables + */ + g_qeglobals.d_gridsize = 8; + g_qeglobals.d_showgrid = true; + + QE_InitVFS(); + + Eclass_Init(); + FillClassList(); // list in entity window + Map_Init(); + + FillTextureMenu(); + FillBSPMenu(); + + /* + ** other stuff + */ + Z_Init (); +} + +void WINAPI QE_ConvertDOSToUnixName( char *dst, const char *src ) +{ + while ( *src ) + { + if ( *src == '\\' ) + *dst = '/'; + else + *dst = *src; + dst++; src++; + } + *dst = 0; +} + +int g_numbrushes, g_numentities; + +void QE_CountBrushesAndUpdateStatusBar( void ) +{ + static int s_lastbrushcount, s_lastentitycount; + static qboolean s_didonce; + + //entity_t *e; + brush_t *b, *next; + + g_numbrushes = 0; + g_numentities = 0; + + if ( active_brushes.next != NULL ) + { + for ( b = active_brushes.next ; b != NULL && b != &active_brushes ; b=next) + { + next = b->next; + if (b->brush_faces ) + { + if ( !b->owner->eclass->fixedsize) + g_numbrushes++; + else + g_numentities++; + } + } + } +/* + if ( entities.next != NULL ) + { + for ( e = entities.next ; e != &entities && g_numentities != MAX_MAP_ENTITIES ; e = e->next) + { + g_numentities++; + } + } +*/ + if ( ( ( g_numbrushes != s_lastbrushcount ) || ( g_numentities != s_lastentitycount ) ) || ( !s_didonce ) ) + { + Sys_UpdateStatusBar(); + + s_lastbrushcount = g_numbrushes; + s_lastentitycount = g_numentities; + s_didonce = true; + } +} + +char com_token[1024]; +qboolean com_eof; + +/* +================ +I_FloatTime +================ +*/ +double I_FloatTime (void) +{ + time_t t; + + time (&t); + + return t; +#if 0 +// more precise, less portable + struct timeval tp; + struct timezone tzp; + static int secbase; + + gettimeofday(&tp, &tzp); + + if (!secbase) + { + secbase = tp.tv_sec; + return tp.tv_usec/1000000.0; + } + + return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0; +#endif +} + + +/* +============== +COM_Parse + +Parse a token out of a string +============== +*/ +char *COM_Parse (char *data) +{ + int c; + int len; + + len = 0; + com_token[0] = 0; + + if (!data) + return NULL; + +// skip whitespace +skipwhite: + while ( (c = *data) <= ' ') + { + if (c == 0) + { + com_eof = true; + return NULL; // end of file; + } + data++; + } + +// skip // comments + if (c=='/' && data[1] == '/') + { + while (*data && *data != '\n') + data++; + goto skipwhite; + } + + +// handle quoted strings specially + if (c == '\"') + { + data++; + do + { + c = *data++; + if (c=='\"') + { + com_token[len] = 0; + return data; + } + com_token[len] = c; + len++; + } while (1); + } + +// parse single characters + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') + { + com_token[len] = c; + len++; + com_token[len] = 0; + return data+1; + } + +// parse a regular word + do + { + com_token[len] = c; + data++; + len++; + c = *data; + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') + break; + } while (c>32); + + com_token[len] = 0; + return data; +} + +char* Get_COM_Token() +{ + return com_token; +} + +/* +============================================================================= + + MISC FUNCTIONS + +============================================================================= +*/ + + +int argc; +char *argv[MAX_NUM_ARGVS]; + +/* +============ +ParseCommandLine +============ +*/ +void ParseCommandLine (char *lpCmdLine) +{ + argc = 1; + argv[0] = "programname"; + + while (*lpCmdLine && (argc < MAX_NUM_ARGVS)) + { + while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126))) + lpCmdLine++; + + if (*lpCmdLine) + { + argv[argc] = lpCmdLine; + argc++; + + while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126))) + lpCmdLine++; + + if (*lpCmdLine) + { + *lpCmdLine = 0; + lpCmdLine++; + } + + } + } +} + + + +/* +================= +CheckParm + +Checks for the given parameter in the program's command line arguments +Returns the argument number (1 to argc-1) or 0 if not present +================= +*/ +int CheckParm (char *check) +{ + int i; + + for (i = 1;i= '0' && *str <= '9') + num += *str-'0'; + else if (*str >= 'a' && *str <= 'f') + num += 10 + *str-'a'; + else if (*str >= 'A' && *str <= 'F') + num += 10 + *str-'A'; + else + Error ("Bad hex number: %s",hex); + str++; + } + + return num; +} + + +int ParseNum (char *str) +{ + if (str[0] == '$') + return ParseHex (str+1); + if (str[0] == '0' && str[1] == 'x') + return ParseHex (str+2); + return atol (str); +} + +// BSP frontend plugin +// global flag for BSP frontend plugin is g_qeglobals.bBSPFrontendPlugin +_QERPlugBSPFrontendTable g_BSPFrontendTable; + +// ============================================================================= +// Sys_ functions + +bool Sys_AltDown () +{ +#ifdef _WIN32 + return (GetKeyState(VK_MENU) & 0x8000) != 0; +#endif + +#if defined (__linux__) || defined (__APPLE__) + char keys[32]; + int x; + + XQueryKeymap(GDK_DISPLAY(), keys); + + x = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_L); + if (keys[x/8] & (1 << (x % 8))) + return true; + + x = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_R); + if (keys[x/8] & (1 << (x % 8))) + return true; + + return false; +#endif +} + +bool Sys_ShiftDown () +{ +#ifdef _WIN32 + return (GetKeyState(VK_SHIFT) & 0x8000) != 0; +#endif + +#if defined (__linux__) || defined (__APPLE__) + char keys[32]; + int x; + + XQueryKeymap(GDK_DISPLAY(), keys); + + x = XKeysymToKeycode (GDK_DISPLAY(), XK_Shift_L); + if (keys[x/8] & (1 << (x % 8))) + return true; + + x = XKeysymToKeycode (GDK_DISPLAY(), XK_Shift_R); + if (keys[x/8] & (1 << (x % 8))) + return true; + + return false; +#endif +} + +void Sys_MarkMapModified (void) +{ + char title[PATH_MAX]; + + if (modified != 1) + { + modified = true; // mark the map as changed + sprintf (title, "%s *", currentmap); + + QE_ConvertDOSToUnixName( title, title ); + Sys_SetTitle (title); + } +} + +void Sys_SetTitle (const char *text) +{ + gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_main_window), text); +} + +bool g_bWaitCursor = false; + +void WINAPI Sys_BeginWait (void) +{ + GdkCursor *cursor = gdk_cursor_new (GDK_WATCH); + gdk_window_set_cursor (g_pParentWnd->m_pWidget->window, cursor); + gdk_cursor_unref (cursor); + g_bWaitCursor = true; +} + +void WINAPI Sys_EndWait (void) +{ + GdkCursor *cursor = gdk_cursor_new (GDK_LEFT_PTR); + gdk_window_set_cursor (g_pParentWnd->m_pWidget->window, cursor); + gdk_cursor_unref (cursor); + g_bWaitCursor = false; +} + +void Sys_GetCursorPos (int *x, int *y) +{ + // FIXME: not multihead safe + gdk_window_get_pointer (NULL, x, y, NULL); +} + +void Sys_SetCursorPos (int x, int y) +{ + // NOTE: coordinates are in GDK space, not OS space +#ifdef _WIN32 + int sys_x = x - g_pParentWnd->GetGDKOffsetX(); + int sys_y = y - g_pParentWnd->GetGDKOffsetY(); + + SetCursorPos (sys_x, sys_y); +#endif + +#if defined (__linux__) || defined (__APPLE__) + XWarpPointer (GDK_DISPLAY(), None, GDK_ROOT_WINDOW(), 0, 0, 0, 0, x, y); +#endif +} + +void Sys_Beep (void) +{ +#if defined (__linux__) || defined (__APPLE__) + gdk_beep (); +#else + MessageBeep (MB_ICONASTERISK); +#endif +} + +double Sys_DoubleTime (void) +{ + return clock()/ 1000.0; +} + +/* +=============================================================== + + STATUS WINDOW + +=============================================================== +*/ + +void Sys_UpdateStatusBar( void ) +{ + extern int g_numbrushes, g_numentities; + + char numbrushbuffer[100]=""; + + sprintf( numbrushbuffer, "Brushes: %d Entities: %d", g_numbrushes, g_numentities ); + g_pParentWnd->SetStatusText(2, numbrushbuffer); + //Sys_Status( numbrushbuffer, 2 ); +} + +void Sys_Status(const char *psz, int part ) +{ + g_pParentWnd->SetStatusText (part, psz); +} + +// ============================================================================= +// MRU + +#define MRU_MAX 4 +static GtkWidget *MRU_items[MRU_MAX]; +static int MRU_used; +typedef char MRU_filename_t[PATH_MAX]; +MRU_filename_t MRU_filenames[MRU_MAX]; + +static char* MRU_GetText (int index) +{ + return MRU_filenames[index]; +} + +void buffer_write_escaped_mnemonic(char* buffer, const char* string) +{ + while(*string != '\0') + { + if(*string == '_') + { + *buffer++ = '_'; + } + + *buffer++ = *string++; + } + *buffer = '\0'; +} + +static void MRU_SetText (int index, const char *filename) +{ + strcpy(MRU_filenames[index], filename); + + char mnemonic[PATH_MAX * 2 + 4]; + mnemonic[0] = '_'; + sprintf(mnemonic+1, "%d", index+1); + mnemonic[2] = '-'; + mnemonic[3] = ' '; + buffer_write_escaped_mnemonic(mnemonic+4, filename); + gtk_label_set_text_with_mnemonic(GTK_LABEL (GTK_BIN (MRU_items[index])->child), mnemonic); +} + +void MRU_Load () +{ + int i = g_PrefsDlg.m_nMRUCount; + + if(i > 4) + i = 4; //FIXME: make this a define + + for (; i > 0; i--) + MRU_AddFile (g_PrefsDlg.m_strMRUFiles[i-1].GetBuffer()); +} + +void MRU_Save () +{ + g_PrefsDlg.m_nMRUCount = MRU_used; + + for (int i = 0; i < MRU_used; i++) + g_PrefsDlg.m_strMRUFiles[i] = MRU_GetText (i); +} + +void MRU_AddWidget (GtkWidget *widget, int pos) +{ + if (pos < MRU_MAX) + MRU_items[pos] = widget; +} + +void MRU_AddFile (const char *str) +{ + int i; + char* text; + + // check if file is already in our list + for (i = 0; i < MRU_used; i++) + { + text = MRU_GetText (i); + + if (strcmp (text, str) == 0) + { + // reorder menu + for (; i > 0; i--) + MRU_SetText (i, MRU_GetText (i-1)); + + MRU_SetText (0, str); + + return; + } + } + + if (MRU_used < MRU_MAX) + MRU_used++; + + // move items down + for (i = MRU_used-1; i > 0; i--) + MRU_SetText (i, MRU_GetText (i-1)); + + MRU_SetText (0, str); + gtk_widget_set_sensitive (MRU_items[0], TRUE); + gtk_widget_show (MRU_items[MRU_used-1]); +} + +void MRU_Activate (int index) +{ + char *text = MRU_GetText (index); + + if (access (text, R_OK) == 0) + { + text = strdup (text); + MRU_AddFile (text); + Map_LoadFile (text); + free (text); + } + else + { + MRU_used--; + + for (int i = index; i < MRU_used; i++) + MRU_SetText (i, MRU_GetText (i+1)); + + if (MRU_used == 0) + { + gtk_label_set_text (GTK_LABEL (GTK_BIN (MRU_items[0])->child), "Recent Files"); + gtk_widget_set_sensitive (MRU_items[0], FALSE); + } + else + { + gtk_widget_hide (MRU_items[MRU_used]); + } + } +} + +/* +====================================================================== + +FILE DIALOGS + +====================================================================== +*/ + +qboolean ConfirmModified () +{ + if (!modified) + return true; + + if (gtk_MessageBox (g_pParentWnd->m_pWidget, "This will lose changes to the map", "warning", MB_OKCANCEL) == IDCANCEL) + return false; + return true; +} + +void ProjectDialog () +{ + const char *filename; + char buffer[NAME_MAX]; + + /* + * Obtain the system directory name and + * store it in buffer. + */ + + strcpy(buffer, g_qeglobals.m_strHomeGame.GetBuffer()); + strcat(buffer, g_pGameDescription->mBaseGame.GetBuffer()); + strcat (buffer, "/scripts/"); + + // Display the Open dialog box + filename = file_dialog (NULL, TRUE, "Open File", buffer, "project"); + + if (filename == NULL) + return; // canceled + + // Open the file. + // NOTE: QE_LoadProject takes care of saving prefs with new path to the project file + if (!QE_LoadProject(filename)) + Sys_Printf ("Failed to load project from file: %s\n", filename); + else + // FIXME TTimo QE_Init is probably broken if you don't call it during startup right now .. + QE_Init(); +} + +/* +======================================================= + +Menu modifications + +======================================================= +*/ + +/* +================== +FillBSPMenu + +================== +*/ +char *bsp_commands[256]; + +void FillBSPMenu () +{ + GtkWidget *item, *menu; // menu points to a GtkMenu (not an item) + epair_t *ep; + GList *lst; + int i; + + menu = GTK_WIDGET (g_object_get_data (G_OBJECT (g_qeglobals_gui.d_main_window), "menu_bsp")); + + while ((lst = gtk_container_children (GTK_CONTAINER (menu))) != NULL) + gtk_container_remove (GTK_CONTAINER (menu), GTK_WIDGET (lst->data)); + + if (g_PrefsDlg.m_bDetachableMenus) { + item = gtk_tearoff_menu_item_new (); + gtk_menu_append (GTK_MENU (menu), item); + gtk_widget_set_sensitive (item, TRUE); + gtk_widget_show (item); + } + + if (g_qeglobals.bBSPFrontendPlugin) + { + CString str = g_BSPFrontendTable.m_pfnGetBSPMenu(); + char cTemp[1024]; + strcpy(cTemp, str); + char* token = strtok(cTemp, ",;"); + if (token && *token == ' ') + { + while (*token == ' ') + token++; + } + i = 0; + + // first token is menu name + item = gtk_menu_get_attach_widget (GTK_MENU (menu)); + gtk_label_set_text (GTK_LABEL (GTK_BIN (item)->child), token); + + token = strtok(NULL, ",;"); + while (token != NULL) + { + g_BSPFrontendCommands = g_slist_append (g_BSPFrontendCommands, g_strdup (token)); + item = gtk_menu_item_new_with_label (token); + gtk_widget_show (item); + gtk_container_add (GTK_CONTAINER (menu), item); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (CMD_BSPCOMMAND+i)); + token = strtok(NULL, ",;"); + i++; + } + } + else + { + i = 0; + for (ep = g_qeglobals.d_project_entity->epairs; ep; ep = ep->next) + { + if (strncmp(ep->key, "bsp_", 4)==0) + { + bsp_commands[i] = ep->key; + item = gtk_menu_item_new_with_label (ep->key+4); + gtk_widget_show (item); + gtk_container_add (GTK_CONTAINER (menu), item); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (HandleCommand), GINT_TO_POINTER (CMD_BSPCOMMAND+i)); + i++; + } + } + } +} + +//============================================== + +void AddSlash(CString& strPath) +{ + if (strPath.GetLength() > 0) + { + if ((strPath.GetAt(strPath.GetLength()-1) != '/') && + (strPath.GetAt(strPath.GetLength()-1) != '\\')) + strPath += '/'; + } +} + +bool ExtractPath_and_Filename(const char* pPath, CString& strPath, CString& strFilename) +{ + CString strPathName; + strPathName = pPath; + int nSlash = strPathName.ReverseFind('\\'); + if (nSlash == -1) + // TTimo: try forward slash, some are using forward + nSlash = strPathName.ReverseFind('/'); + if (nSlash >= 0) + { + strPath = strPathName.Left(nSlash+1); + strFilename = strPathName.Right(strPathName.GetLength() - nSlash - 1); + } + // TTimo: try forward slash, some are using forward + else + strFilename = pPath; + return true; +} + +//=========================================== + +//++timo FIXME: no longer used .. remove! +char *TranslateString (char *buf) +{ + static char buf2[32768]; + int i, l; + char *out; + + l = strlen(buf); + out = buf2; + for (i=0 ; id_texture->name[0] == '(') - { - g_ptr_array_add (notex_faces, face); - return; - } - - for (i = 0; i < len; i++) - if (sort[i].texture == face->d_texture) - { - g_ptr_array_add (sort[i].faces, face); - return; - } - - if (len == alloc) - { - alloc += 8; - sort = (windingsort_t*)realloc (sort, alloc*sizeof(windingsort_t)); - - for (i = len; i < alloc; i++) - sort[i].faces = g_ptr_array_new (); - } - g_ptr_array_set_size (sort[len].faces, 0); - g_ptr_array_add (sort[len].faces, face); - sort[len].texture = face->d_texture; - len++; -} - -void QueueDraw () -{ - guint32 i, k; - face_t *face; - winding_t *w; - int j, nDrawMode = g_pParentWnd->GetCamera().draw_mode; - - if (notex_faces->len) - { - qglDisable (GL_TEXTURE_2D); - - for (i = 0; i < notex_faces->len; i++) - { - face = (face_t*)notex_faces->pdata[i]; - w = face->face_winding; - - qglBegin (GL_POLYGON); - - /* - if (b->patchBrush) - //++timo FIXME: find a use case for this?? - qglColor4f (face->d_color[0], face->d_color[1], face->d_color[2], 0.13); - else - */ - qglColor4f (face->d_color[0], face->d_color[1], face->d_color[2], face->pShader->getTrans ()); - - if (g_PrefsDlg.m_bGLLighting) - qglNormal3fv (face->plane.normal); - - for (j = 0; j < w->numpoints; j++) - { - if (nDrawMode == cd_texture || nDrawMode == cd_light) - qglTexCoord2fv( &w->points[j][3] ); - qglVertex3fv(w->points[j]); - } - - qglEnd (); - } - } - - if (!len) - return; - - if (nDrawMode == cd_texture || nDrawMode == cd_light) - qglEnable (GL_TEXTURE_2D); - - for (k = 0; k < len; k++) - { - qglBindTexture (GL_TEXTURE_2D, sort[k].texture->texture_number); - - for (i = 0; i < sort[k].faces->len; i++) - { - face = (face_t*)sort[k].faces->pdata[i]; - w = face->face_winding; - - qglBegin (GL_POLYGON); - /* - if (b->patchBrush) - //++timo FIXME: find a use case for this?? - qglColor4f (face->d_color[0], face->d_color[1], face->d_color[2], 0.13); - else - */ - qglColor4f (face->d_color[0], face->d_color[1], face->d_color[2], face->pShader->getTrans ()); - - if (g_PrefsDlg.m_bGLLighting) - qglNormal3fv (face->plane.normal); - - for (j = 0; j < w->numpoints; j++) - { - if (nDrawMode == cd_texture || nDrawMode == cd_light) - qglTexCoord2fv( &w->points[j][3] ); - qglVertex3fv(w->points[j]); - } - - qglEnd (); - } - } - qglBindTexture (GL_TEXTURE_2D, 0); -} +/* +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 +*/ + +// +// Try to sort the faces by texture and make rendering faster +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" + +typedef struct +{ + qtexture_t* texture; + GPtrArray* faces; +} windingsort_t; + +static windingsort_t* sort; +static guint32 alloc, len; +static GPtrArray* notex_faces; + +void QueueClear () +{ + len = 0; + + if (notex_faces == NULL) + notex_faces = g_ptr_array_new (); + g_ptr_array_set_size (notex_faces, 0); +} + +void QueueFace (face_t *face) +{ + guint32 i; + + if (face->d_texture->name[0] == '(') + { + g_ptr_array_add (notex_faces, face); + return; + } + + for (i = 0; i < len; i++) + if (sort[i].texture == face->d_texture) + { + g_ptr_array_add (sort[i].faces, face); + return; + } + + if (len == alloc) + { + alloc += 8; + sort = (windingsort_t*)realloc (sort, alloc*sizeof(windingsort_t)); + + for (i = len; i < alloc; i++) + sort[i].faces = g_ptr_array_new (); + } + g_ptr_array_set_size (sort[len].faces, 0); + g_ptr_array_add (sort[len].faces, face); + sort[len].texture = face->d_texture; + len++; +} + +void QueueDraw () +{ + guint32 i, k; + face_t *face; + winding_t *w; + int j, nDrawMode = g_pParentWnd->GetCamera().draw_mode; + + if (notex_faces->len) + { + qglDisable (GL_TEXTURE_2D); + + for (i = 0; i < notex_faces->len; i++) + { + face = (face_t*)notex_faces->pdata[i]; + w = face->face_winding; + + qglBegin (GL_POLYGON); + + /* + if (b->patchBrush) + //++timo FIXME: find a use case for this?? + qglColor4f (face->d_color[0], face->d_color[1], face->d_color[2], 0.13); + else + */ + qglColor4f (face->d_color[0], face->d_color[1], face->d_color[2], face->pShader->getTrans ()); + + if (g_PrefsDlg.m_bGLLighting) + qglNormal3fv (face->plane.normal); + + for (j = 0; j < w->numpoints; j++) + { + if (nDrawMode == cd_texture || nDrawMode == cd_light) + qglTexCoord2fv( &w->points[j][3] ); + qglVertex3fv(w->points[j]); + } + + qglEnd (); + } + } + + if (!len) + return; + + if (nDrawMode == cd_texture || nDrawMode == cd_light) + qglEnable (GL_TEXTURE_2D); + + for (k = 0; k < len; k++) + { + qglBindTexture (GL_TEXTURE_2D, sort[k].texture->texture_number); + + for (i = 0; i < sort[k].faces->len; i++) + { + face = (face_t*)sort[k].faces->pdata[i]; + w = face->face_winding; + + qglBegin (GL_POLYGON); + /* + if (b->patchBrush) + //++timo FIXME: find a use case for this?? + qglColor4f (face->d_color[0], face->d_color[1], face->d_color[2], 0.13); + else + */ + qglColor4f (face->d_color[0], face->d_color[1], face->d_color[2], face->pShader->getTrans ()); + + if (g_PrefsDlg.m_bGLLighting) + qglNormal3fv (face->plane.normal); + + for (j = 0; j < w->numpoints; j++) + { + if (nDrawMode == cd_texture || nDrawMode == cd_light) + qglTexCoord2fv( &w->points[j][3] ); + qglVertex3fv(w->points[j]); + } + + qglEnd (); + } + } + qglBindTexture (GL_TEXTURE_2D, 0); +} diff --git a/radiant/select.cpp b/radiant/select.cpp index 72637684..f563d2de 100644 --- a/radiant/select.cpp +++ b/radiant/select.cpp @@ -1,2125 +1,2125 @@ -/* -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 -*/ - -// select.c -#include "stdafx.h" -#include -#include "filters.h" - -// externs -CPtrArray g_SelectedFaces; -CPtrArray g_SelectedFaceBrushes; -CPtrArray& g_ptrSelectedFaces = g_SelectedFaces; -CPtrArray& g_ptrSelectedFaceBrushes = g_SelectedFaceBrushes; - -/* -=========== -Test_Ray -=========== -*/ -#define DIST_START 999999 -trace_t Test_Ray (vec3_t origin, vec3_t dir, int flags) -{ - brush_t *brush; - face_t *face; - float dist; - trace_t t; - - memset (&t, 0, sizeof(t)); - t.dist = DIST_START; - - if (flags & SF_CYCLE) - { - CPtrArray array; - brush_t *pToSelect = (selected_brushes.next != &selected_brushes) ? selected_brushes.next : NULL; - Select_Deselect(); - - // go through active brushes and accumulate all "hit" brushes - for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next) - { - //if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity) - // continue; - - if (brush->bFiltered) - continue; - - if (!g_PrefsDlg.m_bSelectCurves && brush->patchBrush) - continue; - - if (!g_PrefsDlg.m_bSelectModels && (brush->owner->eclass->nShowFlags & ECLASS_MISCMODEL)) - continue; - - //if (!g_bShowPatchBounds && brush->patchBrush) - // continue; - - face = Brush_Ray (origin, dir, brush, &dist, flags); - - if (face) - array.Add(brush); - } - - int nSize = array.GetSize(); - if (nSize > 0) - { - bool bFound = false; - for (int i = 0; i < nSize; i++) - { - brush_t *b = reinterpret_cast(array.GetAt(i)); - // did we hit the last one selected yet ? - if (b == pToSelect) - { - // yes we want to select the next one in the list - int n = (i > 0) ? i-1 : nSize-1; - pToSelect = reinterpret_cast(array.GetAt(n)); - bFound = true; - break; - } - } - if (!bFound) - pToSelect = reinterpret_cast(array.GetAt(0)); - } - if (pToSelect) - { - face = Brush_Ray (origin, dir, pToSelect, &dist, flags); - t.dist = dist; - t.brush = pToSelect; - t.face = face; - t.selected = false; - return t; - } - } - - if (! (flags & SF_SELECTED_ONLY) ) - { - for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next) - { - if ( (flags & SF_ENTITIES_FIRST) && (brush->owner == world_entity || !brush->owner->eclass->fixedsize)) - continue; - - if (brush->bFiltered) - continue; - - if (!g_PrefsDlg.m_bSelectCurves && brush->patchBrush) - continue; - - if (!g_PrefsDlg.m_bSelectModels && (brush->owner->eclass->nShowFlags & ECLASS_MISCMODEL)) - continue; - - //if (!g_bShowPatchBounds && brush->patchBrush) - // continue; - - face = Brush_Ray (origin, dir, brush, &dist, flags); - if (face && dist > 0 && dist < t.dist) - { - t.dist = dist; - t.brush = brush; - t.face = face; - t.selected = false; - } - } - } - - - for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next) - { - if ( (flags & SF_ENTITIES_FIRST) && (brush->owner == world_entity || !brush->owner->eclass->fixedsize)) - continue; - - if (brush->bFiltered) - continue; - - if (!g_PrefsDlg.m_bSelectCurves && brush->patchBrush) - continue; - - if (!g_PrefsDlg.m_bSelectModels && (brush->owner->eclass->nShowFlags & ECLASS_MISCMODEL)) - continue; - - face = Brush_Ray (origin, dir, brush, &dist, flags); - if (dist > 0 && dist < t.dist) - { - t.dist = dist; - t.brush = brush; - t.face = face; - t.selected = true; - } - } - - // if entites first, but didn't find any, check regular - - if ( (flags & SF_ENTITIES_FIRST) && t.brush == NULL) - return Test_Ray (origin, dir, flags & ~SF_ENTITIES_FIRST); - - return t; - -} - - -/* -============ -Select_Brush - -============ -*/ -void Select_Brush (brush_t *brush, bool bComplete, bool bStatus) -{ - brush_t *b; - entity_t *e; - - g_ptrSelectedFaces.RemoveAll(); - g_ptrSelectedFaceBrushes.RemoveAll(); - if (g_qeglobals.d_select_count < 2) - g_qeglobals.d_select_order[g_qeglobals.d_select_count] = brush; - g_qeglobals.d_select_count++; - - e = brush->owner; - if (e) - { - // select complete entity on first click - if (e != world_entity && bComplete == true) - { - for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - if (b->owner == e) - goto singleselect; - for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext) - { - if( b == brush ) // make sure we add the actual selected brush last, mainly for cycle select - continue; - Brush_RemoveFromList (b); - Brush_AddToList (b, &selected_brushes); - } - Brush_RemoveFromList (brush); - Brush_AddToList (brush, &selected_brushes); - } - else - { - singleselect: - Brush_RemoveFromList (brush); - Brush_AddToList (brush, &selected_brushes); - UpdatePatchInspector(); - } - - if (e->eclass) - { - UpdateEntitySel(brush->owner->eclass); - } - - UpdateSurfaceDialog(); - } - - if (bStatus) - { - vec3_t vMin, vMax, vSize; - Select_GetBounds (vMin, vMax); - VectorSubtract(vMax, vMin, vSize); - CString strStatus; - strStatus.Format("Selection X:: %.1f Y:: %.1f Z:: %.1f", vSize[0], vSize[1], vSize[2]); - g_pParentWnd->SetStatusText(2, strStatus); - } -} - -/* -============= -Select_FaceInSelectedBrushes -============= -*/ -bool Select_FaceInSelectedBrushes( face_t *face ) -{ - brush_t *brush; - face_t *tface; - - for(brush = selected_brushes.next; brush != &selected_brushes; brush = brush->next) - { - for(tface = brush->brush_faces; tface; tface = tface->next) - { - if(tface == face) - { - return true; - } - } - } - - return false; -} - -/* -============ -Select_Ray - -If the origin is inside a brush, that brush will be ignored. -============ -*/ -void Select_Ray (vec3_t origin, vec3_t dir, int flags) -{ - trace_t t; - face_t *tface; - bool bOk; - static trace_t lastTrace = { - NULL, // brush - NULL, // face - 0, // dist - false // selected - }; - - t = Test_Ray (origin, dir, flags); - if (!t.brush) - return; - - if (flags & SF_SINGLEFACE) - { - if( flags & SF_DRAG ) - { - if ( t.brush == lastTrace.brush && t.face == lastTrace.face ) - return; - } - lastTrace = t; - - if(Select_FaceInSelectedBrushes(t.face)) - { - // Deselect the brush - Brush_RemoveFromList (t.brush); - Brush_AddToList (t.brush, &active_brushes); - UpdatePatchInspector(); - - // Select all of the brush's faces except the one we are pointing at - for( tface = t.brush->brush_faces; tface; tface = tface->next ) - { - if( tface == t.face ) - continue; - - bOk = true; - // NOTE: keep the size check in the loop, we remove stuff inside - for (int i = 0; i < g_SelectedFaces.GetSize(); i++) - { - if (tface == reinterpret_cast(g_SelectedFaces.GetAt(i))) - bOk = false; - } - - if(bOk) - { - g_SelectedFaces.Add(tface); - g_SelectedFaceBrushes.Add(t.brush); - } - } - g_qeglobals.d_select_mode = sel_facets_off; - } - else - { - bOk = true; - // NOTE: keep the size check in the loop, we remove stuff inside - for (int i = 0; i < g_SelectedFaces.GetSize(); i++) - { - if (t.face == reinterpret_cast(g_SelectedFaces.GetAt(i))) - { - bOk = false; - if( flags & SF_DRAG_ON ) - continue; - - g_qeglobals.d_select_mode = sel_facets_off; - // need to remove i'th entry - g_SelectedFaces.RemoveAt(i, 1); - g_SelectedFaceBrushes.RemoveAt(i, 1); - } - } - - if (bOk && !(flags & SF_DRAG_OFF)) - { - g_SelectedFaces.Add(t.face); - g_SelectedFaceBrushes.Add(t.brush); - g_qeglobals.d_select_mode = sel_facets_on; - } - } - UpdateSurfaceDialog(); - Sys_UpdateWindows (W_ALL); - //g_qeglobals.d_select_mode = sel_brush; - // Texture_SetTexture requires a brushprimit_texdef fitted to the default width=2 height=2 texture - brushprimit_texdef_t brushprimit_texdef; - ConvertTexMatWithQTexture ( &t.face->brushprimit_texdef, t.face->d_texture, &brushprimit_texdef, NULL ); - Texture_SetTexture ( &t.face->texdef, &brushprimit_texdef, false, NULL, false ); - return; - } - - // move the brush to the other list - if (t.selected) - { - if( flags & SF_DRAG_ON ) - return; - - g_qeglobals.d_select_mode = sel_brush_off; - Brush_RemoveFromList (t.brush); - Brush_AddToList (t.brush, &active_brushes); - - UpdatePatchInspector(); - } - else - { - if( flags & SF_DRAG_OFF ) - return; - - g_qeglobals.d_select_mode = sel_brush_on; - Select_Brush (t.brush, g_PrefsDlg.m_nCamDragMultiSelect == 1 ? Sys_AltDown () : !Sys_AltDown ()); - } - UpdateSurfaceDialog(); - Sys_UpdateWindows (W_ALL); -} - - -void Select_Delete (void) -{ - brush_t *brush; - entity_t *e; - - g_ptrSelectedFaces.RemoveAll(); - g_ptrSelectedFaceBrushes.RemoveAll(); - - g_qeglobals.d_select_mode = sel_brush; - - g_qeglobals.d_select_count = 0; - g_qeglobals.d_num_move_points = 0; - while (selected_brushes.next != &selected_brushes) - { - brush = selected_brushes.next; - if (brush->patchBrush) - { - Patch_Delete(brush->pPatch); - } - e = brush->owner; - Brush_Free (brush); - // remove if no brushes - if (e != world_entity && e->brushes.onext == &e->brushes) - Entity_Free(e); - } - - Sys_MarkMapModified (); - UpdateSurfaceDialog(); - Sys_UpdateWindows (W_ALL); -} - -// update the workzone to a given brush -void UpdateWorkzone_ForBrush( brush_t* b ) -{ - VectorCopy( b->mins, g_qeglobals.d_work_min ); - VectorCopy( b->maxs, g_qeglobals.d_work_max ); - //++timo clean -#if 0 - // will update the workzone to the given brush - // g_pParentWnd->ActiveXY()->GetViewType() - // cf VIEWTYPE defintion: enum VIEWTYPE {YZ, XZ, XY}; - // we fit our work zone to the last brush on the list (b) - int nViewType = g_pParentWnd->ActiveXY()->GetViewType(); - int nDim1 = (nViewType == YZ) ? 1 : 0; - int nDim2 = (nViewType == XY) ? 1 : 2; - g_qeglobals.d_work_min[nDim1] = b->mins[nDim1]; - g_qeglobals.d_work_max[nDim1] = b->maxs[nDim1]; - g_qeglobals.d_work_min[nDim2] = b->mins[nDim2]; - g_qeglobals.d_work_max[nDim2] = b->maxs[nDim2]; -#endif -} - -// here to filter new brushes once unselected -extern void PerformFiltering(); - -void Select_Deselect (bool bDeselectFaces) -{ - brush_t *b; - - Patch_Deselect(); - - g_pParentWnd->ActiveXY()->UndoClear(); - - g_qeglobals.d_workcount++; - g_qeglobals.d_select_count = 0; - g_qeglobals.d_num_move_points = 0; - b = selected_brushes.next; - - if (b == &selected_brushes) - { - if (bDeselectFaces) - { - g_ptrSelectedFaces.RemoveAll(); - g_ptrSelectedFaceBrushes.RemoveAll(); - } - PerformFiltering(); - UpdateSurfaceDialog(); - Sys_UpdateWindows (W_ALL); - return; - } - - if (bDeselectFaces) - { - g_ptrSelectedFaces.RemoveAll(); - g_ptrSelectedFaceBrushes.RemoveAll(); - } - - g_qeglobals.d_select_mode = sel_brush; - - UpdateWorkzone_ForBrush(b); - - selected_brushes.next->prev = &active_brushes; - selected_brushes.prev->next = active_brushes.next; - active_brushes.next->prev = selected_brushes.prev; - active_brushes.next = selected_brushes.next; - selected_brushes.prev = selected_brushes.next = &selected_brushes; - - // filter newly created stuff once it's unselected - PerformFiltering(); - UpdateSurfaceDialog(); - Sys_UpdateWindows (W_ALL); -} - -/* -============ -Select_Move -============ -*/ -/*! Moves the currently selected brush/patch - \param delta How far to move the selection (x,y,z) - \param bSnap If the move should snap to grid points -*/ -void Select_Move (vec3_t delta, bool bSnap) -{ - brush_t *b; - - // actually move the selected brushes - for (b = selected_brushes.next ; b != &selected_brushes ; b=b->next) - Brush_Move (b, delta, bSnap); - - vec3_t vMin, vMax; - Select_GetBounds (vMin, vMax); - CString strStatus; - strStatus.Format("Origin X:: %.1f Y:: %.1f Z:: %.1f", vMin[0], vMax[1], vMax[2]); - g_pParentWnd->SetStatusText(2, strStatus); - - //Sys_UpdateWindows (W_ALL); -} - -/* -================= -Select_NudgeVerts -================= -*/ -/*! Moves the currently selected brush/patch vertices - \param delta How far to move the vertices (x,y,z) - \param bSnap If the move should snap to grid points -*/ -void Select_NudgePoint(vec3_t delta, qboolean bSnap) -{ - if (g_qeglobals.d_select_mode == sel_vertex) - { - // move selected verts - brush_t *b; - vec3_t end; - qboolean success = true; - for (b = selected_brushes.next; b != &selected_brushes; b = b->next) - { - success &= (qboolean)Brush_MoveVertex(b, g_qeglobals.d_move_points[0], delta, end, bSnap); - } - if (success) - VectorCopy(end, g_qeglobals.d_move_points[0]); - } - else if (g_qeglobals.d_select_mode == sel_curvepoint) - { - // move selected patch control points - Patch_UpdateSelected(delta); - } -} - -/* -============ -Select_Clone - -Creates an exact duplicate of the selection in place, then moves -the selected brushes off of their old positions -============ -*/ -void Select_Clone (void) -{ - g_bScreenUpdates = false; - g_pParentWnd->Copy(); - Select_Deselect(); - g_pParentWnd->Paste(); - g_pParentWnd->NudgeSelection(2, g_qeglobals.d_gridsize); - g_pParentWnd->NudgeSelection(3, g_qeglobals.d_gridsize); - Undo_Start("clone"); - Undo_EndBrushList(&selected_brushes); - Undo_End(); - g_bScreenUpdates = true; - Sys_UpdateWindows(W_ALL); -} - -//++timo clean -#if 0 -/* -============ -Select_SetTexture -Timo : bFitScale to compute scale on the plane and counteract plane / axial plane snapping -Timo : brush primitive texturing - the brushprimit_texdef given must be understood as a qtexture_t width=2 height=2 ( HiRes ) -Timo : texture plugin, added an IPluginTexdef* parameter - must be casted to an IPluginTexdef! - if not NULL, get ->Copy() of it into each face or brush ( and remember to hook ) - if NULL, means we have no information, ask for a default -TTimo - shader code cleanup - added IShader* parameter -============ -*/ -void WINAPI Select_SetTexture2 (IShader* pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, void* pPlugTexdef ) -{ - brush_t *b; - int nCount = g_ptrSelectedFaces.GetSize(); - if (nCount > 0) - { - Undo_Start("set face textures"); - ASSERT(g_ptrSelectedFaces.GetSize() == g_ptrSelectedFaceBrushes.GetSize()); - for (int i = 0; i < nCount; i++) - { - face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(i)); - brush_t *selBrush = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(i)); - Undo_AddBrush(selBrush); - //++timo TODO: propagate the IShader* .. - SetFaceTexdef (selFace, texdef, brushprimit_texdef, bFitScale, static_cast(pPlugTexdef) ); - Brush_Build(selBrush, bFitScale); - Undo_EndBrush(selBrush); - } - Undo_End(); - } - else if (selected_brushes.next != &selected_brushes) - { - Undo_Start("set brush textures"); - for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - if (!b->owner->eclass->fixedsize) - { - Undo_AddBrush(b); - Brush_SetTexture2 (b, pShader, texdef, brushprimit_texdef, bFitScale, static_cast(pPlugTexdef) ); - Undo_EndBrush(b); - } - Undo_End(); - } - Sys_UpdateWindows (W_ALL); -} -#endif - -/* -============ -Select_SetTexture -Timo : bFitScale to compute scale on the plane and counteract plane / axial plane snapping -Timo : brush primitive texturing - the brushprimit_texdef given must be understood as a qtexture_t width=2 height=2 ( HiRes ) -Timo : texture plugin, added an IPluginTexdef* parameter - must be casted to an IPluginTexdef! - if not NULL, get ->Copy() of it into each face or brush ( and remember to hook ) - if NULL, means we have no information, ask for a default -============ -*/ -void WINAPI Select_SetTexture (texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, void* pPlugTexdef ) -{ - /* -#ifdef _DEBUG - static int count = 0; -#endif - */ - brush_t *b; - /* -#ifdef _DEBUG - count++; - Sys_Printf("count: %d\n", count); - if(count==4) - Sys_Printf("break!\n"); -#endif - */ - int nCount = g_ptrSelectedFaces.GetSize(); - if (nCount > 0) - { - Undo_Start("set face textures"); - assert(g_ptrSelectedFaces.GetSize() == g_ptrSelectedFaceBrushes.GetSize()); - for (int i = 0; i < nCount; i++) - { - face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(i)); - brush_t *selBrush = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(i)); - Undo_AddBrush(selBrush); - SetFaceTexdef (selFace, texdef, brushprimit_texdef, bFitScale, static_cast(pPlugTexdef) ); - Brush_Build(selBrush, bFitScale); - Undo_EndBrush(selBrush); - } - Undo_End(); - } - else if (selected_brushes.next != &selected_brushes) - { - Undo_Start("set brush textures"); - for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - if (!b->owner->eclass->fixedsize) - { - Undo_AddBrush(b); - Brush_SetTexture (b, texdef, brushprimit_texdef, bFitScale, static_cast(pPlugTexdef) ); - Undo_EndBrush(b); - } - Undo_End(); - } - //++timo FIXME: not necessary in every cases, write a message defering / move one level up - Sys_UpdateWindows (W_ALL); -} - - -/* -================================================================ - - TRANSFORMATIONS - -================================================================ -*/ - -void Select_GetBounds (vec3_t mins, vec3_t maxs) -{ - brush_t *b; - int i; - - 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]; - } - } - } -} - -void Select_GetTrueMid (vec3_t mid) -{ - vec3_t mins, maxs; - Select_GetBounds (mins, maxs); - - for (int i=0 ; i<3 ; i++) - mid[i] = (mins[i] + ((maxs[i] - mins[i]) / 2)); -} - -void Select_GetMid (vec3_t mid) -{ - vec3_t mins, maxs; - int i; - - if (g_PrefsDlg.m_bNoClamp) - { - Select_GetTrueMid(mid); - return; - } - - Select_GetBounds (mins, maxs); - - for (i=0 ; i<3 ; i++) - mid[i] = g_qeglobals.d_gridsize*floor ( ( (mins[i] + maxs[i])*0.5 )/g_qeglobals.d_gridsize ); -} - -vec3_t select_origin; -vec3_t select_matrix[3]; -qboolean select_fliporder; - -// FIXME: bApplyBPrimit is supposed to be temporary -// TODO: manage Brush_Build calls, too many of them with the texture processing -// FIXME: the undo doesn't seem to work correctly on texturing and flip/rotate operations?? this is not supposed to be related to the texture locking code, so what is happening? -// FIXME: ApplyMatrix works on flipping operation, b0rks on Rotations (so does the "regular" rotation code??) -// FIXME: what is getting called in free rotation mode? that used to work right? -void Select_ApplyMatrix (bool bSnap, bool bRotation, int nAxis, float fDeg)//, qboolean bApplyBPrimit) -{ - brush_t *b; - face_t *f; - int i, j; - vec3_t temp, tmporigin; - - for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - { - if(b->owner->eclass->fixedsize) - { - VectorCopy (b->owner->origin, tmporigin); - // transform the origin point - VectorSubtract (b->owner->origin, select_origin, temp); - for (j=0 ; j<3 ; j++) - b->owner->origin[j] = DotProduct(temp, select_matrix[j]) + select_origin[j]; - - // update the origin key - char text[64]; - sprintf (text, "%i %i %i", - (int)b->owner->origin[0], (int)b->owner->origin[1], (int)b->owner->origin[2]); - SetKeyValue(b->owner, "origin", text); - - /*\todo remove brush-based bounding box for fixedsize entities */ - VectorSubtract (b->owner->origin, tmporigin, temp); - for (f=b->brush_faces ; f ; f=f->next) - { - // move fixedsize bbox to new origin - for (i=0 ; i<3 ; i++) - VectorAdd (f->planepts[i], temp, f->planepts[i]); - } - Brush_Build(b, bSnap,true,false,false); // don't filter - - } - else if (b->patchBrush) - { - if (!bRotation && !((g_qeglobals.d_select_mode == sel_curvepoint && g_qeglobals.d_num_move_points != 0) || g_bPatchBendMode)) - // invert patch if this is a mirroring operation, unless points are selected or bendmode is active - patchInvert(b->pPatch); - // NOTE: does not clamp points to integers - Patch_ApplyMatrix(b->pPatch, select_origin, select_matrix, false); - } - else - { - for (f=b->brush_faces ; f ; f=f->next) - { - // FIXME: only in BP mode! - // if we are using Brush Primitives texturing, we need to compute the texture matrix after the geometric transformation - // (with the default texturing you don't need to compute anything for flipping and mirroring operations) - // if (bApplyBPrimit) { - // ApplyMatrix_BrushPrimit (f, select_matrix, select_origin, select_fliporder); - // } - for (i=0 ; i<3 ; i++) - { - VectorSubtract (f->planepts[i], select_origin, temp); - for (j=0 ; j<3 ; j++) - f->planepts[i][j] = DotProduct(temp, select_matrix[j]) + select_origin[j]; - } - if (select_fliporder) - { - VectorCopy (f->planepts[0], temp); - VectorCopy (f->planepts[2], f->planepts[0]); - VectorCopy (temp, f->planepts[2]); - } - } - Brush_Build(b, bSnap,true,false,false); // don't filter - } - } -} - -void ProjectOnPlane(vec3_t& normal,float dist,vec3_t& ez, vec3_t& p) -{ - if (fabs(ez[0]) == 1) - p[0] = (dist - normal[1] * p[1] - normal[2] * p[2]) / normal[0]; - else if (fabs(ez[1]) == 1) - p[1] = (dist - normal[0] * p[0] - normal[2] * p[2]) / normal[1]; - else - p[2] = (dist - normal[0] * p[0] - normal[1] * p[1]) / normal[2]; -} - -void Back(vec3_t& dir, vec3_t& p) -{ - if (fabs(dir[0]) == 1) - p[0] = 0; - else if (fabs(dir[1]) == 1) - p[1] = 0; - else p[2] = 0; -} - - - -// using scale[0] and scale[1] -void ComputeScale(vec3_t& rex, vec3_t& rey, vec3_t& p, face_t* f) -{ - float px = DotProduct(rex, p); - float py = DotProduct(rey, p); - px *= f->texdef.scale[0]; - py *= f->texdef.scale[1]; - vec3_t aux; - VectorCopy(rex, aux); - VectorScale(aux, px, aux); - VectorCopy(aux, p); - VectorCopy(rey, aux); - VectorScale(aux, py, aux); - VectorAdd(p, aux, p); -} - -void ComputeAbsolute(face_t* f, vec3_t& p1, vec3_t& p2, vec3_t& p3) -{ - vec3_t ex,ey,ez; // local axis base - -#ifdef _DEBUG - if (g_qeglobals.m_bBrushPrimitMode) - Sys_Printf("Warning : illegal call of ComputeAbsolute in brush primitive mode\n"); -#endif - - // compute first local axis base - TextureAxisFromPlane(&f->plane, ex, ey); - CrossProduct(ex, ey, ez); - - vec3_t aux; - VectorCopy(ex, aux); - VectorScale(aux, -f->texdef.shift[0], aux); - VectorCopy(aux, p1); - VectorCopy(ey, aux); - VectorScale(aux, -f->texdef.shift[1], aux); - VectorAdd(p1, aux, p1); - VectorCopy(p1, p2); - VectorAdd(p2, ex, p2); - VectorCopy(p1, p3); - VectorAdd(p3, ey, p3); - VectorCopy(ez, aux); - VectorScale(aux, -f->texdef.rotate, aux); - VectorRotate(p1, aux, p1); - VectorRotate(p2, aux, p2); - VectorRotate(p3, aux, p3); - // computing rotated local axis base - vec3_t rex,rey; - VectorCopy(ex, rex); - VectorRotate(rex, aux, rex); - VectorCopy(ey, rey); - VectorRotate(rey, aux, rey); - - ComputeScale(rex,rey,p1,f); - ComputeScale(rex,rey,p2,f); - ComputeScale(rex,rey,p3,f); - - // project on normal plane - // along ez - // assumes plane normal is normalized - ProjectOnPlane(f->plane.normal,f->plane.dist,ez,p1); - ProjectOnPlane(f->plane.normal,f->plane.dist,ez,p2); - ProjectOnPlane(f->plane.normal,f->plane.dist,ez,p3); -}; - - -void AbsoluteToLocal(plane_t normal2, face_t* f, vec3_t& p1, vec3_t& p2, vec3_t& p3) -{ - vec3_t ex,ey,ez; - -#ifdef _DEBUG - if (g_qeglobals.m_bBrushPrimitMode) - Sys_Printf("Warning : illegal call of AbsoluteToLocal in brush primitive mode\n"); -#endif - - // computing new local axis base - TextureAxisFromPlane(&normal2, ex, ey); - CrossProduct(ex, ey, ez); - - // projecting back on (ex,ey) - Back(ez,p1); - Back(ez,p2); - Back(ez,p3); - - vec3_t aux; - // rotation - VectorCopy(p2, aux); - VectorSubtract(aux, p1,aux); - - float x = DotProduct(aux,ex); - float y = DotProduct(aux,ey); - f->texdef.rotate = 180 * atan2(y,x) / Q_PI; - - vec3_t rex,rey; - // computing rotated local axis base - VectorCopy(ez, aux); - VectorScale(aux, f->texdef.rotate, aux); - VectorCopy(ex, rex); - VectorRotate(rex, aux, rex); - VectorCopy(ey, rey); - VectorRotate(rey, aux, rey); - - // scale - VectorCopy(p2, aux); - VectorSubtract(aux, p1, aux); - f->texdef.scale[0] = DotProduct(aux, rex); - VectorCopy(p3, aux); - VectorSubtract(aux, p1, aux); - f->texdef.scale[1] = DotProduct(aux, rey); - - // shift - // only using p1 - x = DotProduct(rex,p1); - y = DotProduct(rey,p1); - x /= f->texdef.scale[0]; - y /= f->texdef.scale[1]; - - VectorCopy(rex, p1); - VectorScale(p1, x, p1); - VectorCopy(rey, aux); - VectorScale(aux, y, aux); - VectorAdd(p1, aux, p1); - VectorCopy(ez, aux); - VectorScale(aux, -f->texdef.rotate, aux); - VectorRotate(p1, aux, p1); - f->texdef.shift[0] = -DotProduct(p1, ex); - f->texdef.shift[1] = -DotProduct(p1, ey); - - // stored rot is good considering local axis base - // change it if necessary - f->texdef.rotate = -f->texdef.rotate; - - Clamp(f->texdef.shift[0], f->d_texture->width); - Clamp(f->texdef.shift[1], f->d_texture->height); - Clamp(f->texdef.rotate, 360); - -} - -void RotateFaceTexture(face_t* f, int nAxis, float fDeg) -{ - vec3_t p1,p2,p3, rota; - p1[0] = p1[1] = p1[2] = 0; - VectorCopy(p1, p2); - VectorCopy(p1, p3); - VectorCopy(p1, rota); - ComputeAbsolute(f, p1, p2, p3); - - rota[nAxis] = fDeg; - VectorRotateOrigin (p1, rota, select_origin, p1); - VectorRotateOrigin (p2, rota, select_origin, p2); - VectorRotateOrigin (p3, rota, select_origin, p3); - - plane_t normal2; - vec3_t vNormal; - vNormal[0] = f->plane.normal[0]; - vNormal[1] = f->plane.normal[1]; - vNormal[2] = f->plane.normal[2]; - VectorRotate(vNormal, rota, vNormal); - normal2.normal[0] = vNormal[0]; - normal2.normal[1] = vNormal[1]; - normal2.normal[2] = vNormal[2]; - AbsoluteToLocal(normal2, f, p1, p2 ,p3); - -} - -void RotateTextures(int nAxis, float fDeg, vec3_t vOrigin) -{ - for (brush_t* b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - { - for (face_t* f=b->brush_faces ; f ; f=f->next) - { - if (g_qeglobals.m_bBrushPrimitMode) - RotateFaceTexture_BrushPrimit (f, nAxis, fDeg, vOrigin); - else - RotateFaceTexture (f, nAxis, fDeg); - } - Brush_Build(b, false,true,false,false); // don't filter - } -} - -void Select_ApplyMatrix_BrushPrimit() -{ - #ifdef _DEBUG - if (!g_qeglobals.m_bBrushPrimitMode) { - Sys_FPrintf(SYS_ERR,"ERROR: Select_ApplyMatrix_BrushPrimit called in non-BP mode\n"); - } - #endif - for (brush_t* b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - { - for (face_t* f=b->brush_faces ; f ; f=f->next) - { - ApplyMatrix_BrushPrimit (f, select_matrix, select_origin); - } - } -} - -void Select_FlipAxis (int axis) -{ - int i; - - Select_GetMid (select_origin); - for (i=0 ; i<3 ; i++) - { - VectorCopy (vec3_origin, select_matrix[i]); - select_matrix[i][i] = 1; - } - select_matrix[axis][axis] = -1; - select_fliporder = true; - - // texture locking - if (g_PrefsDlg.m_bRotateLock) { - // axis flipping inverts space orientation, we have to use a general texture locking algorithm instead of the RotateFaceTexture - if (g_qeglobals.m_bBrushPrimitMode) { - Select_ApplyMatrix_BrushPrimit(); - } - else - { - // there's never been flip locking for non BP mode, this would be tricky to write and there's not much interest for it with the coming of BP format - // what could be done is converting regular to BP, locking, then back to regular :) - Sys_FPrintf(SYS_WRN, "WARNING: regular texturing doesn't have texture lock on flipping operations\n"); - } - } - // geometric transformation - Select_ApplyMatrix (true, false, 0, 0); - Sys_UpdateWindows (W_ALL); -} - - -void Select_Scale(float x, float y, float z) -{ - Select_GetMid (select_origin); - for (brush_t* b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - { - // ignore fixedsize entities - if(b->owner->eclass->fixedsize) continue; - for (face_t* f=b->brush_faces ; f ; f=f->next) - { - for (int i=0 ; i<3 ; i++) - { - f->planepts[i][0] -= select_origin[0]; - f->planepts[i][1] -= select_origin[1]; - f->planepts[i][2] -= select_origin[2]; - f->planepts[i][0] *= x; - f->planepts[i][1] *= y; - f->planepts[i][2] *= z; - - f->planepts[i][0] += select_origin[0]; - f->planepts[i][1] += select_origin[1]; - f->planepts[i][2] += select_origin[2]; - } - } - Brush_Build(b, false,true,false,false); // don't filter - if (b->patchBrush) - { - vec3_t v; - v[0] = x; - v[1] = y; - v[2] = z; - Patch_Scale(b->pPatch, select_origin, v); - } - } -} - -void Select_RotateAxis (int axis, float deg, bool bPaint, bool bMouse) -{ - int i; - vec_t c, s; - - if (deg == 0) - { - return; - } - - if (bMouse) - { - VectorCopy(g_pParentWnd->ActiveXY()->RotateOrigin(), select_origin); - } - else - { - Select_GetMid (select_origin); - } - - /* - if(axis == 2) - { - vec3_t rotation; - VectorSet(rotation, 0, 0, 360 - deg); - for(brush_t *b = selected_brushes.next; b != &selected_brushes; b = b->next) - if(b->owner->model.pEdit) - b->owner->model.pEdit->Rotate(select_origin, rotation); - } - */ - - select_fliporder = false; - - // the "90" degrees algorithm is mostly used on axis rotate as a speedup and possibly avoiding rounding errors as much as possible - // previous implementation was doing an indirect-oriented rotation over the plane whereas the general algo below was doing a direct-oriented rotation - // this was confusing the texture locking algorithms, fixed it to be direct-oriented (side consequence is that the axis rotate toolbar button rotates the other way now) - // NOTE: previous algo was using vec3_origin in the matrix computation.. - // I don't see what an origin does in linear transformations (3x3 matrixes always relate to a (0,0,0) origin) - // in Radiant it's initialized as (0,0,0) and never set to another value - // so I got rid of it when it's not used for initialisation tasks (and even if it's not (0,0,0) it should not matter - if (deg == 90) - { - c = 0; - s = 1; - } - else - { - c = cos(deg * Q_PI / 180.0); - s = sin(deg * Q_PI / 180.0); - } - - for (i=0 ; i<3 ; i++) - { - VectorCopy (vec3_origin, select_matrix[i]); - select_matrix[i][i] = 1; - } - - switch (axis) - { - case 0: - select_matrix[1][1] = c; - select_matrix[1][2] = s; - select_matrix[2][1] = -s; - select_matrix[2][2] = c; - break; - case 1: - select_matrix[0][0] = c; - select_matrix[0][2] = s; - select_matrix[2][0] = -s; - select_matrix[2][2] = c; - break; - case 2: - select_matrix[0][0] = c; - select_matrix[0][1] = s; - select_matrix[1][0] = -s; - select_matrix[1][1] = c; - break; - } - - - // texture locking - if (g_PrefsDlg.m_bRotateLock) - { - // Terrible hack, reversing input rotation angle to correct - // texture rotation direction for X and Z axes. - // RotateTextures needs to be changed to fix this properly? - if (axis == 1) - RotateTextures(axis, deg, select_origin); - else - RotateTextures(axis, deg * -1, select_origin); - } - // geometric transformation - Select_ApplyMatrix(!bMouse, true, axis, deg);//, false); - - if (bPaint) - Sys_UpdateWindows (W_ALL); -} - -/* -================================================================ - -GROUP SELECTIONS - -================================================================ -*/ - -void Select_RealCompleteTall(vec3_t mins, vec3_t maxs) -{ - brush_t *b, *next; - - int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0; - int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2; - - g_qeglobals.d_select_mode = sel_brush; - - for (b=active_brushes.next ; b != &active_brushes ; b=next) - { - next = b->next; - - if (b->bFiltered) - continue; - - if ( (b->maxs[nDim1] > maxs[nDim1] || b->mins[nDim1] < mins[nDim1]) - || (b->maxs[nDim2] > maxs[nDim2] || b->mins[nDim2] < mins[nDim2]) ) - continue; - - Brush_RemoveFromList (b); - Brush_AddToList (b, &selected_brushes); - } -} - -void Select_CompleteTall (void) -{ - vec3_t mins, maxs; - - if (!QE_SingleBrush ()) - return; - - Undo_Start ("select complete tall"); - Undo_AddBrushList (&selected_brushes); - Undo_End(); - - VectorCopy (selected_brushes.next->mins, mins); - VectorCopy (selected_brushes.next->maxs, maxs); - Select_Delete (); - - Select_RealCompleteTall(mins, maxs); - Sys_UpdateWindows (W_ALL); -} - -void Select_PartialTall (void) -{ - brush_t *b, *next; - vec3_t mins, maxs; - - if (!QE_SingleBrush ()) - return; - - Undo_Start ("select complete tall"); - Undo_AddBrushList (&selected_brushes); - Undo_End(); - - g_qeglobals.d_select_mode = sel_brush; - - VectorCopy (selected_brushes.next->mins, mins); - VectorCopy (selected_brushes.next->maxs, maxs); - Select_Delete (); - - int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0; - int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2; - - for (b=active_brushes.next ; b != &active_brushes ; b=next) - { - next = b->next; - - if (b->bFiltered) - continue; - - if ( (b->mins[nDim1] > maxs[nDim1] || b->maxs[nDim1] < mins[nDim1]) - || (b->mins[nDim2] > maxs[nDim2] || b->maxs[nDim2] < mins[nDim2]) ) - continue; - - - Brush_RemoveFromList (b); - Brush_AddToList (b, &selected_brushes); - } - - Sys_UpdateWindows (W_ALL); -} - -void Select_Touching (void) -{ - brush_t *b, *next; - int i; - vec3_t mins, maxs; - - if (!QE_SingleBrush ()) - return; - - g_qeglobals.d_select_mode = sel_brush; - - VectorCopy (selected_brushes.next->mins, mins); - VectorCopy (selected_brushes.next->maxs, maxs); - - for (b=active_brushes.next ; b != &active_brushes ; b=next) - { - next = b->next; - - if (b->bFiltered) - continue; - - for (i=0 ; i<3 ; i++) - if (b->mins[i] > maxs[i]+1 || b->maxs[i] < mins[i]-1) - break; - - if (i == 3) - { - Brush_RemoveFromList (b); - Brush_AddToList (b, &selected_brushes); - } - } - - Sys_UpdateWindows (W_ALL); -} - -void Select_Inside (void) -{ - brush_t *b, *next; - int i; - vec3_t mins, maxs; - - if (!QE_SingleBrush ()) - return; - - Undo_Start ("select inside"); - Undo_AddBrushList (&selected_brushes); - Undo_End(); - - g_qeglobals.d_select_mode = sel_brush; - - VectorCopy (selected_brushes.next->mins, mins); - VectorCopy (selected_brushes.next->maxs, maxs); - Select_Delete (); - - for (b=active_brushes.next ; b != &active_brushes ; b=next) - { - next = b->next; - - if (b->bFiltered) - continue; - - for (i=0 ; i<3 ; i++) - if (b->maxs[i] > maxs[i] || b->mins[i] < mins[i]) - break; - if (i == 3) - { - Brush_RemoveFromList (b); - Brush_AddToList (b, &selected_brushes); - } - } - - Sys_UpdateWindows (W_ALL); -} - -void Select_Ungroup(void) -{ - int numselectedgroups; - entity_t *e; - brush_t *b,* sb; - - numselectedgroups = 0; - for (sb = selected_brushes.next; sb != &selected_brushes; sb = sb->next) - { - e = sb->owner; - - if (e == world_entity || e->eclass->fixedsize) - { - continue; - } - - for (b = e->brushes.onext; b != &e->brushes; b = e->brushes.onext) - { - Entity_UnlinkBrush (b); - Entity_LinkBrush (world_entity, b); - } - Entity_Free (e); - numselectedgroups++; - } - - if (numselectedgroups <= 0) - { - Sys_Printf("No grouped entities selected.\n"); - return; - } - Sys_Printf("Ungrouped %d entit%s.\n", numselectedgroups, (numselectedgroups == 1)?"y":"ies"); - Sys_UpdateWindows (W_ALL); -} - -/*! -group selected brushes into specified entity -if an entity is empty afterwards, destroy it -*/ -void Select_GroupEntity(entity_t* group) -{ - entity_t* e; - brush_t *b; - - if(group->eclass->fixedsize) - { - Sys_FPrintf (SYS_ERR, "Select_GroupEntity: can't group anything to a fixedsize entity\n"); - return; - } - - for (b = selected_brushes.next; b != &selected_brushes; b = b->next) - { - if(b->owner->eclass->fixedsize) continue; - e = b->owner; - Entity_UnlinkBrush(b); - Entity_LinkBrush(group, b); - if(e != world_entity && e->brushes.onext == &e->brushes) - { - Undo_AddEntity(e); - Entity_Free(e); - } - } -} - -/*! -merge all selected entities together into the first one selected -NOTE: makes use of order of selected_brushes list -can be used to move world brushes in an entity, or to merge several ents together -NOTE: didn't devise a strategy on the epairs, we merge into the first entity and use those -*/ -void Select_MergeEntity() -{ - entity_t* e = NULL; - brush_t* b; - for (b = selected_brushes.next; b != &selected_brushes; b = b->next) - { - if(!b->owner->eclass->fixedsize) - { - e = b->owner; - break; - } - } - - if(e != NULL) - { - Select_GroupEntity(e); - - int count = 0; - for(b = e->brushes.onext; b != &e->brushes; b=b->onext) - { - //Brush_RemoveFromList (b); - //Brush_AddToList(b, &active_brushes); - count++; - } - Sys_Printf ("Merged %d brushes into %s entity\n", count, ValueForKey (e, "classname")); - } -} - -/* -==================== -Select_Seperate -==================== -*/ -void Select_Seperate( void ) { - Select_GroupEntity( world_entity ); -} - -/* -==================== -Select_MakeStructural -==================== -*/ -void Select_MakeStructural (void) -{ - brush_t *b; - face_t *f; - - for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - { - for (f=b->brush_faces ; f ; f=f->next) - f->texdef.contents &= ~CONTENTS_DETAIL; - b->bFiltered = FilterBrush(b); - } - Select_Deselect (); - Sys_UpdateWindows (W_ALL); -} - -void Select_MakeDetail (void) -{ - brush_t *b; - face_t *f; - - for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - { - for (f=b->brush_faces ; f ; f=f->next) - f->texdef.contents |= CONTENTS_DETAIL; - b->bFiltered = FilterBrush(b); - } - Select_Deselect (); - Sys_UpdateWindows (W_ALL); -} - -// brush primitive texture adjustments, use the camera view to map adjustments -// ShiftTextureRelative_BrushPrimit ( s , t ) will shift relative to the texture -void ShiftTextureRelative_Camera(face_t *f, int x, int y) -{ - vec3_t vecS, vecT; - vec_t XY[2]; // the values we are going to send for translation - vec_t sgn[2]; // +1 or -1 - int axis[2]; - CamWnd* pCam; - - // get the two relative texture axes for the current texturing - BrushPrimit_GetRelativeAxes(f, vecS, vecT); - - // center point of the face, project it on the camera space - vec3_t C; - VectorClear(C); - int i; - for (i=0; iface_winding->numpoints; i++) - { - VectorAdd(C,f->face_winding->points[i],C); - } - VectorScale(C,1.0/f->face_winding->numpoints,C); - - pCam = g_pParentWnd->GetCamWnd(); - pCam->MatchViewAxes(C, vecS, axis[0], sgn[0]); - pCam->MatchViewAxes(C, vecT, axis[1], sgn[1]); - - // this happens when the two directions can't be mapped on two different directions on the screen - // then the move will occur against a single axis - // (i.e. the user is not positioned well enough to send understandable shift commands) - // NOTE: in most cases this warning is not very relevant because the user would use one of the two axes - // for which the solution is easy (the other one being unknown) - // so this warning could be removed - if (axis[0] == axis[1]) - Sys_FPrintf(SYS_WRN, "Warning: degenerate in ShiftTextureRelative_Camera\n"); - - // compute the X Y geometric increments - // those geometric increments will be applied along the texture axes (the ones we computed above) - XY[0] = 0; - XY[1] = 0; - if (x!=0) - { - // moving right/left - XY[axis[0]] += sgn[0]*x; - } - if (y!=0) - { - XY[axis[1]] += sgn[1]*y; - } - // we worked out a move along vecS vecT, and we now it's geometric amplitude - // apply it - ShiftTextureRelative_BrushPrimit(f, XY[0], XY[1]); -} - -void Select_ShiftTexture(int x, int y) -{ - brush_t *b; - face_t *f; - - int nFaceCount = g_ptrSelectedFaces.GetSize(); - - if(selected_brushes.next == &selected_brushes && nFaceCount == 0) - return; - - for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - { - for (f=b->brush_faces ; f ; f=f->next) - { - if (g_qeglobals.m_bBrushPrimitMode) - { - ShiftTextureRelative_Camera( f, x, y ); - } - else - { - f->texdef.shift[0] += x; - f->texdef.shift[1] += y; - } - } - Brush_Build(b,true,true,false,false); // don't filter - if (b->patchBrush) - { - Patch_ShiftTexture(b->pPatch, x, y); - } - } - - if (nFaceCount > 0) - { - for (int i = 0; i < nFaceCount; i++) - { - face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(i)); - brush_t *selBrush = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(i)); - if (g_qeglobals.m_bBrushPrimitMode) - { - ShiftTextureRelative_Camera( selFace, x, y ); - } - else - { - selFace->texdef.shift[0] += x; - selFace->texdef.shift[1] += y; - } - Brush_Build(selBrush,true,true,false,false); // don't filter - } - } - - Sys_UpdateWindows (W_CAMERA); -} - -// setting float as input -void Select_ScaleTexture(float x, float y) -{ - brush_t *b; - face_t *f; - - int nFaceCount = g_ptrSelectedFaces.GetSize(); - - if(selected_brushes.next == &selected_brushes && nFaceCount == 0) - { - return; - } - - for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - { - for (f=b->brush_faces ; f ; f=f->next) - { - if (g_qeglobals.m_bBrushPrimitMode) - { - // apply same scale as the spinner button of the surface inspector - float shift[2]; - float rotate; - float scale[2]; - brushprimit_texdef_t bp; - // compute normalized texture matrix - ConvertTexMatWithQTexture( &f->brushprimit_texdef, f->d_texture, &bp, NULL ); - // compute fake shift scale rot - TexMatToFakeTexCoords( bp.coords, shift, &rotate, scale ); - // update - scale[0]+=static_cast(x)*0.1; - scale[1]+=static_cast(y)*0.1; - // compute new normalized texture matrix - FakeTexCoordsToTexMat( shift, rotate, scale, bp.coords ); - // apply to face texture matrix - ConvertTexMatWithQTexture( &bp, NULL, &f->brushprimit_texdef, f->d_texture ); - } - else - { - f->texdef.scale[0] += x; - f->texdef.scale[1] += y; - } - } - Brush_Build(b,true,true,false,false); // don't filter - if (b->patchBrush) - { - Patch_ScaleTexture(b->pPatch, x, y); - } - } - - if (nFaceCount > 0) - { - for (int i = 0; i < nFaceCount; i++) - { - face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(i)); - brush_t *selBrush = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(i)); - if (g_qeglobals.m_bBrushPrimitMode) - { - float shift[2]; - float rotate; - float scale[2]; - brushprimit_texdef_t bp; - ConvertTexMatWithQTexture( &selFace->brushprimit_texdef, selFace->d_texture, &bp, NULL ); - TexMatToFakeTexCoords( bp.coords, shift, &rotate, scale ); - scale[0]+=static_cast(x)*0.1; - scale[1]+=static_cast(y)*0.1; - FakeTexCoordsToTexMat( shift, rotate, scale, bp.coords ); - ConvertTexMatWithQTexture( &bp, NULL, &selFace->brushprimit_texdef, selFace->d_texture ); - } - else - { - selFace->texdef.scale[0] += x; - selFace->texdef.scale[1] += y; - } - Brush_Build(selBrush,true,true,false,false); // don't filter - } - } - - Sys_UpdateWindows (W_CAMERA); -} - -void Select_RotateTexture(int amt) -{ - brush_t *b; - face_t *f; - - int nFaceCount = g_ptrSelectedFaces.GetSize(); - - if(selected_brushes.next == &selected_brushes && nFaceCount == 0) - { - return; - } - - for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - { - for (f=b->brush_faces ; f ; f=f->next) - { - if (g_qeglobals.m_bBrushPrimitMode) - { - // apply same scale as the spinner button of the surface inspector - float shift[2]; - float rotate; - float scale[2]; - brushprimit_texdef_t bp; - // compute normalized texture matrix - ConvertTexMatWithQTexture( &f->brushprimit_texdef, f->d_texture, &bp, NULL ); - // compute fake shift scale rot - TexMatToFakeTexCoords( bp.coords, shift, &rotate, scale ); - // update - rotate += amt; - // compute new normalized texture matrix - FakeTexCoordsToTexMat( shift, rotate, scale, bp.coords ); - // apply to face texture matrix - ConvertTexMatWithQTexture( &bp, NULL, &f->brushprimit_texdef, f->d_texture ); - } - else - { - f->texdef.rotate += amt; - f->texdef.rotate = static_cast(f->texdef.rotate) % 360; - } - } - Brush_Build(b,true,true,false,false); // don't filter - if (b->patchBrush) - { - //Patch_RotateTexture(b->nPatchID, amt); - Patch_RotateTexture(b->pPatch, amt); - } - } - - if (nFaceCount > 0) - { - for (int i = 0; i < nFaceCount; i++) - { - face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(i)); - brush_t *selBrush = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(i)); - if (g_qeglobals.m_bBrushPrimitMode) - { - float shift[2]; - float rotate; - float scale[2]; - brushprimit_texdef_t bp; - ConvertTexMatWithQTexture( &selFace->brushprimit_texdef, selFace->d_texture, &bp, NULL ); - TexMatToFakeTexCoords( bp.coords, shift, &rotate, scale ); - rotate += amt; - FakeTexCoordsToTexMat( shift, rotate, scale, bp.coords ); - ConvertTexMatWithQTexture( &bp, NULL, &selFace->brushprimit_texdef, selFace->d_texture ); - } - else - { - selFace->texdef.rotate += amt; - selFace->texdef.rotate = static_cast(selFace->texdef.rotate) % 360; - } - Brush_Build(selBrush,true,true,false,false); // don't filter - } - } - - Sys_UpdateWindows (W_CAMERA); -} - -// TTimo modified to handle shader architecture: -// expects shader names at input, comparison relies on shader names .. texture names no longer relevant -void FindReplaceTextures(const char* pFind, const char* pReplace, bool bSelected, bool bForce, bool bSelectMatchingFaces) -{ - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=391 - if (strchr(pFind, ' ') || strchr(pReplace, ' ')) - { - Sys_FPrintf(SYS_WRN, "FindReplaceTextures: '%s' or '%s' have spaces, aborted\n", pFind, pReplace); - return; - } - - brush_t* pList = (bSelected) ? &selected_brushes : &active_brushes; - if (!bSelected) - Select_Deselect(); - - //++timo BP mode: replacing a texture in BP mode is not that easy, you need to recompute the texture matrix - // if the size of the replacing texture differs, otherwise you get wrong scaling - if (g_qeglobals.m_bBrushPrimitMode) - Sys_Printf("TODO: finalize find/replace code for brush primitives"); - - CPtrArray mFaces; - for (brush_t* pBrush = pList->next ; pBrush != pList; pBrush = pBrush->next) - { - if (!bSelectMatchingFaces && pBrush->patchBrush) - { - Patch_FindReplaceTexture(pBrush, pFind, pReplace, bForce); - } - - bool found = false; //spog - for (face_t* pFace = pBrush->brush_faces; pFace; pFace = pFace->next) - { - if(bForce || strcmpi(pFace->pShader->getName(), pFind) == 0) - { - if (!bSelectMatchingFaces) { - pFace->pShader->DecRef(); - pFace->pShader = QERApp_Shader_ForName( pReplace ); - pFace->pShader->IncRef(); - pFace->d_texture = pFace->pShader->getTexture(); - pFace->texdef.SetName(pReplace); - found = true; - } else if (bSelectMatchingFaces) { - mFaces.Add(pFace); - } - } - } - - if (found) // spog - speed increase, only build brushes that changed - Brush_Build(pBrush); - - } - - if (bSelectMatchingFaces) { - if (bSelected) - Select_Deselect(); - - int nSize = mFaces.GetSize(); - for (int i = 0; i < nSize; i++) { - g_SelectedFaces.Add(reinterpret_cast(mFaces.GetAt(i))); - } - } - - Sys_UpdateWindows (W_CAMERA); -} - -void Select_AllOfType() -{ - brush_t *b, *next; - entity_t *e; - // if no brush selected, we will select based on texture - // the first selected face's texture if any, or the current texture - // if a brush is selected, we will select entities (first non-worldspawn owner in selected brushes) - if (selected_brushes.next == &selected_brushes) - { - - CString strName; - if (g_ptrSelectedFaces.GetSize() == 0) - { - strName = g_qeglobals.d_texturewin.texdef.GetName(); - } - else - { - face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(0)); - strName = selFace->texdef.GetName(); - } - - Sys_Printf("Selecting all brushes with the texture %s\n", strName.GetBuffer()); - - Select_Deselect(); - for (b=active_brushes.next ; b != &active_brushes ; b=next) - { - next = b->next; - - if (b->bFiltered) - continue; - - if (b->patchBrush) - { - if (strcmpi(strName, b->pPatch->pShader->getName()) == 0) - { - Brush_RemoveFromList (b); - Brush_AddToList (b, &selected_brushes); - } - } - else - { - for (face_t* pFace = b->brush_faces; pFace; pFace = pFace->next) - { - if (strcmpi(strName, pFace->texdef.GetName()) == 0) - { - Brush_RemoveFromList (b); - Brush_AddToList (b, &selected_brushes); - } - } - } - } - Sys_UpdateWindows(W_ALL); - return; - } - - - b = selected_brushes.next; - e = b->owner; - - if (e != NULL) - { - if (e != world_entity) - { - CString strName = e->eclass->name; - CString strKey, strVal; - bool bCriteria = GetSelectAllCriteria(strKey, strVal); - Sys_Printf("Selecting all %s entities\n", strName.GetBuffer()); - Select_Deselect(); - - for (b=active_brushes.next ; b != &active_brushes ; b=next) - { - next = b->next; - - if (b->bFiltered) - continue; - - e = b->owner; - if (e != NULL) - { - if (strcmpi(e->eclass->name, strName) == 0) - { - bool doIt = true; - if (bCriteria) { - CString str = ValueForKey (e, strKey); - if (str.CompareNoCase(strVal) != 0) { - doIt = false; - } - } - if (doIt) { - Brush_RemoveFromList (b); - Brush_AddToList (b, &selected_brushes); - } - } - } - } - } - } - Sys_UpdateWindows (W_ALL); - -} - -void Select_Reselect() -{ - Select_Brush(selected_brushes.next); - Sys_UpdateWindows (W_ALL); -} - - -void Select_FitTexture(int nHeight, int nWidth) -{ - brush_t *b; - - int nFaceCount = g_ptrSelectedFaces.GetSize(); - - if(selected_brushes.next == &selected_brushes && nFaceCount == 0) - return; - - for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - { - Brush_FitTexture(b, nHeight, nWidth); - Brush_Build(b,true,true,false,false); // don't filter - } - - if (nFaceCount > 0) - { - for (int i = 0; i < nFaceCount; i++) - { - face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(i)); - brush_t *selBrush = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(i)); - Face_FitTexture(selFace, nHeight, nWidth); - Brush_Build(selBrush,true,true,false,false); // don't filter - } - } - - Sys_UpdateWindows (W_CAMERA); -} - -void Select_Hide() -{ - for (brush_t* b=selected_brushes.next ; b && b != &selected_brushes ; b=b->next) - { - b->hiddenBrush = true; - b->bFiltered = true; - } - Sys_UpdateWindows (W_ALL); -} - -void Select_ShowAllHidden() -{ - brush_t* b; - for (b=selected_brushes.next ; b && b != &selected_brushes ; b=b->next) - { - if (b->hiddenBrush) - { - b->hiddenBrush = false; - b->bFiltered = FilterBrush(b); - } - } - for (b=active_brushes.next ; b && b != &active_brushes ; b=b->next) - { - if (b->hiddenBrush) - { - b->hiddenBrush = false; - b->bFiltered = FilterBrush(b); - } - } - Sys_UpdateWindows (W_ALL); -} - - -/* -============ -Select_Invert -============ -*/ -void Select_Invert(void) -{ - brush_t *next, *prev, *b; - - Sys_Printf("inverting selection...\n"); - - next = active_brushes.next; - prev = active_brushes.prev; - if (selected_brushes.next != &selected_brushes) - { - active_brushes.next = selected_brushes.next; - active_brushes.prev = selected_brushes.prev; - active_brushes.next->prev = &active_brushes; - active_brushes.prev->next = &active_brushes; - } - else - { - active_brushes.next = &active_brushes; - active_brushes.prev = &active_brushes; - } - if (next != &active_brushes) - { - selected_brushes.next = next; - selected_brushes.prev = prev; - selected_brushes.next->prev = &selected_brushes; - selected_brushes.prev->next = &selected_brushes; - } - else - { - selected_brushes.next = &selected_brushes; - selected_brushes.prev = &selected_brushes; - } - - // now check if any hidden brush is selected - for (b = selected_brushes.next; b != &selected_brushes; ) - { - if (b->patchBrush) - b->pPatch->bSelected = true; - - if (b->bFiltered) - { - brush_t *pb = b; - b = b->next; - Brush_RemoveFromList (pb); - Brush_AddToList (pb, &active_brushes); - } - else b = b->next; - - } - - for (b = active_brushes.next; b != &active_brushes; b = b->next) - { - if (b->patchBrush) - { - b->pPatch->bSelected = false; - } - } - - // since invert selection only works at the brush level, - // set g_qeglobals.d_select_mode accordingly - g_qeglobals.d_select_mode = sel_brush; - - // since invert selection only works at the brush level, - // set g_qeglobals.d_select_mode accordingly - g_qeglobals.d_select_mode = sel_brush; - - Sys_UpdateWindows(W_ALL); - - Sys_Printf("done.\n"); -} - -#ifdef ENABLE_GROUPS -/* -=========== -Select_Name -=========== -*/ -void Select_Name(const char *pName) -{ - if (g_qeglobals.m_bBrushPrimitMode) - { - for (brush_t* b=selected_brushes.next ; b && b != &selected_brushes ; b=b->next) - { - Brush_SetEpair(b, "Name", pName); - } - } -} - -/* -================= -Select_AddToGroup -add selected brushes to a group, update the tree -================= -*/ -void Select_AddToGroup(const char *pName) -{ - if (g_qeglobals.m_bBrushPrimitMode) - { - for (brush_t* b=selected_brushes.next ; b && b != &selected_brushes ; b=b->next) - { - Brush_SetEpair(b, "group", pName); - Group_AddToProperGroup(b); - } - } -} -#endif +/* +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 +*/ + +// select.c +#include "stdafx.h" +#include +#include "filters.h" + +// externs +CPtrArray g_SelectedFaces; +CPtrArray g_SelectedFaceBrushes; +CPtrArray& g_ptrSelectedFaces = g_SelectedFaces; +CPtrArray& g_ptrSelectedFaceBrushes = g_SelectedFaceBrushes; + +/* +=========== +Test_Ray +=========== +*/ +#define DIST_START 999999 +trace_t Test_Ray (vec3_t origin, vec3_t dir, int flags) +{ + brush_t *brush; + face_t *face; + float dist; + trace_t t; + + memset (&t, 0, sizeof(t)); + t.dist = DIST_START; + + if (flags & SF_CYCLE) + { + CPtrArray array; + brush_t *pToSelect = (selected_brushes.next != &selected_brushes) ? selected_brushes.next : NULL; + Select_Deselect(); + + // go through active brushes and accumulate all "hit" brushes + for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next) + { + //if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity) + // continue; + + if (brush->bFiltered) + continue; + + if (!g_PrefsDlg.m_bSelectCurves && brush->patchBrush) + continue; + + if (!g_PrefsDlg.m_bSelectModels && (brush->owner->eclass->nShowFlags & ECLASS_MISCMODEL)) + continue; + + //if (!g_bShowPatchBounds && brush->patchBrush) + // continue; + + face = Brush_Ray (origin, dir, brush, &dist, flags); + + if (face) + array.Add(brush); + } + + int nSize = array.GetSize(); + if (nSize > 0) + { + bool bFound = false; + for (int i = 0; i < nSize; i++) + { + brush_t *b = reinterpret_cast(array.GetAt(i)); + // did we hit the last one selected yet ? + if (b == pToSelect) + { + // yes we want to select the next one in the list + int n = (i > 0) ? i-1 : nSize-1; + pToSelect = reinterpret_cast(array.GetAt(n)); + bFound = true; + break; + } + } + if (!bFound) + pToSelect = reinterpret_cast(array.GetAt(0)); + } + if (pToSelect) + { + face = Brush_Ray (origin, dir, pToSelect, &dist, flags); + t.dist = dist; + t.brush = pToSelect; + t.face = face; + t.selected = false; + return t; + } + } + + if (! (flags & SF_SELECTED_ONLY) ) + { + for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next) + { + if ( (flags & SF_ENTITIES_FIRST) && (brush->owner == world_entity || !brush->owner->eclass->fixedsize)) + continue; + + if (brush->bFiltered) + continue; + + if (!g_PrefsDlg.m_bSelectCurves && brush->patchBrush) + continue; + + if (!g_PrefsDlg.m_bSelectModels && (brush->owner->eclass->nShowFlags & ECLASS_MISCMODEL)) + continue; + + //if (!g_bShowPatchBounds && brush->patchBrush) + // continue; + + face = Brush_Ray (origin, dir, brush, &dist, flags); + if (face && dist > 0 && dist < t.dist) + { + t.dist = dist; + t.brush = brush; + t.face = face; + t.selected = false; + } + } + } + + + for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next) + { + if ( (flags & SF_ENTITIES_FIRST) && (brush->owner == world_entity || !brush->owner->eclass->fixedsize)) + continue; + + if (brush->bFiltered) + continue; + + if (!g_PrefsDlg.m_bSelectCurves && brush->patchBrush) + continue; + + if (!g_PrefsDlg.m_bSelectModels && (brush->owner->eclass->nShowFlags & ECLASS_MISCMODEL)) + continue; + + face = Brush_Ray (origin, dir, brush, &dist, flags); + if (dist > 0 && dist < t.dist) + { + t.dist = dist; + t.brush = brush; + t.face = face; + t.selected = true; + } + } + + // if entites first, but didn't find any, check regular + + if ( (flags & SF_ENTITIES_FIRST) && t.brush == NULL) + return Test_Ray (origin, dir, flags & ~SF_ENTITIES_FIRST); + + return t; + +} + + +/* +============ +Select_Brush + +============ +*/ +void Select_Brush (brush_t *brush, bool bComplete, bool bStatus) +{ + brush_t *b; + entity_t *e; + + g_ptrSelectedFaces.RemoveAll(); + g_ptrSelectedFaceBrushes.RemoveAll(); + if (g_qeglobals.d_select_count < 2) + g_qeglobals.d_select_order[g_qeglobals.d_select_count] = brush; + g_qeglobals.d_select_count++; + + e = brush->owner; + if (e) + { + // select complete entity on first click + if (e != world_entity && bComplete == true) + { + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + if (b->owner == e) + goto singleselect; + for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext) + { + if( b == brush ) // make sure we add the actual selected brush last, mainly for cycle select + continue; + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + Brush_RemoveFromList (brush); + Brush_AddToList (brush, &selected_brushes); + } + else + { + singleselect: + Brush_RemoveFromList (brush); + Brush_AddToList (brush, &selected_brushes); + UpdatePatchInspector(); + } + + if (e->eclass) + { + UpdateEntitySel(brush->owner->eclass); + } + + UpdateSurfaceDialog(); + } + + if (bStatus) + { + vec3_t vMin, vMax, vSize; + Select_GetBounds (vMin, vMax); + VectorSubtract(vMax, vMin, vSize); + CString strStatus; + strStatus.Format("Selection X:: %.1f Y:: %.1f Z:: %.1f", vSize[0], vSize[1], vSize[2]); + g_pParentWnd->SetStatusText(2, strStatus); + } +} + +/* +============= +Select_FaceInSelectedBrushes +============= +*/ +bool Select_FaceInSelectedBrushes( face_t *face ) +{ + brush_t *brush; + face_t *tface; + + for(brush = selected_brushes.next; brush != &selected_brushes; brush = brush->next) + { + for(tface = brush->brush_faces; tface; tface = tface->next) + { + if(tface == face) + { + return true; + } + } + } + + return false; +} + +/* +============ +Select_Ray + +If the origin is inside a brush, that brush will be ignored. +============ +*/ +void Select_Ray (vec3_t origin, vec3_t dir, int flags) +{ + trace_t t; + face_t *tface; + bool bOk; + static trace_t lastTrace = { + NULL, // brush + NULL, // face + 0, // dist + false // selected + }; + + t = Test_Ray (origin, dir, flags); + if (!t.brush) + return; + + if (flags & SF_SINGLEFACE) + { + if( flags & SF_DRAG ) + { + if ( t.brush == lastTrace.brush && t.face == lastTrace.face ) + return; + } + lastTrace = t; + + if(Select_FaceInSelectedBrushes(t.face)) + { + // Deselect the brush + Brush_RemoveFromList (t.brush); + Brush_AddToList (t.brush, &active_brushes); + UpdatePatchInspector(); + + // Select all of the brush's faces except the one we are pointing at + for( tface = t.brush->brush_faces; tface; tface = tface->next ) + { + if( tface == t.face ) + continue; + + bOk = true; + // NOTE: keep the size check in the loop, we remove stuff inside + for (int i = 0; i < g_SelectedFaces.GetSize(); i++) + { + if (tface == reinterpret_cast(g_SelectedFaces.GetAt(i))) + bOk = false; + } + + if(bOk) + { + g_SelectedFaces.Add(tface); + g_SelectedFaceBrushes.Add(t.brush); + } + } + g_qeglobals.d_select_mode = sel_facets_off; + } + else + { + bOk = true; + // NOTE: keep the size check in the loop, we remove stuff inside + for (int i = 0; i < g_SelectedFaces.GetSize(); i++) + { + if (t.face == reinterpret_cast(g_SelectedFaces.GetAt(i))) + { + bOk = false; + if( flags & SF_DRAG_ON ) + continue; + + g_qeglobals.d_select_mode = sel_facets_off; + // need to remove i'th entry + g_SelectedFaces.RemoveAt(i, 1); + g_SelectedFaceBrushes.RemoveAt(i, 1); + } + } + + if (bOk && !(flags & SF_DRAG_OFF)) + { + g_SelectedFaces.Add(t.face); + g_SelectedFaceBrushes.Add(t.brush); + g_qeglobals.d_select_mode = sel_facets_on; + } + } + UpdateSurfaceDialog(); + Sys_UpdateWindows (W_ALL); + //g_qeglobals.d_select_mode = sel_brush; + // Texture_SetTexture requires a brushprimit_texdef fitted to the default width=2 height=2 texture + brushprimit_texdef_t brushprimit_texdef; + ConvertTexMatWithQTexture ( &t.face->brushprimit_texdef, t.face->d_texture, &brushprimit_texdef, NULL ); + Texture_SetTexture ( &t.face->texdef, &brushprimit_texdef, false, NULL, false ); + return; + } + + // move the brush to the other list + if (t.selected) + { + if( flags & SF_DRAG_ON ) + return; + + g_qeglobals.d_select_mode = sel_brush_off; + Brush_RemoveFromList (t.brush); + Brush_AddToList (t.brush, &active_brushes); + + UpdatePatchInspector(); + } + else + { + if( flags & SF_DRAG_OFF ) + return; + + g_qeglobals.d_select_mode = sel_brush_on; + Select_Brush (t.brush, g_PrefsDlg.m_nCamDragMultiSelect == 1 ? Sys_AltDown () : !Sys_AltDown ()); + } + UpdateSurfaceDialog(); + Sys_UpdateWindows (W_ALL); +} + + +void Select_Delete (void) +{ + brush_t *brush; + entity_t *e; + + g_ptrSelectedFaces.RemoveAll(); + g_ptrSelectedFaceBrushes.RemoveAll(); + + g_qeglobals.d_select_mode = sel_brush; + + g_qeglobals.d_select_count = 0; + g_qeglobals.d_num_move_points = 0; + while (selected_brushes.next != &selected_brushes) + { + brush = selected_brushes.next; + if (brush->patchBrush) + { + Patch_Delete(brush->pPatch); + } + e = brush->owner; + Brush_Free (brush); + // remove if no brushes + if (e != world_entity && e->brushes.onext == &e->brushes) + Entity_Free(e); + } + + Sys_MarkMapModified (); + UpdateSurfaceDialog(); + Sys_UpdateWindows (W_ALL); +} + +// update the workzone to a given brush +void UpdateWorkzone_ForBrush( brush_t* b ) +{ + VectorCopy( b->mins, g_qeglobals.d_work_min ); + VectorCopy( b->maxs, g_qeglobals.d_work_max ); + //++timo clean +#if 0 + // will update the workzone to the given brush + // g_pParentWnd->ActiveXY()->GetViewType() + // cf VIEWTYPE defintion: enum VIEWTYPE {YZ, XZ, XY}; + // we fit our work zone to the last brush on the list (b) + int nViewType = g_pParentWnd->ActiveXY()->GetViewType(); + int nDim1 = (nViewType == YZ) ? 1 : 0; + int nDim2 = (nViewType == XY) ? 1 : 2; + g_qeglobals.d_work_min[nDim1] = b->mins[nDim1]; + g_qeglobals.d_work_max[nDim1] = b->maxs[nDim1]; + g_qeglobals.d_work_min[nDim2] = b->mins[nDim2]; + g_qeglobals.d_work_max[nDim2] = b->maxs[nDim2]; +#endif +} + +// here to filter new brushes once unselected +extern void PerformFiltering(); + +void Select_Deselect (bool bDeselectFaces) +{ + brush_t *b; + + Patch_Deselect(); + + g_pParentWnd->ActiveXY()->UndoClear(); + + g_qeglobals.d_workcount++; + g_qeglobals.d_select_count = 0; + g_qeglobals.d_num_move_points = 0; + b = selected_brushes.next; + + if (b == &selected_brushes) + { + if (bDeselectFaces) + { + g_ptrSelectedFaces.RemoveAll(); + g_ptrSelectedFaceBrushes.RemoveAll(); + } + PerformFiltering(); + UpdateSurfaceDialog(); + Sys_UpdateWindows (W_ALL); + return; + } + + if (bDeselectFaces) + { + g_ptrSelectedFaces.RemoveAll(); + g_ptrSelectedFaceBrushes.RemoveAll(); + } + + g_qeglobals.d_select_mode = sel_brush; + + UpdateWorkzone_ForBrush(b); + + selected_brushes.next->prev = &active_brushes; + selected_brushes.prev->next = active_brushes.next; + active_brushes.next->prev = selected_brushes.prev; + active_brushes.next = selected_brushes.next; + selected_brushes.prev = selected_brushes.next = &selected_brushes; + + // filter newly created stuff once it's unselected + PerformFiltering(); + UpdateSurfaceDialog(); + Sys_UpdateWindows (W_ALL); +} + +/* +============ +Select_Move +============ +*/ +/*! Moves the currently selected brush/patch + \param delta How far to move the selection (x,y,z) + \param bSnap If the move should snap to grid points +*/ +void Select_Move (vec3_t delta, bool bSnap) +{ + brush_t *b; + + // actually move the selected brushes + for (b = selected_brushes.next ; b != &selected_brushes ; b=b->next) + Brush_Move (b, delta, bSnap); + + vec3_t vMin, vMax; + Select_GetBounds (vMin, vMax); + CString strStatus; + strStatus.Format("Origin X:: %.1f Y:: %.1f Z:: %.1f", vMin[0], vMax[1], vMax[2]); + g_pParentWnd->SetStatusText(2, strStatus); + + //Sys_UpdateWindows (W_ALL); +} + +/* +================= +Select_NudgeVerts +================= +*/ +/*! Moves the currently selected brush/patch vertices + \param delta How far to move the vertices (x,y,z) + \param bSnap If the move should snap to grid points +*/ +void Select_NudgePoint(vec3_t delta, qboolean bSnap) +{ + if (g_qeglobals.d_select_mode == sel_vertex) + { + // move selected verts + brush_t *b; + vec3_t end; + qboolean success = true; + for (b = selected_brushes.next; b != &selected_brushes; b = b->next) + { + success &= (qboolean)Brush_MoveVertex(b, g_qeglobals.d_move_points[0], delta, end, bSnap); + } + if (success) + VectorCopy(end, g_qeglobals.d_move_points[0]); + } + else if (g_qeglobals.d_select_mode == sel_curvepoint) + { + // move selected patch control points + Patch_UpdateSelected(delta); + } +} + +/* +============ +Select_Clone + +Creates an exact duplicate of the selection in place, then moves +the selected brushes off of their old positions +============ +*/ +void Select_Clone (void) +{ + g_bScreenUpdates = false; + g_pParentWnd->Copy(); + Select_Deselect(); + g_pParentWnd->Paste(); + g_pParentWnd->NudgeSelection(2, g_qeglobals.d_gridsize); + g_pParentWnd->NudgeSelection(3, g_qeglobals.d_gridsize); + Undo_Start("clone"); + Undo_EndBrushList(&selected_brushes); + Undo_End(); + g_bScreenUpdates = true; + Sys_UpdateWindows(W_ALL); +} + +//++timo clean +#if 0 +/* +============ +Select_SetTexture +Timo : bFitScale to compute scale on the plane and counteract plane / axial plane snapping +Timo : brush primitive texturing + the brushprimit_texdef given must be understood as a qtexture_t width=2 height=2 ( HiRes ) +Timo : texture plugin, added an IPluginTexdef* parameter + must be casted to an IPluginTexdef! + if not NULL, get ->Copy() of it into each face or brush ( and remember to hook ) + if NULL, means we have no information, ask for a default +TTimo - shader code cleanup + added IShader* parameter +============ +*/ +void WINAPI Select_SetTexture2 (IShader* pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, void* pPlugTexdef ) +{ + brush_t *b; + int nCount = g_ptrSelectedFaces.GetSize(); + if (nCount > 0) + { + Undo_Start("set face textures"); + ASSERT(g_ptrSelectedFaces.GetSize() == g_ptrSelectedFaceBrushes.GetSize()); + for (int i = 0; i < nCount; i++) + { + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(i)); + brush_t *selBrush = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(i)); + Undo_AddBrush(selBrush); + //++timo TODO: propagate the IShader* .. + SetFaceTexdef (selFace, texdef, brushprimit_texdef, bFitScale, static_cast(pPlugTexdef) ); + Brush_Build(selBrush, bFitScale); + Undo_EndBrush(selBrush); + } + Undo_End(); + } + else if (selected_brushes.next != &selected_brushes) + { + Undo_Start("set brush textures"); + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + if (!b->owner->eclass->fixedsize) + { + Undo_AddBrush(b); + Brush_SetTexture2 (b, pShader, texdef, brushprimit_texdef, bFitScale, static_cast(pPlugTexdef) ); + Undo_EndBrush(b); + } + Undo_End(); + } + Sys_UpdateWindows (W_ALL); +} +#endif + +/* +============ +Select_SetTexture +Timo : bFitScale to compute scale on the plane and counteract plane / axial plane snapping +Timo : brush primitive texturing + the brushprimit_texdef given must be understood as a qtexture_t width=2 height=2 ( HiRes ) +Timo : texture plugin, added an IPluginTexdef* parameter + must be casted to an IPluginTexdef! + if not NULL, get ->Copy() of it into each face or brush ( and remember to hook ) + if NULL, means we have no information, ask for a default +============ +*/ +void WINAPI Select_SetTexture (texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, void* pPlugTexdef ) +{ + /* +#ifdef _DEBUG + static int count = 0; +#endif + */ + brush_t *b; + /* +#ifdef _DEBUG + count++; + Sys_Printf("count: %d\n", count); + if(count==4) + Sys_Printf("break!\n"); +#endif + */ + int nCount = g_ptrSelectedFaces.GetSize(); + if (nCount > 0) + { + Undo_Start("set face textures"); + assert(g_ptrSelectedFaces.GetSize() == g_ptrSelectedFaceBrushes.GetSize()); + for (int i = 0; i < nCount; i++) + { + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(i)); + brush_t *selBrush = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(i)); + Undo_AddBrush(selBrush); + SetFaceTexdef (selFace, texdef, brushprimit_texdef, bFitScale, static_cast(pPlugTexdef) ); + Brush_Build(selBrush, bFitScale); + Undo_EndBrush(selBrush); + } + Undo_End(); + } + else if (selected_brushes.next != &selected_brushes) + { + Undo_Start("set brush textures"); + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + if (!b->owner->eclass->fixedsize) + { + Undo_AddBrush(b); + Brush_SetTexture (b, texdef, brushprimit_texdef, bFitScale, static_cast(pPlugTexdef) ); + Undo_EndBrush(b); + } + Undo_End(); + } + //++timo FIXME: not necessary in every cases, write a message defering / move one level up + Sys_UpdateWindows (W_ALL); +} + + +/* +================================================================ + + TRANSFORMATIONS + +================================================================ +*/ + +void Select_GetBounds (vec3_t mins, vec3_t maxs) +{ + brush_t *b; + int i; + + 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]; + } + } + } +} + +void Select_GetTrueMid (vec3_t mid) +{ + vec3_t mins, maxs; + Select_GetBounds (mins, maxs); + + for (int i=0 ; i<3 ; i++) + mid[i] = (mins[i] + ((maxs[i] - mins[i]) / 2)); +} + +void Select_GetMid (vec3_t mid) +{ + vec3_t mins, maxs; + int i; + + if (g_PrefsDlg.m_bNoClamp) + { + Select_GetTrueMid(mid); + return; + } + + Select_GetBounds (mins, maxs); + + for (i=0 ; i<3 ; i++) + mid[i] = g_qeglobals.d_gridsize*floor ( ( (mins[i] + maxs[i])*0.5 )/g_qeglobals.d_gridsize ); +} + +vec3_t select_origin; +vec3_t select_matrix[3]; +qboolean select_fliporder; + +// FIXME: bApplyBPrimit is supposed to be temporary +// TODO: manage Brush_Build calls, too many of them with the texture processing +// FIXME: the undo doesn't seem to work correctly on texturing and flip/rotate operations?? this is not supposed to be related to the texture locking code, so what is happening? +// FIXME: ApplyMatrix works on flipping operation, b0rks on Rotations (so does the "regular" rotation code??) +// FIXME: what is getting called in free rotation mode? that used to work right? +void Select_ApplyMatrix (bool bSnap, bool bRotation, int nAxis, float fDeg)//, qboolean bApplyBPrimit) +{ + brush_t *b; + face_t *f; + int i, j; + vec3_t temp, tmporigin; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + if(b->owner->eclass->fixedsize) + { + VectorCopy (b->owner->origin, tmporigin); + // transform the origin point + VectorSubtract (b->owner->origin, select_origin, temp); + for (j=0 ; j<3 ; j++) + b->owner->origin[j] = DotProduct(temp, select_matrix[j]) + select_origin[j]; + + // update the origin key + char text[64]; + sprintf (text, "%i %i %i", + (int)b->owner->origin[0], (int)b->owner->origin[1], (int)b->owner->origin[2]); + SetKeyValue(b->owner, "origin", text); + + /*\todo remove brush-based bounding box for fixedsize entities */ + VectorSubtract (b->owner->origin, tmporigin, temp); + for (f=b->brush_faces ; f ; f=f->next) + { + // move fixedsize bbox to new origin + for (i=0 ; i<3 ; i++) + VectorAdd (f->planepts[i], temp, f->planepts[i]); + } + Brush_Build(b, bSnap,true,false,false); // don't filter + + } + else if (b->patchBrush) + { + if (!bRotation && !((g_qeglobals.d_select_mode == sel_curvepoint && g_qeglobals.d_num_move_points != 0) || g_bPatchBendMode)) + // invert patch if this is a mirroring operation, unless points are selected or bendmode is active + patchInvert(b->pPatch); + // NOTE: does not clamp points to integers + Patch_ApplyMatrix(b->pPatch, select_origin, select_matrix, false); + } + else + { + for (f=b->brush_faces ; f ; f=f->next) + { + // FIXME: only in BP mode! + // if we are using Brush Primitives texturing, we need to compute the texture matrix after the geometric transformation + // (with the default texturing you don't need to compute anything for flipping and mirroring operations) + // if (bApplyBPrimit) { + // ApplyMatrix_BrushPrimit (f, select_matrix, select_origin, select_fliporder); + // } + for (i=0 ; i<3 ; i++) + { + VectorSubtract (f->planepts[i], select_origin, temp); + for (j=0 ; j<3 ; j++) + f->planepts[i][j] = DotProduct(temp, select_matrix[j]) + select_origin[j]; + } + if (select_fliporder) + { + VectorCopy (f->planepts[0], temp); + VectorCopy (f->planepts[2], f->planepts[0]); + VectorCopy (temp, f->planepts[2]); + } + } + Brush_Build(b, bSnap,true,false,false); // don't filter + } + } +} + +void ProjectOnPlane(vec3_t& normal,float dist,vec3_t& ez, vec3_t& p) +{ + if (fabs(ez[0]) == 1) + p[0] = (dist - normal[1] * p[1] - normal[2] * p[2]) / normal[0]; + else if (fabs(ez[1]) == 1) + p[1] = (dist - normal[0] * p[0] - normal[2] * p[2]) / normal[1]; + else + p[2] = (dist - normal[0] * p[0] - normal[1] * p[1]) / normal[2]; +} + +void Back(vec3_t& dir, vec3_t& p) +{ + if (fabs(dir[0]) == 1) + p[0] = 0; + else if (fabs(dir[1]) == 1) + p[1] = 0; + else p[2] = 0; +} + + + +// using scale[0] and scale[1] +void ComputeScale(vec3_t& rex, vec3_t& rey, vec3_t& p, face_t* f) +{ + float px = DotProduct(rex, p); + float py = DotProduct(rey, p); + px *= f->texdef.scale[0]; + py *= f->texdef.scale[1]; + vec3_t aux; + VectorCopy(rex, aux); + VectorScale(aux, px, aux); + VectorCopy(aux, p); + VectorCopy(rey, aux); + VectorScale(aux, py, aux); + VectorAdd(p, aux, p); +} + +void ComputeAbsolute(face_t* f, vec3_t& p1, vec3_t& p2, vec3_t& p3) +{ + vec3_t ex,ey,ez; // local axis base + +#ifdef _DEBUG + if (g_qeglobals.m_bBrushPrimitMode) + Sys_Printf("Warning : illegal call of ComputeAbsolute in brush primitive mode\n"); +#endif + + // compute first local axis base + TextureAxisFromPlane(&f->plane, ex, ey); + CrossProduct(ex, ey, ez); + + vec3_t aux; + VectorCopy(ex, aux); + VectorScale(aux, -f->texdef.shift[0], aux); + VectorCopy(aux, p1); + VectorCopy(ey, aux); + VectorScale(aux, -f->texdef.shift[1], aux); + VectorAdd(p1, aux, p1); + VectorCopy(p1, p2); + VectorAdd(p2, ex, p2); + VectorCopy(p1, p3); + VectorAdd(p3, ey, p3); + VectorCopy(ez, aux); + VectorScale(aux, -f->texdef.rotate, aux); + VectorRotate(p1, aux, p1); + VectorRotate(p2, aux, p2); + VectorRotate(p3, aux, p3); + // computing rotated local axis base + vec3_t rex,rey; + VectorCopy(ex, rex); + VectorRotate(rex, aux, rex); + VectorCopy(ey, rey); + VectorRotate(rey, aux, rey); + + ComputeScale(rex,rey,p1,f); + ComputeScale(rex,rey,p2,f); + ComputeScale(rex,rey,p3,f); + + // project on normal plane + // along ez + // assumes plane normal is normalized + ProjectOnPlane(f->plane.normal,f->plane.dist,ez,p1); + ProjectOnPlane(f->plane.normal,f->plane.dist,ez,p2); + ProjectOnPlane(f->plane.normal,f->plane.dist,ez,p3); +}; + + +void AbsoluteToLocal(plane_t normal2, face_t* f, vec3_t& p1, vec3_t& p2, vec3_t& p3) +{ + vec3_t ex,ey,ez; + +#ifdef _DEBUG + if (g_qeglobals.m_bBrushPrimitMode) + Sys_Printf("Warning : illegal call of AbsoluteToLocal in brush primitive mode\n"); +#endif + + // computing new local axis base + TextureAxisFromPlane(&normal2, ex, ey); + CrossProduct(ex, ey, ez); + + // projecting back on (ex,ey) + Back(ez,p1); + Back(ez,p2); + Back(ez,p3); + + vec3_t aux; + // rotation + VectorCopy(p2, aux); + VectorSubtract(aux, p1,aux); + + float x = DotProduct(aux,ex); + float y = DotProduct(aux,ey); + f->texdef.rotate = 180 * atan2(y,x) / Q_PI; + + vec3_t rex,rey; + // computing rotated local axis base + VectorCopy(ez, aux); + VectorScale(aux, f->texdef.rotate, aux); + VectorCopy(ex, rex); + VectorRotate(rex, aux, rex); + VectorCopy(ey, rey); + VectorRotate(rey, aux, rey); + + // scale + VectorCopy(p2, aux); + VectorSubtract(aux, p1, aux); + f->texdef.scale[0] = DotProduct(aux, rex); + VectorCopy(p3, aux); + VectorSubtract(aux, p1, aux); + f->texdef.scale[1] = DotProduct(aux, rey); + + // shift + // only using p1 + x = DotProduct(rex,p1); + y = DotProduct(rey,p1); + x /= f->texdef.scale[0]; + y /= f->texdef.scale[1]; + + VectorCopy(rex, p1); + VectorScale(p1, x, p1); + VectorCopy(rey, aux); + VectorScale(aux, y, aux); + VectorAdd(p1, aux, p1); + VectorCopy(ez, aux); + VectorScale(aux, -f->texdef.rotate, aux); + VectorRotate(p1, aux, p1); + f->texdef.shift[0] = -DotProduct(p1, ex); + f->texdef.shift[1] = -DotProduct(p1, ey); + + // stored rot is good considering local axis base + // change it if necessary + f->texdef.rotate = -f->texdef.rotate; + + Clamp(f->texdef.shift[0], f->d_texture->width); + Clamp(f->texdef.shift[1], f->d_texture->height); + Clamp(f->texdef.rotate, 360); + +} + +void RotateFaceTexture(face_t* f, int nAxis, float fDeg) +{ + vec3_t p1,p2,p3, rota; + p1[0] = p1[1] = p1[2] = 0; + VectorCopy(p1, p2); + VectorCopy(p1, p3); + VectorCopy(p1, rota); + ComputeAbsolute(f, p1, p2, p3); + + rota[nAxis] = fDeg; + VectorRotateOrigin (p1, rota, select_origin, p1); + VectorRotateOrigin (p2, rota, select_origin, p2); + VectorRotateOrigin (p3, rota, select_origin, p3); + + plane_t normal2; + vec3_t vNormal; + vNormal[0] = f->plane.normal[0]; + vNormal[1] = f->plane.normal[1]; + vNormal[2] = f->plane.normal[2]; + VectorRotate(vNormal, rota, vNormal); + normal2.normal[0] = vNormal[0]; + normal2.normal[1] = vNormal[1]; + normal2.normal[2] = vNormal[2]; + AbsoluteToLocal(normal2, f, p1, p2 ,p3); + +} + +void RotateTextures(int nAxis, float fDeg, vec3_t vOrigin) +{ + for (brush_t* b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + for (face_t* f=b->brush_faces ; f ; f=f->next) + { + if (g_qeglobals.m_bBrushPrimitMode) + RotateFaceTexture_BrushPrimit (f, nAxis, fDeg, vOrigin); + else + RotateFaceTexture (f, nAxis, fDeg); + } + Brush_Build(b, false,true,false,false); // don't filter + } +} + +void Select_ApplyMatrix_BrushPrimit() +{ + #ifdef _DEBUG + if (!g_qeglobals.m_bBrushPrimitMode) { + Sys_FPrintf(SYS_ERR,"ERROR: Select_ApplyMatrix_BrushPrimit called in non-BP mode\n"); + } + #endif + for (brush_t* b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + for (face_t* f=b->brush_faces ; f ; f=f->next) + { + ApplyMatrix_BrushPrimit (f, select_matrix, select_origin); + } + } +} + +void Select_FlipAxis (int axis) +{ + int i; + + Select_GetMid (select_origin); + for (i=0 ; i<3 ; i++) + { + VectorCopy (vec3_origin, select_matrix[i]); + select_matrix[i][i] = 1; + } + select_matrix[axis][axis] = -1; + select_fliporder = true; + + // texture locking + if (g_PrefsDlg.m_bRotateLock) { + // axis flipping inverts space orientation, we have to use a general texture locking algorithm instead of the RotateFaceTexture + if (g_qeglobals.m_bBrushPrimitMode) { + Select_ApplyMatrix_BrushPrimit(); + } + else + { + // there's never been flip locking for non BP mode, this would be tricky to write and there's not much interest for it with the coming of BP format + // what could be done is converting regular to BP, locking, then back to regular :) + Sys_FPrintf(SYS_WRN, "WARNING: regular texturing doesn't have texture lock on flipping operations\n"); + } + } + // geometric transformation + Select_ApplyMatrix (true, false, 0, 0); + Sys_UpdateWindows (W_ALL); +} + + +void Select_Scale(float x, float y, float z) +{ + Select_GetMid (select_origin); + for (brush_t* b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + // ignore fixedsize entities + if(b->owner->eclass->fixedsize) continue; + for (face_t* f=b->brush_faces ; f ; f=f->next) + { + for (int i=0 ; i<3 ; i++) + { + f->planepts[i][0] -= select_origin[0]; + f->planepts[i][1] -= select_origin[1]; + f->planepts[i][2] -= select_origin[2]; + f->planepts[i][0] *= x; + f->planepts[i][1] *= y; + f->planepts[i][2] *= z; + + f->planepts[i][0] += select_origin[0]; + f->planepts[i][1] += select_origin[1]; + f->planepts[i][2] += select_origin[2]; + } + } + Brush_Build(b, false,true,false,false); // don't filter + if (b->patchBrush) + { + vec3_t v; + v[0] = x; + v[1] = y; + v[2] = z; + Patch_Scale(b->pPatch, select_origin, v); + } + } +} + +void Select_RotateAxis (int axis, float deg, bool bPaint, bool bMouse) +{ + int i; + vec_t c, s; + + if (deg == 0) + { + return; + } + + if (bMouse) + { + VectorCopy(g_pParentWnd->ActiveXY()->RotateOrigin(), select_origin); + } + else + { + Select_GetMid (select_origin); + } + + /* + if(axis == 2) + { + vec3_t rotation; + VectorSet(rotation, 0, 0, 360 - deg); + for(brush_t *b = selected_brushes.next; b != &selected_brushes; b = b->next) + if(b->owner->model.pEdit) + b->owner->model.pEdit->Rotate(select_origin, rotation); + } + */ + + select_fliporder = false; + + // the "90" degrees algorithm is mostly used on axis rotate as a speedup and possibly avoiding rounding errors as much as possible + // previous implementation was doing an indirect-oriented rotation over the plane whereas the general algo below was doing a direct-oriented rotation + // this was confusing the texture locking algorithms, fixed it to be direct-oriented (side consequence is that the axis rotate toolbar button rotates the other way now) + // NOTE: previous algo was using vec3_origin in the matrix computation.. + // I don't see what an origin does in linear transformations (3x3 matrixes always relate to a (0,0,0) origin) + // in Radiant it's initialized as (0,0,0) and never set to another value + // so I got rid of it when it's not used for initialisation tasks (and even if it's not (0,0,0) it should not matter + if (deg == 90) + { + c = 0; + s = 1; + } + else + { + c = cos(deg * Q_PI / 180.0); + s = sin(deg * Q_PI / 180.0); + } + + for (i=0 ; i<3 ; i++) + { + VectorCopy (vec3_origin, select_matrix[i]); + select_matrix[i][i] = 1; + } + + switch (axis) + { + case 0: + select_matrix[1][1] = c; + select_matrix[1][2] = s; + select_matrix[2][1] = -s; + select_matrix[2][2] = c; + break; + case 1: + select_matrix[0][0] = c; + select_matrix[0][2] = s; + select_matrix[2][0] = -s; + select_matrix[2][2] = c; + break; + case 2: + select_matrix[0][0] = c; + select_matrix[0][1] = s; + select_matrix[1][0] = -s; + select_matrix[1][1] = c; + break; + } + + + // texture locking + if (g_PrefsDlg.m_bRotateLock) + { + // Terrible hack, reversing input rotation angle to correct + // texture rotation direction for X and Z axes. + // RotateTextures needs to be changed to fix this properly? + if (axis == 1) + RotateTextures(axis, deg, select_origin); + else + RotateTextures(axis, deg * -1, select_origin); + } + // geometric transformation + Select_ApplyMatrix(!bMouse, true, axis, deg);//, false); + + if (bPaint) + Sys_UpdateWindows (W_ALL); +} + +/* +================================================================ + +GROUP SELECTIONS + +================================================================ +*/ + +void Select_RealCompleteTall(vec3_t mins, vec3_t maxs) +{ + brush_t *b, *next; + + int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0; + int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2; + + g_qeglobals.d_select_mode = sel_brush; + + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + + if (b->bFiltered) + continue; + + if ( (b->maxs[nDim1] > maxs[nDim1] || b->mins[nDim1] < mins[nDim1]) + || (b->maxs[nDim2] > maxs[nDim2] || b->mins[nDim2] < mins[nDim2]) ) + continue; + + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } +} + +void Select_CompleteTall (void) +{ + vec3_t mins, maxs; + + if (!QE_SingleBrush ()) + return; + + Undo_Start ("select complete tall"); + Undo_AddBrushList (&selected_brushes); + Undo_End(); + + VectorCopy (selected_brushes.next->mins, mins); + VectorCopy (selected_brushes.next->maxs, maxs); + Select_Delete (); + + Select_RealCompleteTall(mins, maxs); + Sys_UpdateWindows (W_ALL); +} + +void Select_PartialTall (void) +{ + brush_t *b, *next; + vec3_t mins, maxs; + + if (!QE_SingleBrush ()) + return; + + Undo_Start ("select complete tall"); + Undo_AddBrushList (&selected_brushes); + Undo_End(); + + g_qeglobals.d_select_mode = sel_brush; + + VectorCopy (selected_brushes.next->mins, mins); + VectorCopy (selected_brushes.next->maxs, maxs); + Select_Delete (); + + int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0; + int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2; + + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + + if (b->bFiltered) + continue; + + if ( (b->mins[nDim1] > maxs[nDim1] || b->maxs[nDim1] < mins[nDim1]) + || (b->mins[nDim2] > maxs[nDim2] || b->maxs[nDim2] < mins[nDim2]) ) + continue; + + + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + + Sys_UpdateWindows (W_ALL); +} + +void Select_Touching (void) +{ + brush_t *b, *next; + int i; + vec3_t mins, maxs; + + if (!QE_SingleBrush ()) + return; + + g_qeglobals.d_select_mode = sel_brush; + + VectorCopy (selected_brushes.next->mins, mins); + VectorCopy (selected_brushes.next->maxs, maxs); + + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + + if (b->bFiltered) + continue; + + for (i=0 ; i<3 ; i++) + if (b->mins[i] > maxs[i]+1 || b->maxs[i] < mins[i]-1) + break; + + if (i == 3) + { + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + } + + Sys_UpdateWindows (W_ALL); +} + +void Select_Inside (void) +{ + brush_t *b, *next; + int i; + vec3_t mins, maxs; + + if (!QE_SingleBrush ()) + return; + + Undo_Start ("select inside"); + Undo_AddBrushList (&selected_brushes); + Undo_End(); + + g_qeglobals.d_select_mode = sel_brush; + + VectorCopy (selected_brushes.next->mins, mins); + VectorCopy (selected_brushes.next->maxs, maxs); + Select_Delete (); + + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + + if (b->bFiltered) + continue; + + for (i=0 ; i<3 ; i++) + if (b->maxs[i] > maxs[i] || b->mins[i] < mins[i]) + break; + if (i == 3) + { + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + } + + Sys_UpdateWindows (W_ALL); +} + +void Select_Ungroup(void) +{ + int numselectedgroups; + entity_t *e; + brush_t *b,* sb; + + numselectedgroups = 0; + for (sb = selected_brushes.next; sb != &selected_brushes; sb = sb->next) + { + e = sb->owner; + + if (e == world_entity || e->eclass->fixedsize) + { + continue; + } + + for (b = e->brushes.onext; b != &e->brushes; b = e->brushes.onext) + { + Entity_UnlinkBrush (b); + Entity_LinkBrush (world_entity, b); + } + Entity_Free (e); + numselectedgroups++; + } + + if (numselectedgroups <= 0) + { + Sys_Printf("No grouped entities selected.\n"); + return; + } + Sys_Printf("Ungrouped %d entit%s.\n", numselectedgroups, (numselectedgroups == 1)?"y":"ies"); + Sys_UpdateWindows (W_ALL); +} + +/*! +group selected brushes into specified entity +if an entity is empty afterwards, destroy it +*/ +void Select_GroupEntity(entity_t* group) +{ + entity_t* e; + brush_t *b; + + if(group->eclass->fixedsize) + { + Sys_FPrintf (SYS_ERR, "Select_GroupEntity: can't group anything to a fixedsize entity\n"); + return; + } + + for (b = selected_brushes.next; b != &selected_brushes; b = b->next) + { + if(b->owner->eclass->fixedsize) continue; + e = b->owner; + Entity_UnlinkBrush(b); + Entity_LinkBrush(group, b); + if(e != world_entity && e->brushes.onext == &e->brushes) + { + Undo_AddEntity(e); + Entity_Free(e); + } + } +} + +/*! +merge all selected entities together into the first one selected +NOTE: makes use of order of selected_brushes list +can be used to move world brushes in an entity, or to merge several ents together +NOTE: didn't devise a strategy on the epairs, we merge into the first entity and use those +*/ +void Select_MergeEntity() +{ + entity_t* e = NULL; + brush_t* b; + for (b = selected_brushes.next; b != &selected_brushes; b = b->next) + { + if(!b->owner->eclass->fixedsize) + { + e = b->owner; + break; + } + } + + if(e != NULL) + { + Select_GroupEntity(e); + + int count = 0; + for(b = e->brushes.onext; b != &e->brushes; b=b->onext) + { + //Brush_RemoveFromList (b); + //Brush_AddToList(b, &active_brushes); + count++; + } + Sys_Printf ("Merged %d brushes into %s entity\n", count, ValueForKey (e, "classname")); + } +} + +/* +==================== +Select_Seperate +==================== +*/ +void Select_Seperate( void ) { + Select_GroupEntity( world_entity ); +} + +/* +==================== +Select_MakeStructural +==================== +*/ +void Select_MakeStructural (void) +{ + brush_t *b; + face_t *f; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + for (f=b->brush_faces ; f ; f=f->next) + f->texdef.contents &= ~CONTENTS_DETAIL; + b->bFiltered = FilterBrush(b); + } + Select_Deselect (); + Sys_UpdateWindows (W_ALL); +} + +void Select_MakeDetail (void) +{ + brush_t *b; + face_t *f; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + for (f=b->brush_faces ; f ; f=f->next) + f->texdef.contents |= CONTENTS_DETAIL; + b->bFiltered = FilterBrush(b); + } + Select_Deselect (); + Sys_UpdateWindows (W_ALL); +} + +// brush primitive texture adjustments, use the camera view to map adjustments +// ShiftTextureRelative_BrushPrimit ( s , t ) will shift relative to the texture +void ShiftTextureRelative_Camera(face_t *f, int x, int y) +{ + vec3_t vecS, vecT; + vec_t XY[2]; // the values we are going to send for translation + vec_t sgn[2]; // +1 or -1 + int axis[2]; + CamWnd* pCam; + + // get the two relative texture axes for the current texturing + BrushPrimit_GetRelativeAxes(f, vecS, vecT); + + // center point of the face, project it on the camera space + vec3_t C; + VectorClear(C); + int i; + for (i=0; iface_winding->numpoints; i++) + { + VectorAdd(C,f->face_winding->points[i],C); + } + VectorScale(C,1.0/f->face_winding->numpoints,C); + + pCam = g_pParentWnd->GetCamWnd(); + pCam->MatchViewAxes(C, vecS, axis[0], sgn[0]); + pCam->MatchViewAxes(C, vecT, axis[1], sgn[1]); + + // this happens when the two directions can't be mapped on two different directions on the screen + // then the move will occur against a single axis + // (i.e. the user is not positioned well enough to send understandable shift commands) + // NOTE: in most cases this warning is not very relevant because the user would use one of the two axes + // for which the solution is easy (the other one being unknown) + // so this warning could be removed + if (axis[0] == axis[1]) + Sys_FPrintf(SYS_WRN, "Warning: degenerate in ShiftTextureRelative_Camera\n"); + + // compute the X Y geometric increments + // those geometric increments will be applied along the texture axes (the ones we computed above) + XY[0] = 0; + XY[1] = 0; + if (x!=0) + { + // moving right/left + XY[axis[0]] += sgn[0]*x; + } + if (y!=0) + { + XY[axis[1]] += sgn[1]*y; + } + // we worked out a move along vecS vecT, and we now it's geometric amplitude + // apply it + ShiftTextureRelative_BrushPrimit(f, XY[0], XY[1]); +} + +void Select_ShiftTexture(int x, int y) +{ + brush_t *b; + face_t *f; + + int nFaceCount = g_ptrSelectedFaces.GetSize(); + + if(selected_brushes.next == &selected_brushes && nFaceCount == 0) + return; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + for (f=b->brush_faces ; f ; f=f->next) + { + if (g_qeglobals.m_bBrushPrimitMode) + { + ShiftTextureRelative_Camera( f, x, y ); + } + else + { + f->texdef.shift[0] += x; + f->texdef.shift[1] += y; + } + } + Brush_Build(b,true,true,false,false); // don't filter + if (b->patchBrush) + { + Patch_ShiftTexture(b->pPatch, x, y); + } + } + + if (nFaceCount > 0) + { + for (int i = 0; i < nFaceCount; i++) + { + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(i)); + brush_t *selBrush = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(i)); + if (g_qeglobals.m_bBrushPrimitMode) + { + ShiftTextureRelative_Camera( selFace, x, y ); + } + else + { + selFace->texdef.shift[0] += x; + selFace->texdef.shift[1] += y; + } + Brush_Build(selBrush,true,true,false,false); // don't filter + } + } + + Sys_UpdateWindows (W_CAMERA); +} + +// setting float as input +void Select_ScaleTexture(float x, float y) +{ + brush_t *b; + face_t *f; + + int nFaceCount = g_ptrSelectedFaces.GetSize(); + + if(selected_brushes.next == &selected_brushes && nFaceCount == 0) + { + return; + } + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + for (f=b->brush_faces ; f ; f=f->next) + { + if (g_qeglobals.m_bBrushPrimitMode) + { + // apply same scale as the spinner button of the surface inspector + float shift[2]; + float rotate; + float scale[2]; + brushprimit_texdef_t bp; + // compute normalized texture matrix + ConvertTexMatWithQTexture( &f->brushprimit_texdef, f->d_texture, &bp, NULL ); + // compute fake shift scale rot + TexMatToFakeTexCoords( bp.coords, shift, &rotate, scale ); + // update + scale[0]+=static_cast(x)*0.1; + scale[1]+=static_cast(y)*0.1; + // compute new normalized texture matrix + FakeTexCoordsToTexMat( shift, rotate, scale, bp.coords ); + // apply to face texture matrix + ConvertTexMatWithQTexture( &bp, NULL, &f->brushprimit_texdef, f->d_texture ); + } + else + { + f->texdef.scale[0] += x; + f->texdef.scale[1] += y; + } + } + Brush_Build(b,true,true,false,false); // don't filter + if (b->patchBrush) + { + Patch_ScaleTexture(b->pPatch, x, y); + } + } + + if (nFaceCount > 0) + { + for (int i = 0; i < nFaceCount; i++) + { + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(i)); + brush_t *selBrush = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(i)); + if (g_qeglobals.m_bBrushPrimitMode) + { + float shift[2]; + float rotate; + float scale[2]; + brushprimit_texdef_t bp; + ConvertTexMatWithQTexture( &selFace->brushprimit_texdef, selFace->d_texture, &bp, NULL ); + TexMatToFakeTexCoords( bp.coords, shift, &rotate, scale ); + scale[0]+=static_cast(x)*0.1; + scale[1]+=static_cast(y)*0.1; + FakeTexCoordsToTexMat( shift, rotate, scale, bp.coords ); + ConvertTexMatWithQTexture( &bp, NULL, &selFace->brushprimit_texdef, selFace->d_texture ); + } + else + { + selFace->texdef.scale[0] += x; + selFace->texdef.scale[1] += y; + } + Brush_Build(selBrush,true,true,false,false); // don't filter + } + } + + Sys_UpdateWindows (W_CAMERA); +} + +void Select_RotateTexture(int amt) +{ + brush_t *b; + face_t *f; + + int nFaceCount = g_ptrSelectedFaces.GetSize(); + + if(selected_brushes.next == &selected_brushes && nFaceCount == 0) + { + return; + } + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + for (f=b->brush_faces ; f ; f=f->next) + { + if (g_qeglobals.m_bBrushPrimitMode) + { + // apply same scale as the spinner button of the surface inspector + float shift[2]; + float rotate; + float scale[2]; + brushprimit_texdef_t bp; + // compute normalized texture matrix + ConvertTexMatWithQTexture( &f->brushprimit_texdef, f->d_texture, &bp, NULL ); + // compute fake shift scale rot + TexMatToFakeTexCoords( bp.coords, shift, &rotate, scale ); + // update + rotate += amt; + // compute new normalized texture matrix + FakeTexCoordsToTexMat( shift, rotate, scale, bp.coords ); + // apply to face texture matrix + ConvertTexMatWithQTexture( &bp, NULL, &f->brushprimit_texdef, f->d_texture ); + } + else + { + f->texdef.rotate += amt; + f->texdef.rotate = static_cast(f->texdef.rotate) % 360; + } + } + Brush_Build(b,true,true,false,false); // don't filter + if (b->patchBrush) + { + //Patch_RotateTexture(b->nPatchID, amt); + Patch_RotateTexture(b->pPatch, amt); + } + } + + if (nFaceCount > 0) + { + for (int i = 0; i < nFaceCount; i++) + { + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(i)); + brush_t *selBrush = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(i)); + if (g_qeglobals.m_bBrushPrimitMode) + { + float shift[2]; + float rotate; + float scale[2]; + brushprimit_texdef_t bp; + ConvertTexMatWithQTexture( &selFace->brushprimit_texdef, selFace->d_texture, &bp, NULL ); + TexMatToFakeTexCoords( bp.coords, shift, &rotate, scale ); + rotate += amt; + FakeTexCoordsToTexMat( shift, rotate, scale, bp.coords ); + ConvertTexMatWithQTexture( &bp, NULL, &selFace->brushprimit_texdef, selFace->d_texture ); + } + else + { + selFace->texdef.rotate += amt; + selFace->texdef.rotate = static_cast(selFace->texdef.rotate) % 360; + } + Brush_Build(selBrush,true,true,false,false); // don't filter + } + } + + Sys_UpdateWindows (W_CAMERA); +} + +// TTimo modified to handle shader architecture: +// expects shader names at input, comparison relies on shader names .. texture names no longer relevant +void FindReplaceTextures(const char* pFind, const char* pReplace, bool bSelected, bool bForce, bool bSelectMatchingFaces) +{ + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=391 + if (strchr(pFind, ' ') || strchr(pReplace, ' ')) + { + Sys_FPrintf(SYS_WRN, "FindReplaceTextures: '%s' or '%s' have spaces, aborted\n", pFind, pReplace); + return; + } + + brush_t* pList = (bSelected) ? &selected_brushes : &active_brushes; + if (!bSelected) + Select_Deselect(); + + //++timo BP mode: replacing a texture in BP mode is not that easy, you need to recompute the texture matrix + // if the size of the replacing texture differs, otherwise you get wrong scaling + if (g_qeglobals.m_bBrushPrimitMode) + Sys_Printf("TODO: finalize find/replace code for brush primitives"); + + CPtrArray mFaces; + for (brush_t* pBrush = pList->next ; pBrush != pList; pBrush = pBrush->next) + { + if (!bSelectMatchingFaces && pBrush->patchBrush) + { + Patch_FindReplaceTexture(pBrush, pFind, pReplace, bForce); + } + + bool found = false; //spog + for (face_t* pFace = pBrush->brush_faces; pFace; pFace = pFace->next) + { + if(bForce || strcmpi(pFace->pShader->getName(), pFind) == 0) + { + if (!bSelectMatchingFaces) { + pFace->pShader->DecRef(); + pFace->pShader = QERApp_Shader_ForName( pReplace ); + pFace->pShader->IncRef(); + pFace->d_texture = pFace->pShader->getTexture(); + pFace->texdef.SetName(pReplace); + found = true; + } else if (bSelectMatchingFaces) { + mFaces.Add(pFace); + } + } + } + + if (found) // spog - speed increase, only build brushes that changed + Brush_Build(pBrush); + + } + + if (bSelectMatchingFaces) { + if (bSelected) + Select_Deselect(); + + int nSize = mFaces.GetSize(); + for (int i = 0; i < nSize; i++) { + g_SelectedFaces.Add(reinterpret_cast(mFaces.GetAt(i))); + } + } + + Sys_UpdateWindows (W_CAMERA); +} + +void Select_AllOfType() +{ + brush_t *b, *next; + entity_t *e; + // if no brush selected, we will select based on texture + // the first selected face's texture if any, or the current texture + // if a brush is selected, we will select entities (first non-worldspawn owner in selected brushes) + if (selected_brushes.next == &selected_brushes) + { + + CString strName; + if (g_ptrSelectedFaces.GetSize() == 0) + { + strName = g_qeglobals.d_texturewin.texdef.GetName(); + } + else + { + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(0)); + strName = selFace->texdef.GetName(); + } + + Sys_Printf("Selecting all brushes with the texture %s\n", strName.GetBuffer()); + + Select_Deselect(); + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + + if (b->bFiltered) + continue; + + if (b->patchBrush) + { + if (strcmpi(strName, b->pPatch->pShader->getName()) == 0) + { + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + } + else + { + for (face_t* pFace = b->brush_faces; pFace; pFace = pFace->next) + { + if (strcmpi(strName, pFace->texdef.GetName()) == 0) + { + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + } + } + } + Sys_UpdateWindows(W_ALL); + return; + } + + + b = selected_brushes.next; + e = b->owner; + + if (e != NULL) + { + if (e != world_entity) + { + CString strName = e->eclass->name; + CString strKey, strVal; + bool bCriteria = GetSelectAllCriteria(strKey, strVal); + Sys_Printf("Selecting all %s entities\n", strName.GetBuffer()); + Select_Deselect(); + + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + + if (b->bFiltered) + continue; + + e = b->owner; + if (e != NULL) + { + if (strcmpi(e->eclass->name, strName) == 0) + { + bool doIt = true; + if (bCriteria) { + CString str = ValueForKey (e, strKey); + if (str.CompareNoCase(strVal) != 0) { + doIt = false; + } + } + if (doIt) { + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + } + } + } + } + } + Sys_UpdateWindows (W_ALL); + +} + +void Select_Reselect() +{ + Select_Brush(selected_brushes.next); + Sys_UpdateWindows (W_ALL); +} + + +void Select_FitTexture(int nHeight, int nWidth) +{ + brush_t *b; + + int nFaceCount = g_ptrSelectedFaces.GetSize(); + + if(selected_brushes.next == &selected_brushes && nFaceCount == 0) + return; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + Brush_FitTexture(b, nHeight, nWidth); + Brush_Build(b,true,true,false,false); // don't filter + } + + if (nFaceCount > 0) + { + for (int i = 0; i < nFaceCount; i++) + { + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(i)); + brush_t *selBrush = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(i)); + Face_FitTexture(selFace, nHeight, nWidth); + Brush_Build(selBrush,true,true,false,false); // don't filter + } + } + + Sys_UpdateWindows (W_CAMERA); +} + +void Select_Hide() +{ + for (brush_t* b=selected_brushes.next ; b && b != &selected_brushes ; b=b->next) + { + b->hiddenBrush = true; + b->bFiltered = true; + } + Sys_UpdateWindows (W_ALL); +} + +void Select_ShowAllHidden() +{ + brush_t* b; + for (b=selected_brushes.next ; b && b != &selected_brushes ; b=b->next) + { + if (b->hiddenBrush) + { + b->hiddenBrush = false; + b->bFiltered = FilterBrush(b); + } + } + for (b=active_brushes.next ; b && b != &active_brushes ; b=b->next) + { + if (b->hiddenBrush) + { + b->hiddenBrush = false; + b->bFiltered = FilterBrush(b); + } + } + Sys_UpdateWindows (W_ALL); +} + + +/* +============ +Select_Invert +============ +*/ +void Select_Invert(void) +{ + brush_t *next, *prev, *b; + + Sys_Printf("inverting selection...\n"); + + next = active_brushes.next; + prev = active_brushes.prev; + if (selected_brushes.next != &selected_brushes) + { + active_brushes.next = selected_brushes.next; + active_brushes.prev = selected_brushes.prev; + active_brushes.next->prev = &active_brushes; + active_brushes.prev->next = &active_brushes; + } + else + { + active_brushes.next = &active_brushes; + active_brushes.prev = &active_brushes; + } + if (next != &active_brushes) + { + selected_brushes.next = next; + selected_brushes.prev = prev; + selected_brushes.next->prev = &selected_brushes; + selected_brushes.prev->next = &selected_brushes; + } + else + { + selected_brushes.next = &selected_brushes; + selected_brushes.prev = &selected_brushes; + } + + // now check if any hidden brush is selected + for (b = selected_brushes.next; b != &selected_brushes; ) + { + if (b->patchBrush) + b->pPatch->bSelected = true; + + if (b->bFiltered) + { + brush_t *pb = b; + b = b->next; + Brush_RemoveFromList (pb); + Brush_AddToList (pb, &active_brushes); + } + else b = b->next; + + } + + for (b = active_brushes.next; b != &active_brushes; b = b->next) + { + if (b->patchBrush) + { + b->pPatch->bSelected = false; + } + } + + // since invert selection only works at the brush level, + // set g_qeglobals.d_select_mode accordingly + g_qeglobals.d_select_mode = sel_brush; + + // since invert selection only works at the brush level, + // set g_qeglobals.d_select_mode accordingly + g_qeglobals.d_select_mode = sel_brush; + + Sys_UpdateWindows(W_ALL); + + Sys_Printf("done.\n"); +} + +#ifdef ENABLE_GROUPS +/* +=========== +Select_Name +=========== +*/ +void Select_Name(const char *pName) +{ + if (g_qeglobals.m_bBrushPrimitMode) + { + for (brush_t* b=selected_brushes.next ; b && b != &selected_brushes ; b=b->next) + { + Brush_SetEpair(b, "Name", pName); + } + } +} + +/* +================= +Select_AddToGroup +add selected brushes to a group, update the tree +================= +*/ +void Select_AddToGroup(const char *pName) +{ + if (g_qeglobals.m_bBrushPrimitMode) + { + for (brush_t* b=selected_brushes.next ; b && b != &selected_brushes ; b=b->next) + { + Brush_SetEpair(b, "group", pName); + Group_AddToProperGroup(b); + } + } +} +#endif diff --git a/radiant/selectedface.cpp b/radiant/selectedface.cpp index 3954a035..b325df59 100644 --- a/radiant/selectedface.cpp +++ b/radiant/selectedface.cpp @@ -1,128 +1,128 @@ -/* -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 -*/ - -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// Quick interface hack for selected face interface -// this one really needs more work, but I'm in a hurry with TexTool - -#include "stdafx.h" - -int WINAPI QERApp_GetSelectedFaceCount() -{ - return g_ptrSelectedFaces.GetSize(); -} - -face_t* WINAPI QERApp_GetSelectedFace(int iface) -{ - if (iface>=g_ptrSelectedFaces.GetSize()) - { - Sys_FPrintf (SYS_ERR, "QERApp_GetFace: selected faces count exceeded\n"); - return NULL; - } - return reinterpret_cast(g_ptrSelectedFaces.GetAt(iface)); -} - -brush_t* WINAPI QERApp_GetSelectedFaceBrush(int iface) -{ - if (iface>=g_ptrSelectedFaceBrushes.GetSize()) - { - Sys_FPrintf (SYS_ERR, "QERApp_GetFace: selected faces count exceeded\n"); - return NULL; - } - return reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(iface)); -} - -// NOTE: we expect pWinding to have MAX_POINTS_ON_WINDING points ready for writing -int WINAPI QERApp_GetFaceInfo(int iface, _QERFaceData *pFaceData, winding_t *pWinding) -{ - int size; - - if (iface>=g_ptrSelectedFaces.GetSize()) - { - Sys_FPrintf (SYS_ERR, "QERApp_GetFaceInfo: selected faces count exceeded\n"); - return 0; - } - if (!g_qeglobals.m_bBrushPrimitMode) - { - Sys_Printf("Warning: unexpected QERApp_GetFaceInfo out of brush primitive mode\n"); - return 0; - } - face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(iface)); - strcpy( pFaceData->m_TextureName, selFace->texdef.GetName() ); - VectorCopy( selFace->planepts[0], pFaceData->m_v1 ); - VectorCopy( selFace->planepts[1], pFaceData->m_v2 ); - VectorCopy( selFace->planepts[2], pFaceData->m_v3 ); - pFaceData->m_bBPrimit = true; - memcpy( &pFaceData->brushprimit_texdef, &selFace->brushprimit_texdef, sizeof(brushprimit_texdef_t) ); - size = (int)((winding_t *)0)->points[selFace->face_winding->numpoints]; - memcpy( pWinding, selFace->face_winding, size ); - return 1; -} - -int WINAPI QERApp_SetFaceInfo(int iface, _QERFaceData *pFaceData) -{ - if (iface>=g_ptrSelectedFaces.GetSize()) - { - Sys_FPrintf (SYS_ERR, "QERApp_SetFaceInfo: selected faces count exceeded\n"); - return 0; - } - if (!g_qeglobals.m_bBrushPrimitMode) - { - Sys_Printf("Warning: unexpected QERApp_SetFaceInfo out of brush primitive mode\n"); - return 0; - } - face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(iface)); - brush_t *selBrush = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(iface)); - //strcpy( selected_face->texdef.name, pFaceData->m_TextureName ); - selFace->texdef.SetName(pFaceData->m_TextureName); - VectorCopy( pFaceData->m_v1, selFace->planepts[0] ); - VectorCopy( pFaceData->m_v2, selFace->planepts[1] ); - VectorCopy( pFaceData->m_v3, selFace->planepts[2] ); - memcpy( &selFace->brushprimit_texdef, &pFaceData->brushprimit_texdef, sizeof(brushprimit_texdef_t) ); - Brush_Build( selBrush ); - Sys_UpdateWindows(W_ALL); - return 1; -} - -int WINAPI QERApp_ISelectedFace_GetTextureNumber(int iface) -{ - if (iface>=g_ptrSelectedFaces.GetSize()) - { - Sys_FPrintf (SYS_ERR, "QERApp_ISelectedFace_GetTextureNumber: selected faces count exceeded\n"); - return 0; - } - face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(iface)); - return selFace->d_texture->texture_number; -} - -void WINAPI QERApp_GetTextureSize (int iface, int Size[2]) -{ - if (iface>=g_ptrSelectedFaces.GetSize()) - { - Sys_FPrintf (SYS_ERR, "QERApp_GetTextureSize: selected faces count exceeded\n"); - return; - } - face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(iface)); - Size[0] = selFace->d_texture->width; - Size[1] = selFace->d_texture->height; -} +/* +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 +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// Quick interface hack for selected face interface +// this one really needs more work, but I'm in a hurry with TexTool + +#include "stdafx.h" + +int WINAPI QERApp_GetSelectedFaceCount() +{ + return g_ptrSelectedFaces.GetSize(); +} + +face_t* WINAPI QERApp_GetSelectedFace(int iface) +{ + if (iface>=g_ptrSelectedFaces.GetSize()) + { + Sys_FPrintf (SYS_ERR, "QERApp_GetFace: selected faces count exceeded\n"); + return NULL; + } + return reinterpret_cast(g_ptrSelectedFaces.GetAt(iface)); +} + +brush_t* WINAPI QERApp_GetSelectedFaceBrush(int iface) +{ + if (iface>=g_ptrSelectedFaceBrushes.GetSize()) + { + Sys_FPrintf (SYS_ERR, "QERApp_GetFace: selected faces count exceeded\n"); + return NULL; + } + return reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(iface)); +} + +// NOTE: we expect pWinding to have MAX_POINTS_ON_WINDING points ready for writing +int WINAPI QERApp_GetFaceInfo(int iface, _QERFaceData *pFaceData, winding_t *pWinding) +{ + int size; + + if (iface>=g_ptrSelectedFaces.GetSize()) + { + Sys_FPrintf (SYS_ERR, "QERApp_GetFaceInfo: selected faces count exceeded\n"); + return 0; + } + if (!g_qeglobals.m_bBrushPrimitMode) + { + Sys_Printf("Warning: unexpected QERApp_GetFaceInfo out of brush primitive mode\n"); + return 0; + } + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(iface)); + strcpy( pFaceData->m_TextureName, selFace->texdef.GetName() ); + VectorCopy( selFace->planepts[0], pFaceData->m_v1 ); + VectorCopy( selFace->planepts[1], pFaceData->m_v2 ); + VectorCopy( selFace->planepts[2], pFaceData->m_v3 ); + pFaceData->m_bBPrimit = true; + memcpy( &pFaceData->brushprimit_texdef, &selFace->brushprimit_texdef, sizeof(brushprimit_texdef_t) ); + size = (int)((winding_t *)0)->points[selFace->face_winding->numpoints]; + memcpy( pWinding, selFace->face_winding, size ); + return 1; +} + +int WINAPI QERApp_SetFaceInfo(int iface, _QERFaceData *pFaceData) +{ + if (iface>=g_ptrSelectedFaces.GetSize()) + { + Sys_FPrintf (SYS_ERR, "QERApp_SetFaceInfo: selected faces count exceeded\n"); + return 0; + } + if (!g_qeglobals.m_bBrushPrimitMode) + { + Sys_Printf("Warning: unexpected QERApp_SetFaceInfo out of brush primitive mode\n"); + return 0; + } + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(iface)); + brush_t *selBrush = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(iface)); + //strcpy( selected_face->texdef.name, pFaceData->m_TextureName ); + selFace->texdef.SetName(pFaceData->m_TextureName); + VectorCopy( pFaceData->m_v1, selFace->planepts[0] ); + VectorCopy( pFaceData->m_v2, selFace->planepts[1] ); + VectorCopy( pFaceData->m_v3, selFace->planepts[2] ); + memcpy( &selFace->brushprimit_texdef, &pFaceData->brushprimit_texdef, sizeof(brushprimit_texdef_t) ); + Brush_Build( selBrush ); + Sys_UpdateWindows(W_ALL); + return 1; +} + +int WINAPI QERApp_ISelectedFace_GetTextureNumber(int iface) +{ + if (iface>=g_ptrSelectedFaces.GetSize()) + { + Sys_FPrintf (SYS_ERR, "QERApp_ISelectedFace_GetTextureNumber: selected faces count exceeded\n"); + return 0; + } + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(iface)); + return selFace->d_texture->texture_number; +} + +void WINAPI QERApp_GetTextureSize (int iface, int Size[2]) +{ + if (iface>=g_ptrSelectedFaces.GetSize()) + { + Sys_FPrintf (SYS_ERR, "QERApp_GetTextureSize: selected faces count exceeded\n"); + return; + } + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(iface)); + Size[0] = selFace->d_texture->width; + Size[1] = selFace->d_texture->height; +} diff --git a/radiant/stdafx.cpp b/radiant/stdafx.cpp index c10d9ae3..4b7ac630 100644 --- a/radiant/stdafx.cpp +++ b/radiant/stdafx.cpp @@ -1,35 +1,35 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -// TTimo -// precompiled headers stuff -// NOTE: this file is useless on non-MSVC builds - -#include "stdafx.h" +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// TTimo +// precompiled headers stuff +// NOTE: this file is useless on non-MSVC builds + +#include "stdafx.h" diff --git a/radiant/surfacedialog.cpp b/radiant/surfacedialog.cpp index 31e65284..6df9e693 100644 --- a/radiant/surfacedialog.cpp +++ b/radiant/surfacedialog.cpp @@ -1,1134 +1,1134 @@ -/* -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 -*/ - -// -// Surface Dialog -// -// Leonardo Zide (leo@lokigames.com) -// - -#include -#include "stdafx.h" -#include "surfacedialog.h" - -SurfaceDlg g_dlgSurface; - -///////////////////////////////////////////////////////////////////////////// -// surface properties plugin - -/* -=================================================== - - SURFACE INSPECTOR - -=================================================== -*/ - -// the texdef to switch back to when the OnCancel is called -texdef_t g_old_texdef; -// when != NULL, this thing means the surface inspector is currently being displayed -// NOTE a boolean flag would have been more explicit, this is totally so ugly -GtkWidget* g_surfwin = NULL; -// turn on/off processing of the "changed" "value_changed" messages -// (need to turn off when we are feeding data in) -bool g_bListenChanged = true; -// the struct used to store the increments (saved in registry) -texdef_t *l_pIncrement = &g_qeglobals.d_savedinfo.m_SIIncrement; -// turn on/off listening of the update messages -bool g_bListenUpdate = true; - -#ifdef _DEBUG -// experimental stuff, work directly on BP -static void OnTest(GtkWidget *widget, gpointer data) -{ - if (!g_qeglobals.m_bBrushPrimitMode) - { - Sys_FPrintf(SYS_WRN, "BP mode required\n"); - return; - } - if (g_ptrSelectedFaces.GetSize() != 1) - { - Sys_FPrintf(SYS_WRN, "Expected single face selection\n"); - return; - } - brush_t *b = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(0)); - face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(0)); - // get the ST axis base for the face - vec3_t texS,texT; - ComputeAxisBase(selFace->plane.normal, texS, texT); - // find ST coordinates for the center of the face - float Os=0,Ot=0; - int i; - for (i=0; iface_winding->numpoints; i++) - { - Os += DotProduct(selFace->face_winding->points[i],texS); - Ot += DotProduct(selFace->face_winding->points[i],texT); - } - Os /= selFace->face_winding->numpoints; - Ot /= selFace->face_winding->numpoints; - brushprimit_texdef_t *pBP = &selFace->brushprimit_texdef; - - // (FIXME: initial version, before axis base change optimize) - - // we need to compute our BP matrix in this new axis base (O,texS,texT) - // the general case if BPO = M * BP * M^-1 - // where BPO is transformation expressed in (O,texS,texT) - // M is the axis base change from (origin,texS,texT) to (O,texS,texT) - // here we have a special case, M is a translation and it's inverse is easy - vec_t BPO[2][3]; - vec_t aux[2][3]; - vec_t m[2][3]; - memset(&m, 0, sizeof(vec_t)*6); - m[0][0] = 1; m[1][1] = 1; m[0][2] = -Os; m[1][2] = -Ot; - BPMatMul(m, pBP->coords, aux); - m[0][2] = Os; m[1][2] = Ot; // now M^-1 - BPMatMul(aux, m, BPO); - -#if 0 - // apply a scaling - // scale factors against S and T axis, we apply on top of the existing matrix - // <1 will decrease the texel/world resolution, >1 will increase - float sS = 1.025,sT = 1.025; - BPMatScale(BPO,sS,sT); -#endif -#if 0 - // apply a rotation - float theta = 5; - BPMatRotate(BPO,theta); -#endif -#if 0 - // read the scale - ConvertTexMatWithQTexture(BPO, selFace->d_texture, aux, NULL); - // reset the scale (normalize the matrix) - vec_t v1,v2; - v1 = sqrt(aux[0][0]*aux[0][0]+aux[1][0]*aux[1][0]); - v2 = sqrt(aux[0][1]*aux[0][1]+aux[1][1]*aux[1][1]); - // if reading the scale values, we have them here: - Sys_Printf("Current Scale: S: %g T: %g\n", v1, v2); - return; -#endif -#if 1 - // apply a given scale (on S and T) - ConvertTexMatWithQTexture(BPO, selFace->d_texture, aux, NULL); - // reset the scale (normalize the matrix) - vec_t v1,v2; - v1 = sqrt(aux[0][0]*aux[0][0]+aux[1][0]*aux[1][0]); - v2 = sqrt(aux[0][1]*aux[0][1]+aux[1][1]*aux[1][1]); - vec_t sS,sT; - // put the values for scale on S and T here: - sS = 1.2 / v1; - sT = 0.8 / v2; - aux[0][0] *= sS; aux[1][0] *= sS; - aux[0][1] *= sT; aux[1][1] *= sT; - ConvertTexMatWithQTexture(aux, NULL, BPO, selFace->d_texture); -#endif - - // now BPO must be expressed back in (origin,texS,texT) axis base BP = M^-1 * BPO * M - BPMatMul(m, BPO, aux); // m is M^-1 - m[0][2] = -Os; m[1][2] = -Ot; - BPMatMul(aux, m, pBP->coords); - - // now emit the coordinates on the winding - EmitBrushPrimitTextureCoordinates(selFace, selFace->face_winding); - Sys_UpdateWindows(W_CAMERA); -} - -/* - FIXME: try again, there must be a silly mistake in the formula expansion - // we need to compute our BP matrix in this new axis base (O,texS,texT) - // the general case is BPO = M * BP * M^-1 - // where BPO is transformation expressed in (O,texS,texT) - // M is the axis base change from (origin,texS,texT) to (O,texS,texT) - // here we have a special case, M is a translation and it's inverse is easy - // the M * BP * M^-1 formula can be expanded and simplified - vec_t BPO[2][3]; - memcpy(&BPO, &pBP->coords, sizeof(vec_t)*6); - BPO[0][2] = Os*(pBP->coords[0][0]-1.0) + Ot*pBP->coords[0][1] + pBP->coords[0][2]; - BPO[1][2] = Os*pBP->coords[1][0] + Ot*(pBP->coords[1][1]-1.0) + Ot*pBP->coords[1][2]; - - // apply a scaling - // scale factors against S and T axis, we apply on top of the existing matrix - // <1 will decrease the texel/world resolution, >1 will increase - float sS = 1.025,sT = 1.025; - BPMatScale(BPO,sS,sT); - - // now BPO must be expressed back in (origin,texS,texT) axis base BP = M^-1 * BPO * M - // same expanded formula as above - memcpy(&pBP->coords, &BPO, sizeof(vec_t)*6); - pBP->coords[0][2] = Os*(1.0-BPO[0][0]) - Ot*BPO[0][1] + BPO[0][2]; - pBP->coords[1][2] = -Os*BPO[1][0] + Ot*(1.0-BPO[1][1]) + BPO[1][2]; -*/ - -/* - // initial version, before axis base change optimize - - // we need to compute our BP matrix in this new axis base (O,texS,texT) - // the general case if BPO = M * BP * M^-1 - // where BPO is transformation expressed in (O,texS,texT) - // M is the axis base change from (origin,texS,texT) to (O,texS,texT) - // here we have a special case, M is a translation and it's inverse is easy - vec_t BPO[2][3]; - vec_t aux[2][3]; - vec_t m[2][3]; - memset(&m, 0, sizeof(vec_t)*6); - m[0][0] = 1; m[1][1] = 1; m[0][2] = -Os; m[1][2] = -Ot; - BPMatMul(m, pBP->coords, aux); - m[0][2] = Os; m[1][2] = Ot; // now M^-1 - BPMatMul(aux, m, BPO); - - // apply a scaling - // scale factors against S and T axis, we apply on top of the existing matrix - // <1 will decrease the texel/world resolution, >1 will increase - float sS = 1.025,sT = 1.025; - BPMatScale(BPO,sS,sT); - - // now BPO must be expressed back in (origin,texS,texT) axis base BP = M^-1 * BPO * M - BPMatMul(m, BPO, aux); // m is M^-1 - m[0][2] = -Os; m[1][2] = -Ot; - BPMatMul(aux, m, pBP->coords); -*/ -#endif - -static void OnDone(GtkWidget *widget, gpointer data) -{ - g_dlgSurface.GetTexMods(); - g_dlgSurface.HideDlg (); - Sys_UpdateWindows(W_ALL); -} - -// OnUpdate is called when something is changed in the dialog -// and must be reflected in the views. But it's not a change -// so important, so the system will try to undo our last do before applying the new changes -static void OnUpdate (GtkWidget *widget, gpointer data) -{ - if (!g_bListenChanged) - return; - - if (OnlyPatchesSelected()) - { - //++timo possible bug or misfeature in our gtk_MessageBox here.. -// gtk_MessageBox("The surface inspector doesn't work for patches, use the patch inspector instead (Shift+S)", "Surface Inspector", MB_OK ); - Sys_Printf("The surface inspector doesn't work for patches, use the patch inspector instead (Shift+S)\n"); - return; - } - - // avoid long delays on slow computers - while (gtk_events_pending ()) - gtk_main_iteration (); - - g_dlgSurface.GetTexMods (); - Sys_UpdateWindows(W_CAMERA); -} - -// reflect the current changes in the views, and make sure -// the changes are stored in the undo. -static void OnApply (GtkWidget *widget, gpointer data) -{ - if (!g_bListenChanged) - return; - - g_dlgSurface.GetTexMods (); - g_dlgSurface.m_nUndoId = 0; // that way we are sure we won't call undo - Sys_UpdateWindows(W_CAMERA); -} - -// we use OnTextureKey to detect when the user edits something in the texture widget -// in which case next 'Enter' will be interpreted as a OnApply instead of a OnDone -static gint OnTextureKey (GtkWidget* widget, GdkEventKey* event, gpointer data) -{ -#ifdef DBG_SI - Sys_Printf("OnTextureKey\n"); -#endif - if (event->keyval != GDK_Return) - g_dlgSurface.m_bEditingTextureWidget = true; - return FALSE; -} - -static void OnCancel(GtkWidget *widget, gpointer data) -{ - g_qeglobals.d_texturewin.texdef = g_old_texdef; - // cancel the last do if we own it - if (g_dlgSurface.m_nUndoId == Undo_GetUndoId()) - { -#ifdef DBG_SI - Sys_Printf("OnCancel calling Undo_Undo\n"); -#endif - g_bListenUpdate = false; - Undo_Undo(); - g_bListenUpdate = true; - g_dlgSurface.m_nUndoId = 0; - } - g_dlgSurface.HideDlg (); -} - -static gint OnDialogKey (GtkWidget* widget, GdkEventKey* event, gpointer data) -{ - if (g_surfwin) - { - if (event->keyval == GDK_Return) - { - if (g_dlgSurface.m_bEditingTextureWidget) - { - OnApply (NULL, NULL); - g_dlgSurface.m_bEditingTextureWidget = false; - } - else - { - OnDone (NULL, NULL); - } - return TRUE; - } - if (event->keyval == GDK_Escape) - { - OnCancel (NULL, NULL); - return TRUE; - } - } - return FALSE; -} - -// the widget can be one of hshift, vshift, hscale, vscale, rotate -// we use the g_bListenChanged flag to ignore when changing stuff ourselves -static void OnIncrementChanged(GtkWidget *widget, gpointer data) -{ - if (!g_bListenChanged) - return; - -#ifdef DBG_SI - Sys_Printf("OnIncrementChanged\n"); -#endif - - gfloat val = 0; - sscanf( gtk_entry_get_text (GTK_ENTRY (widget)), "%g", &val); - // now push it into the appropriate spin button - GtkAdjustment * adjust; - if (widget == g_dlgSurface.GetDlgWidget ("hshift_inc")) - { - l_pIncrement->shift[0] = val; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (g_dlgSurface.GetDlgWidget ("hshift"))); - adjust->step_increment = l_pIncrement->shift[0]; - } - else if (widget == g_dlgSurface.GetDlgWidget ("vshift_inc")) - { - l_pIncrement->shift[1] = val; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (g_dlgSurface.GetDlgWidget ("vshift"))); - adjust->step_increment = l_pIncrement->shift[1]; - } - else if (widget == g_dlgSurface.GetDlgWidget ("hscale_inc")) - { - l_pIncrement->scale[0] = val; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (g_dlgSurface.GetDlgWidget ("hscale"))); - adjust->step_increment = l_pIncrement->scale[0]; - } - else if (widget == g_dlgSurface.GetDlgWidget ("vscale_inc")) - { - l_pIncrement->scale[1] = val; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (g_dlgSurface.GetDlgWidget ("vscale"))); - adjust->step_increment = l_pIncrement->scale[1]; - } - else if (widget == g_dlgSurface.GetDlgWidget ("rotate_inc")) - { - l_pIncrement->rotate = val; - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (g_dlgSurface.GetDlgWidget ("rotate"))); - adjust->step_increment = l_pIncrement->rotate; - } -} - -// make the shift increments match the grid settings -// the objective being that the shift+arrows shortcuts move the texture by the corresponding grid size -// this depends on a scale value if you have selected a particular texture on which you want it to work: -// we move the textures in pixels, not world units. (i.e. increment values are in pixel) -// depending on the texture scale it doesn't take the same amount of pixels to move of g_qeglobals.d_gridsize -// increment * scale = gridsize -// hscale and vscale are optional parameters, if they are zero they will be set to the default scale -// NOTE: the default scale depends if you are using BP mode or regular. -// For regular it's 0.5f (128 pixels cover 64 world units), for BP it's simply 1.0f -// see fenris #2810 -void DoSnapTToGrid(float hscale, float vscale) -{ - if (hscale == 0.0f) - { - (g_qeglobals.m_bBrushPrimitMode) ? hscale = 1.0f : hscale = 0.5f; - } - if (vscale == 0.0f) - { - (g_qeglobals.m_bBrushPrimitMode) ? vscale = 1.0f : vscale = 0.5f; - } -#ifdef _DEBUG - Sys_Printf ("DoSnapTToGrid: hscale %g vscale %g\n", hscale, vscale); -#endif - l_pIncrement->shift[0] = (int) ( (float)g_qeglobals.d_gridsize / hscale ); - l_pIncrement->shift[1] = (int) ( (float)g_qeglobals.d_gridsize / vscale ); - // now some update work - // FIXME: doesn't look good here, seems to be called several times - g_dlgSurface.SetTexMods(); -} - -// make the shift increments match the grid settings -// the objective being that the shift+arrows shortcuts move the texture by the corresponding grid size -// this depends on the current texture scale used? -// we move the textures in pixels, not world units. (i.e. increment values are in pixel) -// depending on the texture scale it doesn't take the same amount of pixels to move of g_qeglobals.d_gridsize -// increment * scale = gridsize -static void OnBtnMatchGrid(GtkWidget *widget, gpointer data) -{ - float hscale, vscale; - hscale = gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (g_dlgSurface.GetDlgWidget ("hscale"))); - vscale = gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (g_dlgSurface.GetDlgWidget ("vscale"))); - if (hscale == 0.0f || vscale == 0.0f) - { - Sys_Printf("ERROR: unexpected scale == 0.0f\n"); - return; - } - DoSnapTToGrid (hscale, vscale); -} - -void UpdateSurfaceDialog() -{ - if (!g_bListenUpdate) - return; - - g_SurfaceTable.m_pfnUpdateSurfaceDialog(); -} - -// DoSurface will always try to show the surface inspector -// or update it because something new has been selected -void DoSurface (void) -{ -#ifdef DBG_SI - Sys_Printf("DoSurface\n"); -#endif - g_SurfaceTable.m_pfnDoSurface(); - return; -} - -void ToggleSurface() -{ - g_SurfaceTable.m_pfnToggleSurface(); - return; -} - -// NOTE: will raise and show the Surface inspector and exec fit for patches and brushes -void SurfaceDlgFitAll() -{ - g_SurfaceTable.m_pfnSurfaceDlgFitAll(); - return; -} - -static void OnBtnPatchdetails(GtkWidget *widget, gpointer data) -{ - Patch_NaturalizeSelected(true); - Sys_UpdateWindows(W_ALL); -} - -static void OnBtnPatchnatural(GtkWidget *widget, gpointer data) -{ - Patch_NaturalizeSelected(); - Sys_UpdateWindows(W_ALL); -} - -static void OnBtnPatchreset(GtkWidget *widget, gpointer data) -{ - float fx, fy; - - if (DoTextureLayout (&fx, &fy) == IDOK) - Patch_ResetTexturing (fx, fy); - Sys_UpdateWindows(W_ALL); -} - -static void OnBtnPatchFit(GtkWidget *widget, gpointer data) -{ - Patch_ResetTexturing(1.0, 1.0); - Sys_UpdateWindows(W_ALL); -} - -static void OnBtnAxial(GtkWidget *widget, gpointer data) -{ - Select_SetTexture (&g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef, true); - g_dlgSurface.SetTexMods(); - Sys_UpdateWindows(W_ALL); -} - -static void OnBtnFaceFit(GtkWidget *widget, gpointer data) -{ - g_dlgSurface.UpdateData(TRUE); - if (g_ptrSelectedFaces.GetSize() == 0) - { - brush_t *b; - for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - { - for (face_t* pFace = b->brush_faces; pFace; pFace = pFace->next) - { - g_ptrSelectedFaces.Add(pFace); - g_ptrSelectedFaceBrushes.Add(b); - } - } - Select_FitTexture(g_dlgSurface.m_nHeight, g_dlgSurface.m_nWidth); - g_dlgSurface.SetTexMods(); - g_ptrSelectedFaces.RemoveAll(); - } - else - { - Select_FitTexture(g_dlgSurface.m_nHeight, g_dlgSurface.m_nWidth); - g_dlgSurface.SetTexMods(); - } - Sys_UpdateWindows(W_ALL); -} - -// ============================================================================= -// SurfaceDialog class - -SurfaceDlg::SurfaceDlg () -{ - m_nHeight = 1; - m_nWidth = 1; - m_nUndoId = 0; -} - -void SurfaceDlg::ShowDlg() -{ - Dialog::ShowDlg(); - if(GetWidget() == NULL) - Create(); - g_surfwin = GetWidget (); -} -void SurfaceDlg::HideDlg() -{ - g_surfwin = NULL; - Dialog::HideDlg(); -} - -GtkWidget* SurfaceDlg::GetWidget() -{ - return g_SurfaceTable.m_pfnGet_SI_Module_Widget(); -} - -// set default values for increments (shift scale and rot) -// this is called by the prefs code if can't find the values -void SurfaceDlg::InitDefaultIncrement(texdef_t *tex) -{ - tex->SetName("foo"); - tex->shift[0] = 8; - tex->shift[1] = 8; - tex->scale[0] = 0.25; - tex->scale[1] = 0.25; - tex->rotate = 10; -} - -void SurfaceDlg::BuildDialog () -{ - GtkWidget *dlg, *vbox, *hbox2, *frame, *table, *label; - GtkWidget *button, *entry, *spin; - - dlg = m_pWidget; - - load_window_pos (dlg, g_PrefsDlg.mWindowInfo.posSurfaceWnd); - - gtk_window_set_title (GTK_WINDOW (dlg), "Surface inspector"); - //g_signal_connect (G_OBJECT (dlg), "delete_event", G_CALLBACK (OnCancel), NULL); - // we catch 'Enter' and interpret is as OnDone - gtk_signal_connect (GTK_OBJECT (dlg), "key_press_event", GTK_SIGNAL_FUNC (OnDialogKey), NULL); - gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pParentWnd->m_pWidget)); - - // replaced by only the vbox: - vbox = gtk_vbox_new (FALSE, 5); - gtk_widget_show (vbox); - gtk_container_add (GTK_CONTAINER (dlg), vbox); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - - hbox2 = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox2); - gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, TRUE, 0); - - label = gtk_label_new ("Texture"); - gtk_widget_show (label); - gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 0); - - entry = gtk_entry_new (); - gtk_signal_connect (GTK_OBJECT (entry), "key_press_event", GTK_SIGNAL_FUNC (OnTextureKey), NULL); - gtk_widget_show (entry); - gtk_box_pack_start (GTK_BOX (hbox2), entry, TRUE, TRUE, 0); - g_object_set_data (G_OBJECT (m_pWidget), "texture", entry); - -// table = gtk_table_new (5, 4, FALSE); - table = gtk_table_new (6, 4, FALSE); - gtk_widget_show (table); - gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - - label = gtk_label_new ("Horizontal shift"); - gtk_widget_show (label); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, -8192, 8192, 2, 8, 8)), 0, 0); - g_object_set_data (G_OBJECT (dlg), "hshift", spin); - gtk_signal_connect (GTK_OBJECT (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin))), "value_changed", - GTK_SIGNAL_FUNC (OnUpdate), NULL); - gtk_widget_show (spin); - gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (spin, 60, -2); - - label = gtk_label_new ("Step"); - gtk_widget_show (label); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0); - gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - entry = gtk_entry_new (); - g_object_set_data (G_OBJECT (dlg), "hshift_inc", entry); - gtk_signal_connect (GTK_OBJECT (entry), "changed", - GTK_SIGNAL_FUNC (OnIncrementChanged), NULL); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - - label = gtk_label_new ("Vertical shift"); - gtk_widget_show (label); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, -8192, 8192, 2, 8, 8)), 0, 0); - g_object_set_data (G_OBJECT (dlg), "vshift", spin); - gtk_signal_connect (GTK_OBJECT (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin))), "value_changed", - GTK_SIGNAL_FUNC (OnUpdate), NULL); - gtk_widget_show (spin); - gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (spin, 60, -2); - - label = gtk_label_new ("Step"); - gtk_widget_show (label); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0); - gtk_table_attach (GTK_TABLE (table), label, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - entry = gtk_entry_new (); - g_object_set_data (G_OBJECT (dlg), "vshift_inc", entry); - gtk_signal_connect (GTK_OBJECT (entry), "changed", - GTK_SIGNAL_FUNC (OnIncrementChanged), NULL); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - - label = gtk_label_new ("Horizontal stretch"); - gtk_widget_show (label); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, -1000, 1000, 1, 10, 10)), 0, 0); - g_object_set_data (G_OBJECT (dlg), "hscale", spin); - gtk_signal_connect (GTK_OBJECT (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin))), "value_changed", - GTK_SIGNAL_FUNC (OnUpdate), NULL); - gtk_widget_show (spin); - gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (spin, 60, -2); - - label = gtk_label_new ("Step"); - gtk_widget_show (label); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0); - gtk_table_attach (GTK_TABLE (table), label, 2, 3, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 2, 3); - - entry = gtk_entry_new (); - g_object_set_data (G_OBJECT (dlg), "hscale_inc", entry); - gtk_signal_connect (GTK_OBJECT (entry), "changed", - GTK_SIGNAL_FUNC (OnIncrementChanged), NULL); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 2, 3); - gtk_widget_set_usize (entry, 50, -2); - - label = gtk_label_new ("Vertical stretch"); - gtk_widget_show (label); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, -1000, 1000, 1, 10, 10)), 0, 0); - g_object_set_data (G_OBJECT (dlg), "vscale", spin); - gtk_signal_connect (GTK_OBJECT (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin))), "value_changed", - GTK_SIGNAL_FUNC (OnUpdate), NULL); - gtk_widget_show (spin); - gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 3, 4, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (spin, 60, -2); - - label = gtk_label_new ("Step"); - gtk_widget_show (label); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0); - gtk_table_attach (GTK_TABLE (table), label, 2, 3, 3, 4, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - entry = gtk_entry_new (); - g_object_set_data (G_OBJECT (dlg), "vscale_inc", entry); - gtk_signal_connect (GTK_OBJECT (entry), "changed", - GTK_SIGNAL_FUNC (OnIncrementChanged), NULL); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 3, 4, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - - label = gtk_label_new ("Rotate"); - gtk_widget_show (label); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 4, 5, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, -360, 360, 1, 10, 10)), 1, 0); - g_object_set_data (G_OBJECT (dlg), "rotate", spin); - gtk_signal_connect (GTK_OBJECT (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin))), "value_changed", - GTK_SIGNAL_FUNC (OnUpdate), NULL); - gtk_widget_show (spin); - gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 4, 5, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (spin, 60, -2); - gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spin), TRUE); - - label = gtk_label_new ("Step"); - gtk_widget_show (label); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0); - gtk_table_attach (GTK_TABLE (table), label, 2, 3, 4, 5, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - entry = gtk_entry_new (); - g_object_set_data (G_OBJECT (dlg), "rotate_inc", entry); - gtk_signal_connect (GTK_OBJECT (entry), "changed", - GTK_SIGNAL_FUNC (OnIncrementChanged), NULL); - gtk_widget_show (entry); - gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 4, 5, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (entry, 50, -2); - - // match grid button - button = gtk_button_new_with_label ("Match Grid"); - gtk_widget_show (button); - gtk_table_attach (GTK_TABLE (table), button, 2, 4, 5, 6, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (OnBtnMatchGrid), NULL); - - frame = gtk_frame_new ("Texturing"); - gtk_widget_show (frame); - gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); - - table = gtk_table_new (4, 4, FALSE); - gtk_widget_show (table); - gtk_container_add (GTK_CONTAINER (frame), table); - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - gtk_container_set_border_width (GTK_CONTAINER (table), 5); - - label = gtk_label_new ("Brush"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - label = gtk_label_new ("Patch"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - label = gtk_label_new ("Width"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - label = gtk_label_new ("Height"); - gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 3, 4, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - button = gtk_button_new_with_label ("Axial"); - gtk_widget_show (button); - gtk_table_attach (GTK_TABLE (table), button, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (OnBtnAxial), NULL); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Fit"); - gtk_widget_show (button); - gtk_table_attach (GTK_TABLE (table), button, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (OnBtnFaceFit), NULL); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("CAP"); - gtk_widget_show (button); - gtk_table_attach (GTK_TABLE (table), button, 0, 1, 3, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (OnBtnPatchdetails), NULL); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Set..."); - gtk_widget_show (button); - gtk_table_attach (GTK_TABLE (table), button, 1, 2, 3, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (OnBtnPatchreset), NULL); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Natural"); - gtk_widget_show (button); - gtk_table_attach (GTK_TABLE (table), button, 2, 3, 3, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (OnBtnPatchnatural), NULL); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Fit"); - gtk_widget_show (button); - gtk_table_attach (GTK_TABLE (table), button, 3, 4, 3, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (OnBtnPatchFit), NULL); - gtk_widget_set_usize (button, 60, -2); - - spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (1, 1, 32, 1, 10, 10)), 1, 0); - gtk_widget_show (spin); - gtk_table_attach (GTK_TABLE (table), spin, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (spin, 60, -2); - AddDialogData (spin, &m_nWidth, DLG_SPIN_INT); - - spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (1, 1, 32, 1, 10, 10)), 1, 0); - gtk_widget_show (spin); - gtk_table_attach (GTK_TABLE (table), spin, 3, 4, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_widget_set_usize (spin, 60, -2); - AddDialogData (spin, &m_nHeight, DLG_SPIN_INT); - - hbox2 = gtk_hbox_new (FALSE, 5); - gtk_widget_show (hbox2); - gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, TRUE, 0); - - button = gtk_button_new_with_label ("Done"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (OnDone), NULL); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Apply"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (OnApply), NULL); - gtk_widget_set_usize (button, 60, -2); - - button = gtk_button_new_with_label ("Cancel"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (OnCancel), NULL); - gtk_widget_set_usize (button, 60, -2); - - // that's a bit of trashy stuff from Textool-v2 branch -#ifdef _DEBUG - // FIXME: testing only, scaling in BP mode - button = gtk_button_new_with_label ("Test"); - gtk_widget_show (button); - gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, FALSE, 0); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (OnTest), NULL); - gtk_widget_set_usize (button, 60, -2); -#endif - - // Initialize - SetTexMods (); -} - -/* -============== -SetTexMods - -Set the fields to the current texdef (i.e. map/texdef -> dialog widgets) -if faces selected (instead of brushes) -> will read this face texdef, else current texdef -if only patches selected, will read the patch texdef -=============== -*/ - -void SurfaceDlg::SetTexMods() -{ - texdef_t *pt; - brushprimit_texdef_t *bpt; - // local copy if a width=2 height=2 qtetxture_t is needed - brushprimit_texdef_t local_bp; - -#ifdef DBG_SI - Sys_Printf("SurfaceDlg::SetTexMods\n"); -#endif - - if (!g_surfwin) - return; - - if (g_ptrSelectedFaces.GetSize() > 0) - { - face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(0)); - pt = &selFace->texdef; - if (g_qeglobals.m_bBrushPrimitMode) - { - // compute a texture matrix related to the default matrix width=2 height=2 - ConvertTexMatWithQTexture( &selFace->brushprimit_texdef, selFace->d_texture, &local_bp, NULL ); - bpt = &local_bp; - } - } - else - { - pt = &g_qeglobals.d_texturewin.texdef; - if (g_qeglobals.m_bBrushPrimitMode) - { - bpt = &g_qeglobals.d_texturewin.brushprimit_texdef; - } - } - // brush primitive mode : compute fake shift scale rot representation - if (g_qeglobals.m_bBrushPrimitMode) - TexMatToFakeTexCoords( bpt->coords, m_shift, &m_rotate, m_scale ); - - g_bListenChanged = false; - - if(strncmp(pt->GetName(), "textures/", 9) != 0) - pt->SetName(SHADER_NOT_FOUND); - gtk_entry_set_text (GTK_ENTRY (GetDlgWidget ("texture")), pt->GetName()+9); - - GtkSpinButton *spin; - spin = GTK_SPIN_BUTTON (GetDlgWidget ("hshift")); - gtk_spin_button_set_digits (spin, 2); - if (g_qeglobals.m_bBrushPrimitMode) - gtk_spin_button_set_value (spin, m_shift[0]); - else - gtk_spin_button_set_value (spin, pt->shift[0]); - GtkAdjustment *adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->shift[0]; - char buf[10]; // got into snprintf paranoia after BoundChecker detected a stack overrun -#ifdef _WIN32 - // TTimo: THIS IS UGLY -#define snprintf _snprintf -#endif - snprintf (buf, 10, "%g", l_pIncrement->shift[0]); - gtk_entry_set_text (GTK_ENTRY (GetDlgWidget ("hshift_inc")), buf); - - spin = GTK_SPIN_BUTTON (GetDlgWidget ("vshift")); - gtk_spin_button_set_digits (spin, 2); - if (g_qeglobals.m_bBrushPrimitMode) - gtk_spin_button_set_value (spin, m_shift[1]); - else - gtk_spin_button_set_value (spin, pt->shift[1]); - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->shift[1]; - snprintf (buf, 10, "%g", l_pIncrement->shift[1]); - gtk_entry_set_text (GTK_ENTRY (GetDlgWidget ("vshift_inc")), buf); - - spin = GTK_SPIN_BUTTON (GetDlgWidget ("hscale")); - gtk_spin_button_set_digits (spin, 5); - gtk_spin_button_set_value (spin, g_qeglobals.m_bBrushPrimitMode ? m_scale[0] : pt->scale[0]); - - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->scale[0]; - snprintf (buf, 10, "%g", l_pIncrement->scale[0]); - gtk_entry_set_text (GTK_ENTRY (GetDlgWidget ("hscale_inc")), buf); - - spin = GTK_SPIN_BUTTON (GetDlgWidget ("vscale")); - gtk_spin_button_set_digits (spin, 5); - gtk_spin_button_set_value (spin, g_qeglobals.m_bBrushPrimitMode ? m_scale[1] : pt->scale[1]); - - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->scale[1]; - snprintf (buf, 10, "%g", l_pIncrement->scale[1]); - gtk_entry_set_text (GTK_ENTRY (GetDlgWidget ("vscale_inc")), buf); - - //++timo compute BProtate as int .. - spin = GTK_SPIN_BUTTON (GetDlgWidget ("rotate")); - gtk_spin_button_set_digits (spin, 2); - gtk_spin_button_set_value (spin, g_qeglobals.m_bBrushPrimitMode ? m_rotate : pt->rotate); - - adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); - adjust->step_increment = l_pIncrement->rotate; - snprintf (buf, 10, "%g", l_pIncrement->rotate); - gtk_entry_set_text (GTK_ENTRY (GetDlgWidget ("rotate_inc")), buf); - - g_bListenChanged = true; - - // undo tricks: set the undo id to zero so we don't attempt to undo something that does not belong to us - m_nUndoId = 0; - // store the current texdef as our escape route if user hits OnCancel - g_old_texdef = g_qeglobals.d_texturewin.texdef; - // reset the Enter key behaviour flag - m_bEditingTextureWidget = false; -} - -/* -============== -GetTexMods - -Reads the fields to get the current texdef (i.e. widgets -> MAP) -in brush primitive mode, grab the fake shift scale rot and compute a new texture matrix -=============== -*/ -void SurfaceDlg::GetTexMods() -{ - char buffer[1024]; - texdef_t *pt; - -#ifdef DBG_SI - Sys_Printf("SurfaceDlg::GetTexMods\n"); -#endif - - if (g_ptrSelectedFaces.GetSize() > 0) - { - //++timo just a test, we disable the undo when working on selected faces - m_nUndoId=0; - face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(0)); - g_qeglobals.d_texturewin.texdef = selFace->texdef; -#ifdef DBG_SI - Sys_Printf("g_qeglobals.d_texturewin.texdef = selFace->texdef\n"); -#endif - } -// else -// { - pt = &g_qeglobals.d_texturewin.texdef; -#ifdef DBG_SI - Sys_Printf("pt = &g_qeglobals.d_texturewin.texdef\n"); -#endif -// } - - const char* text = gtk_entry_get_text (GTK_ENTRY (GetDlgWidget ("texture"))); - -#ifdef DBG_SI - Sys_Printf("pt->SetName(%s)\n", text ); -#endif - - // TTimo: detect and refuse invalid texture names (at least the ones with spaces) - if (text[0] <= ' ' || strchr(text, ' ')) - { - Sys_FPrintf(SYS_WRN, "WARNING: spaces in shader names are not allowed, ignoring '%s'\n", text); - pt->SetName(SHADER_NOT_FOUND); - gtk_entry_set_text (GTK_ENTRY (GetDlgWidget ("texture")), pt->GetName()); - } - else - { - strcpy(buffer, "textures/"); - strcpy(buffer+9, text); - pt->SetName(buffer); - } - - - (g_qeglobals.m_bBrushPrimitMode ? m_shift[0] : pt->shift[0]) = - gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (GetDlgWidget ("hshift"))); - (g_qeglobals.m_bBrushPrimitMode ? m_shift[1] : pt->shift[1]) = - gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (GetDlgWidget ("vshift"))); - (g_qeglobals.m_bBrushPrimitMode ? m_scale[0] : pt->scale[0]) = - gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (GetDlgWidget ("hscale"))); - (g_qeglobals.m_bBrushPrimitMode ? m_scale[1] : pt->scale[1]) = - gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (GetDlgWidget ("vscale"))); - (g_qeglobals.m_bBrushPrimitMode ? m_rotate : pt->rotate) = - gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (GetDlgWidget ("rotate"))); - - // a local copy of the texture matrix, given for a qtexture_t with width=2 height=2 - brushprimit_texdef_t local_bp; - brushprimit_texdef_t *bpt; - if (g_qeglobals.m_bBrushPrimitMode) - { - face_t *selFace = NULL; - if (g_ptrSelectedFaces.GetSize() > 0) - { - selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(0)); - bpt = &selFace->brushprimit_texdef; - } - else - { - bpt = &g_qeglobals.d_texturewin.brushprimit_texdef; - } - // compute texture matrix - // the matrix returned must be understood as a qtexture_t with width=2 height=2 - FakeTexCoordsToTexMat( m_shift, m_rotate, m_scale, local_bp.coords ); - // copy the texture matrix in the global struct - // fit the qtexture if we have a face selected, otherwise g_qeglobals.d_texturewin.brushprimit_texdef uses the basic qtexture_t with width=2 height=2 - - ConvertTexMatWithQTexture( &local_bp, NULL, bpt, ( (selFace) ? selFace->d_texture : NULL ) ); - } - // we are gonna do stuff, if we own the last do we undo it first - if (m_nUndoId != 0) - { - // check the do we're about to undo is the one we pushed earlier - if (m_nUndoId == Undo_GetUndoId()) - { -#ifdef DBG_SI - Sys_Printf("GetTexMods calling Undo_Undo (silent)\n"); -#endif - g_bListenUpdate=false; - Undo_Undo(true); - g_bListenUpdate=true; - } - } - Select_SetTexture(pt,&local_bp); - m_nUndoId = Undo_GetUndoId(); -} - -void SurfaceDlg::FitAll() -{ - OnBtnFaceFit(NULL, NULL); - OnBtnPatchFit(NULL, NULL); -} +/* +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 +*/ + +// +// Surface Dialog +// +// Leonardo Zide (leo@lokigames.com) +// + +#include +#include "stdafx.h" +#include "surfacedialog.h" + +SurfaceDlg g_dlgSurface; + +///////////////////////////////////////////////////////////////////////////// +// surface properties plugin + +/* +=================================================== + + SURFACE INSPECTOR + +=================================================== +*/ + +// the texdef to switch back to when the OnCancel is called +texdef_t g_old_texdef; +// when != NULL, this thing means the surface inspector is currently being displayed +// NOTE a boolean flag would have been more explicit, this is totally so ugly +GtkWidget* g_surfwin = NULL; +// turn on/off processing of the "changed" "value_changed" messages +// (need to turn off when we are feeding data in) +bool g_bListenChanged = true; +// the struct used to store the increments (saved in registry) +texdef_t *l_pIncrement = &g_qeglobals.d_savedinfo.m_SIIncrement; +// turn on/off listening of the update messages +bool g_bListenUpdate = true; + +#ifdef _DEBUG +// experimental stuff, work directly on BP +static void OnTest(GtkWidget *widget, gpointer data) +{ + if (!g_qeglobals.m_bBrushPrimitMode) + { + Sys_FPrintf(SYS_WRN, "BP mode required\n"); + return; + } + if (g_ptrSelectedFaces.GetSize() != 1) + { + Sys_FPrintf(SYS_WRN, "Expected single face selection\n"); + return; + } + brush_t *b = reinterpret_cast(g_ptrSelectedFaceBrushes.GetAt(0)); + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(0)); + // get the ST axis base for the face + vec3_t texS,texT; + ComputeAxisBase(selFace->plane.normal, texS, texT); + // find ST coordinates for the center of the face + float Os=0,Ot=0; + int i; + for (i=0; iface_winding->numpoints; i++) + { + Os += DotProduct(selFace->face_winding->points[i],texS); + Ot += DotProduct(selFace->face_winding->points[i],texT); + } + Os /= selFace->face_winding->numpoints; + Ot /= selFace->face_winding->numpoints; + brushprimit_texdef_t *pBP = &selFace->brushprimit_texdef; + + // (FIXME: initial version, before axis base change optimize) + + // we need to compute our BP matrix in this new axis base (O,texS,texT) + // the general case if BPO = M * BP * M^-1 + // where BPO is transformation expressed in (O,texS,texT) + // M is the axis base change from (origin,texS,texT) to (O,texS,texT) + // here we have a special case, M is a translation and it's inverse is easy + vec_t BPO[2][3]; + vec_t aux[2][3]; + vec_t m[2][3]; + memset(&m, 0, sizeof(vec_t)*6); + m[0][0] = 1; m[1][1] = 1; m[0][2] = -Os; m[1][2] = -Ot; + BPMatMul(m, pBP->coords, aux); + m[0][2] = Os; m[1][2] = Ot; // now M^-1 + BPMatMul(aux, m, BPO); + +#if 0 + // apply a scaling + // scale factors against S and T axis, we apply on top of the existing matrix + // <1 will decrease the texel/world resolution, >1 will increase + float sS = 1.025,sT = 1.025; + BPMatScale(BPO,sS,sT); +#endif +#if 0 + // apply a rotation + float theta = 5; + BPMatRotate(BPO,theta); +#endif +#if 0 + // read the scale + ConvertTexMatWithQTexture(BPO, selFace->d_texture, aux, NULL); + // reset the scale (normalize the matrix) + vec_t v1,v2; + v1 = sqrt(aux[0][0]*aux[0][0]+aux[1][0]*aux[1][0]); + v2 = sqrt(aux[0][1]*aux[0][1]+aux[1][1]*aux[1][1]); + // if reading the scale values, we have them here: + Sys_Printf("Current Scale: S: %g T: %g\n", v1, v2); + return; +#endif +#if 1 + // apply a given scale (on S and T) + ConvertTexMatWithQTexture(BPO, selFace->d_texture, aux, NULL); + // reset the scale (normalize the matrix) + vec_t v1,v2; + v1 = sqrt(aux[0][0]*aux[0][0]+aux[1][0]*aux[1][0]); + v2 = sqrt(aux[0][1]*aux[0][1]+aux[1][1]*aux[1][1]); + vec_t sS,sT; + // put the values for scale on S and T here: + sS = 1.2 / v1; + sT = 0.8 / v2; + aux[0][0] *= sS; aux[1][0] *= sS; + aux[0][1] *= sT; aux[1][1] *= sT; + ConvertTexMatWithQTexture(aux, NULL, BPO, selFace->d_texture); +#endif + + // now BPO must be expressed back in (origin,texS,texT) axis base BP = M^-1 * BPO * M + BPMatMul(m, BPO, aux); // m is M^-1 + m[0][2] = -Os; m[1][2] = -Ot; + BPMatMul(aux, m, pBP->coords); + + // now emit the coordinates on the winding + EmitBrushPrimitTextureCoordinates(selFace, selFace->face_winding); + Sys_UpdateWindows(W_CAMERA); +} + +/* + FIXME: try again, there must be a silly mistake in the formula expansion + // we need to compute our BP matrix in this new axis base (O,texS,texT) + // the general case is BPO = M * BP * M^-1 + // where BPO is transformation expressed in (O,texS,texT) + // M is the axis base change from (origin,texS,texT) to (O,texS,texT) + // here we have a special case, M is a translation and it's inverse is easy + // the M * BP * M^-1 formula can be expanded and simplified + vec_t BPO[2][3]; + memcpy(&BPO, &pBP->coords, sizeof(vec_t)*6); + BPO[0][2] = Os*(pBP->coords[0][0]-1.0) + Ot*pBP->coords[0][1] + pBP->coords[0][2]; + BPO[1][2] = Os*pBP->coords[1][0] + Ot*(pBP->coords[1][1]-1.0) + Ot*pBP->coords[1][2]; + + // apply a scaling + // scale factors against S and T axis, we apply on top of the existing matrix + // <1 will decrease the texel/world resolution, >1 will increase + float sS = 1.025,sT = 1.025; + BPMatScale(BPO,sS,sT); + + // now BPO must be expressed back in (origin,texS,texT) axis base BP = M^-1 * BPO * M + // same expanded formula as above + memcpy(&pBP->coords, &BPO, sizeof(vec_t)*6); + pBP->coords[0][2] = Os*(1.0-BPO[0][0]) - Ot*BPO[0][1] + BPO[0][2]; + pBP->coords[1][2] = -Os*BPO[1][0] + Ot*(1.0-BPO[1][1]) + BPO[1][2]; +*/ + +/* + // initial version, before axis base change optimize + + // we need to compute our BP matrix in this new axis base (O,texS,texT) + // the general case if BPO = M * BP * M^-1 + // where BPO is transformation expressed in (O,texS,texT) + // M is the axis base change from (origin,texS,texT) to (O,texS,texT) + // here we have a special case, M is a translation and it's inverse is easy + vec_t BPO[2][3]; + vec_t aux[2][3]; + vec_t m[2][3]; + memset(&m, 0, sizeof(vec_t)*6); + m[0][0] = 1; m[1][1] = 1; m[0][2] = -Os; m[1][2] = -Ot; + BPMatMul(m, pBP->coords, aux); + m[0][2] = Os; m[1][2] = Ot; // now M^-1 + BPMatMul(aux, m, BPO); + + // apply a scaling + // scale factors against S and T axis, we apply on top of the existing matrix + // <1 will decrease the texel/world resolution, >1 will increase + float sS = 1.025,sT = 1.025; + BPMatScale(BPO,sS,sT); + + // now BPO must be expressed back in (origin,texS,texT) axis base BP = M^-1 * BPO * M + BPMatMul(m, BPO, aux); // m is M^-1 + m[0][2] = -Os; m[1][2] = -Ot; + BPMatMul(aux, m, pBP->coords); +*/ +#endif + +static void OnDone(GtkWidget *widget, gpointer data) +{ + g_dlgSurface.GetTexMods(); + g_dlgSurface.HideDlg (); + Sys_UpdateWindows(W_ALL); +} + +// OnUpdate is called when something is changed in the dialog +// and must be reflected in the views. But it's not a change +// so important, so the system will try to undo our last do before applying the new changes +static void OnUpdate (GtkWidget *widget, gpointer data) +{ + if (!g_bListenChanged) + return; + + if (OnlyPatchesSelected()) + { + //++timo possible bug or misfeature in our gtk_MessageBox here.. +// gtk_MessageBox("The surface inspector doesn't work for patches, use the patch inspector instead (Shift+S)", "Surface Inspector", MB_OK ); + Sys_Printf("The surface inspector doesn't work for patches, use the patch inspector instead (Shift+S)\n"); + return; + } + + // avoid long delays on slow computers + while (gtk_events_pending ()) + gtk_main_iteration (); + + g_dlgSurface.GetTexMods (); + Sys_UpdateWindows(W_CAMERA); +} + +// reflect the current changes in the views, and make sure +// the changes are stored in the undo. +static void OnApply (GtkWidget *widget, gpointer data) +{ + if (!g_bListenChanged) + return; + + g_dlgSurface.GetTexMods (); + g_dlgSurface.m_nUndoId = 0; // that way we are sure we won't call undo + Sys_UpdateWindows(W_CAMERA); +} + +// we use OnTextureKey to detect when the user edits something in the texture widget +// in which case next 'Enter' will be interpreted as a OnApply instead of a OnDone +static gint OnTextureKey (GtkWidget* widget, GdkEventKey* event, gpointer data) +{ +#ifdef DBG_SI + Sys_Printf("OnTextureKey\n"); +#endif + if (event->keyval != GDK_Return) + g_dlgSurface.m_bEditingTextureWidget = true; + return FALSE; +} + +static void OnCancel(GtkWidget *widget, gpointer data) +{ + g_qeglobals.d_texturewin.texdef = g_old_texdef; + // cancel the last do if we own it + if (g_dlgSurface.m_nUndoId == Undo_GetUndoId()) + { +#ifdef DBG_SI + Sys_Printf("OnCancel calling Undo_Undo\n"); +#endif + g_bListenUpdate = false; + Undo_Undo(); + g_bListenUpdate = true; + g_dlgSurface.m_nUndoId = 0; + } + g_dlgSurface.HideDlg (); +} + +static gint OnDialogKey (GtkWidget* widget, GdkEventKey* event, gpointer data) +{ + if (g_surfwin) + { + if (event->keyval == GDK_Return) + { + if (g_dlgSurface.m_bEditingTextureWidget) + { + OnApply (NULL, NULL); + g_dlgSurface.m_bEditingTextureWidget = false; + } + else + { + OnDone (NULL, NULL); + } + return TRUE; + } + if (event->keyval == GDK_Escape) + { + OnCancel (NULL, NULL); + return TRUE; + } + } + return FALSE; +} + +// the widget can be one of hshift, vshift, hscale, vscale, rotate +// we use the g_bListenChanged flag to ignore when changing stuff ourselves +static void OnIncrementChanged(GtkWidget *widget, gpointer data) +{ + if (!g_bListenChanged) + return; + +#ifdef DBG_SI + Sys_Printf("OnIncrementChanged\n"); +#endif + + gfloat val = 0; + sscanf( gtk_entry_get_text (GTK_ENTRY (widget)), "%g", &val); + // now push it into the appropriate spin button + GtkAdjustment * adjust; + if (widget == g_dlgSurface.GetDlgWidget ("hshift_inc")) + { + l_pIncrement->shift[0] = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (g_dlgSurface.GetDlgWidget ("hshift"))); + adjust->step_increment = l_pIncrement->shift[0]; + } + else if (widget == g_dlgSurface.GetDlgWidget ("vshift_inc")) + { + l_pIncrement->shift[1] = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (g_dlgSurface.GetDlgWidget ("vshift"))); + adjust->step_increment = l_pIncrement->shift[1]; + } + else if (widget == g_dlgSurface.GetDlgWidget ("hscale_inc")) + { + l_pIncrement->scale[0] = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (g_dlgSurface.GetDlgWidget ("hscale"))); + adjust->step_increment = l_pIncrement->scale[0]; + } + else if (widget == g_dlgSurface.GetDlgWidget ("vscale_inc")) + { + l_pIncrement->scale[1] = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (g_dlgSurface.GetDlgWidget ("vscale"))); + adjust->step_increment = l_pIncrement->scale[1]; + } + else if (widget == g_dlgSurface.GetDlgWidget ("rotate_inc")) + { + l_pIncrement->rotate = val; + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (g_dlgSurface.GetDlgWidget ("rotate"))); + adjust->step_increment = l_pIncrement->rotate; + } +} + +// make the shift increments match the grid settings +// the objective being that the shift+arrows shortcuts move the texture by the corresponding grid size +// this depends on a scale value if you have selected a particular texture on which you want it to work: +// we move the textures in pixels, not world units. (i.e. increment values are in pixel) +// depending on the texture scale it doesn't take the same amount of pixels to move of g_qeglobals.d_gridsize +// increment * scale = gridsize +// hscale and vscale are optional parameters, if they are zero they will be set to the default scale +// NOTE: the default scale depends if you are using BP mode or regular. +// For regular it's 0.5f (128 pixels cover 64 world units), for BP it's simply 1.0f +// see fenris #2810 +void DoSnapTToGrid(float hscale, float vscale) +{ + if (hscale == 0.0f) + { + (g_qeglobals.m_bBrushPrimitMode) ? hscale = 1.0f : hscale = 0.5f; + } + if (vscale == 0.0f) + { + (g_qeglobals.m_bBrushPrimitMode) ? vscale = 1.0f : vscale = 0.5f; + } +#ifdef _DEBUG + Sys_Printf ("DoSnapTToGrid: hscale %g vscale %g\n", hscale, vscale); +#endif + l_pIncrement->shift[0] = (int) ( (float)g_qeglobals.d_gridsize / hscale ); + l_pIncrement->shift[1] = (int) ( (float)g_qeglobals.d_gridsize / vscale ); + // now some update work + // FIXME: doesn't look good here, seems to be called several times + g_dlgSurface.SetTexMods(); +} + +// make the shift increments match the grid settings +// the objective being that the shift+arrows shortcuts move the texture by the corresponding grid size +// this depends on the current texture scale used? +// we move the textures in pixels, not world units. (i.e. increment values are in pixel) +// depending on the texture scale it doesn't take the same amount of pixels to move of g_qeglobals.d_gridsize +// increment * scale = gridsize +static void OnBtnMatchGrid(GtkWidget *widget, gpointer data) +{ + float hscale, vscale; + hscale = gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (g_dlgSurface.GetDlgWidget ("hscale"))); + vscale = gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (g_dlgSurface.GetDlgWidget ("vscale"))); + if (hscale == 0.0f || vscale == 0.0f) + { + Sys_Printf("ERROR: unexpected scale == 0.0f\n"); + return; + } + DoSnapTToGrid (hscale, vscale); +} + +void UpdateSurfaceDialog() +{ + if (!g_bListenUpdate) + return; + + g_SurfaceTable.m_pfnUpdateSurfaceDialog(); +} + +// DoSurface will always try to show the surface inspector +// or update it because something new has been selected +void DoSurface (void) +{ +#ifdef DBG_SI + Sys_Printf("DoSurface\n"); +#endif + g_SurfaceTable.m_pfnDoSurface(); + return; +} + +void ToggleSurface() +{ + g_SurfaceTable.m_pfnToggleSurface(); + return; +} + +// NOTE: will raise and show the Surface inspector and exec fit for patches and brushes +void SurfaceDlgFitAll() +{ + g_SurfaceTable.m_pfnSurfaceDlgFitAll(); + return; +} + +static void OnBtnPatchdetails(GtkWidget *widget, gpointer data) +{ + Patch_NaturalizeSelected(true); + Sys_UpdateWindows(W_ALL); +} + +static void OnBtnPatchnatural(GtkWidget *widget, gpointer data) +{ + Patch_NaturalizeSelected(); + Sys_UpdateWindows(W_ALL); +} + +static void OnBtnPatchreset(GtkWidget *widget, gpointer data) +{ + float fx, fy; + + if (DoTextureLayout (&fx, &fy) == IDOK) + Patch_ResetTexturing (fx, fy); + Sys_UpdateWindows(W_ALL); +} + +static void OnBtnPatchFit(GtkWidget *widget, gpointer data) +{ + Patch_ResetTexturing(1.0, 1.0); + Sys_UpdateWindows(W_ALL); +} + +static void OnBtnAxial(GtkWidget *widget, gpointer data) +{ + Select_SetTexture (&g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef, true); + g_dlgSurface.SetTexMods(); + Sys_UpdateWindows(W_ALL); +} + +static void OnBtnFaceFit(GtkWidget *widget, gpointer data) +{ + g_dlgSurface.UpdateData(TRUE); + if (g_ptrSelectedFaces.GetSize() == 0) + { + brush_t *b; + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + for (face_t* pFace = b->brush_faces; pFace; pFace = pFace->next) + { + g_ptrSelectedFaces.Add(pFace); + g_ptrSelectedFaceBrushes.Add(b); + } + } + Select_FitTexture(g_dlgSurface.m_nHeight, g_dlgSurface.m_nWidth); + g_dlgSurface.SetTexMods(); + g_ptrSelectedFaces.RemoveAll(); + } + else + { + Select_FitTexture(g_dlgSurface.m_nHeight, g_dlgSurface.m_nWidth); + g_dlgSurface.SetTexMods(); + } + Sys_UpdateWindows(W_ALL); +} + +// ============================================================================= +// SurfaceDialog class + +SurfaceDlg::SurfaceDlg () +{ + m_nHeight = 1; + m_nWidth = 1; + m_nUndoId = 0; +} + +void SurfaceDlg::ShowDlg() +{ + Dialog::ShowDlg(); + if(GetWidget() == NULL) + Create(); + g_surfwin = GetWidget (); +} +void SurfaceDlg::HideDlg() +{ + g_surfwin = NULL; + Dialog::HideDlg(); +} + +GtkWidget* SurfaceDlg::GetWidget() +{ + return g_SurfaceTable.m_pfnGet_SI_Module_Widget(); +} + +// set default values for increments (shift scale and rot) +// this is called by the prefs code if can't find the values +void SurfaceDlg::InitDefaultIncrement(texdef_t *tex) +{ + tex->SetName("foo"); + tex->shift[0] = 8; + tex->shift[1] = 8; + tex->scale[0] = 0.25; + tex->scale[1] = 0.25; + tex->rotate = 10; +} + +void SurfaceDlg::BuildDialog () +{ + GtkWidget *dlg, *vbox, *hbox2, *frame, *table, *label; + GtkWidget *button, *entry, *spin; + + dlg = m_pWidget; + + load_window_pos (dlg, g_PrefsDlg.mWindowInfo.posSurfaceWnd); + + gtk_window_set_title (GTK_WINDOW (dlg), "Surface inspector"); + //g_signal_connect (G_OBJECT (dlg), "delete_event", G_CALLBACK (OnCancel), NULL); + // we catch 'Enter' and interpret is as OnDone + gtk_signal_connect (GTK_OBJECT (dlg), "key_press_event", GTK_SIGNAL_FUNC (OnDialogKey), NULL); + gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pParentWnd->m_pWidget)); + + // replaced by only the vbox: + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, TRUE, 0); + + label = gtk_label_new ("Texture"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 0); + + entry = gtk_entry_new (); + gtk_signal_connect (GTK_OBJECT (entry), "key_press_event", GTK_SIGNAL_FUNC (OnTextureKey), NULL); + gtk_widget_show (entry); + gtk_box_pack_start (GTK_BOX (hbox2), entry, TRUE, TRUE, 0); + g_object_set_data (G_OBJECT (m_pWidget), "texture", entry); + +// table = gtk_table_new (5, 4, FALSE); + table = gtk_table_new (6, 4, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Horizontal shift"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, -8192, 8192, 2, 8, 8)), 0, 0); + g_object_set_data (G_OBJECT (dlg), "hshift", spin); + gtk_signal_connect (GTK_OBJECT (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin))), "value_changed", + GTK_SIGNAL_FUNC (OnUpdate), NULL); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + + label = gtk_label_new ("Step"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + entry = gtk_entry_new (); + g_object_set_data (G_OBJECT (dlg), "hshift_inc", entry); + gtk_signal_connect (GTK_OBJECT (entry), "changed", + GTK_SIGNAL_FUNC (OnIncrementChanged), NULL); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + + label = gtk_label_new ("Vertical shift"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, -8192, 8192, 2, 8, 8)), 0, 0); + g_object_set_data (G_OBJECT (dlg), "vshift", spin); + gtk_signal_connect (GTK_OBJECT (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin))), "value_changed", + GTK_SIGNAL_FUNC (OnUpdate), NULL); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + + label = gtk_label_new ("Step"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + entry = gtk_entry_new (); + g_object_set_data (G_OBJECT (dlg), "vshift_inc", entry); + gtk_signal_connect (GTK_OBJECT (entry), "changed", + GTK_SIGNAL_FUNC (OnIncrementChanged), NULL); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + + label = gtk_label_new ("Horizontal stretch"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, -1000, 1000, 1, 10, 10)), 0, 0); + g_object_set_data (G_OBJECT (dlg), "hscale", spin); + gtk_signal_connect (GTK_OBJECT (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin))), "value_changed", + GTK_SIGNAL_FUNC (OnUpdate), NULL); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + + label = gtk_label_new ("Step"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 2, 3); + + entry = gtk_entry_new (); + g_object_set_data (G_OBJECT (dlg), "hscale_inc", entry); + gtk_signal_connect (GTK_OBJECT (entry), "changed", + GTK_SIGNAL_FUNC (OnIncrementChanged), NULL); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 2, 3); + gtk_widget_set_usize (entry, 50, -2); + + label = gtk_label_new ("Vertical stretch"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, -1000, 1000, 1, 10, 10)), 0, 0); + g_object_set_data (G_OBJECT (dlg), "vscale", spin); + gtk_signal_connect (GTK_OBJECT (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin))), "value_changed", + GTK_SIGNAL_FUNC (OnUpdate), NULL); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + + label = gtk_label_new ("Step"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + entry = gtk_entry_new (); + g_object_set_data (G_OBJECT (dlg), "vscale_inc", entry); + gtk_signal_connect (GTK_OBJECT (entry), "changed", + GTK_SIGNAL_FUNC (OnIncrementChanged), NULL); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + + label = gtk_label_new ("Rotate"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, -360, 360, 1, 10, 10)), 1, 0); + g_object_set_data (G_OBJECT (dlg), "rotate", spin); + gtk_signal_connect (GTK_OBJECT (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin))), "value_changed", + GTK_SIGNAL_FUNC (OnUpdate), NULL); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spin), TRUE); + + label = gtk_label_new ("Step"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + entry = gtk_entry_new (); + g_object_set_data (G_OBJECT (dlg), "rotate_inc", entry); + gtk_signal_connect (GTK_OBJECT (entry), "changed", + GTK_SIGNAL_FUNC (OnIncrementChanged), NULL); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + + // match grid button + button = gtk_button_new_with_label ("Match Grid"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 2, 4, 5, 6, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnBtnMatchGrid), NULL); + + frame = gtk_frame_new ("Texturing"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (4, 4, FALSE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + label = gtk_label_new ("Brush"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("Patch"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("Width"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new ("Height"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + button = gtk_button_new_with_label ("Axial"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnBtnAxial), NULL); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Fit"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnBtnFaceFit), NULL); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("CAP"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnBtnPatchdetails), NULL); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Set..."); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnBtnPatchreset), NULL); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Natural"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnBtnPatchnatural), NULL); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Fit"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 3, 4, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnBtnPatchFit), NULL); + gtk_widget_set_usize (button, 60, -2); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (1, 1, 32, 1, 10, 10)), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + AddDialogData (spin, &m_nWidth, DLG_SPIN_INT); + + spin = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (1, 1, 32, 1, 10, 10)), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + AddDialogData (spin, &m_nHeight, DLG_SPIN_INT); + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("Done"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnDone), NULL); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Apply"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnApply), NULL); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnCancel), NULL); + gtk_widget_set_usize (button, 60, -2); + + // that's a bit of trashy stuff from Textool-v2 branch +#ifdef _DEBUG + // FIXME: testing only, scaling in BP mode + button = gtk_button_new_with_label ("Test"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (OnTest), NULL); + gtk_widget_set_usize (button, 60, -2); +#endif + + // Initialize + SetTexMods (); +} + +/* +============== +SetTexMods + +Set the fields to the current texdef (i.e. map/texdef -> dialog widgets) +if faces selected (instead of brushes) -> will read this face texdef, else current texdef +if only patches selected, will read the patch texdef +=============== +*/ + +void SurfaceDlg::SetTexMods() +{ + texdef_t *pt; + brushprimit_texdef_t *bpt; + // local copy if a width=2 height=2 qtetxture_t is needed + brushprimit_texdef_t local_bp; + +#ifdef DBG_SI + Sys_Printf("SurfaceDlg::SetTexMods\n"); +#endif + + if (!g_surfwin) + return; + + if (g_ptrSelectedFaces.GetSize() > 0) + { + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(0)); + pt = &selFace->texdef; + if (g_qeglobals.m_bBrushPrimitMode) + { + // compute a texture matrix related to the default matrix width=2 height=2 + ConvertTexMatWithQTexture( &selFace->brushprimit_texdef, selFace->d_texture, &local_bp, NULL ); + bpt = &local_bp; + } + } + else + { + pt = &g_qeglobals.d_texturewin.texdef; + if (g_qeglobals.m_bBrushPrimitMode) + { + bpt = &g_qeglobals.d_texturewin.brushprimit_texdef; + } + } + // brush primitive mode : compute fake shift scale rot representation + if (g_qeglobals.m_bBrushPrimitMode) + TexMatToFakeTexCoords( bpt->coords, m_shift, &m_rotate, m_scale ); + + g_bListenChanged = false; + + if(strncmp(pt->GetName(), "textures/", 9) != 0) + pt->SetName(SHADER_NOT_FOUND); + gtk_entry_set_text (GTK_ENTRY (GetDlgWidget ("texture")), pt->GetName()+9); + + GtkSpinButton *spin; + spin = GTK_SPIN_BUTTON (GetDlgWidget ("hshift")); + gtk_spin_button_set_digits (spin, 2); + if (g_qeglobals.m_bBrushPrimitMode) + gtk_spin_button_set_value (spin, m_shift[0]); + else + gtk_spin_button_set_value (spin, pt->shift[0]); + GtkAdjustment *adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[0]; + char buf[10]; // got into snprintf paranoia after BoundChecker detected a stack overrun +#ifdef _WIN32 + // TTimo: THIS IS UGLY +#define snprintf _snprintf +#endif + snprintf (buf, 10, "%g", l_pIncrement->shift[0]); + gtk_entry_set_text (GTK_ENTRY (GetDlgWidget ("hshift_inc")), buf); + + spin = GTK_SPIN_BUTTON (GetDlgWidget ("vshift")); + gtk_spin_button_set_digits (spin, 2); + if (g_qeglobals.m_bBrushPrimitMode) + gtk_spin_button_set_value (spin, m_shift[1]); + else + gtk_spin_button_set_value (spin, pt->shift[1]); + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->shift[1]; + snprintf (buf, 10, "%g", l_pIncrement->shift[1]); + gtk_entry_set_text (GTK_ENTRY (GetDlgWidget ("vshift_inc")), buf); + + spin = GTK_SPIN_BUTTON (GetDlgWidget ("hscale")); + gtk_spin_button_set_digits (spin, 5); + gtk_spin_button_set_value (spin, g_qeglobals.m_bBrushPrimitMode ? m_scale[0] : pt->scale[0]); + + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[0]; + snprintf (buf, 10, "%g", l_pIncrement->scale[0]); + gtk_entry_set_text (GTK_ENTRY (GetDlgWidget ("hscale_inc")), buf); + + spin = GTK_SPIN_BUTTON (GetDlgWidget ("vscale")); + gtk_spin_button_set_digits (spin, 5); + gtk_spin_button_set_value (spin, g_qeglobals.m_bBrushPrimitMode ? m_scale[1] : pt->scale[1]); + + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->scale[1]; + snprintf (buf, 10, "%g", l_pIncrement->scale[1]); + gtk_entry_set_text (GTK_ENTRY (GetDlgWidget ("vscale_inc")), buf); + + //++timo compute BProtate as int .. + spin = GTK_SPIN_BUTTON (GetDlgWidget ("rotate")); + gtk_spin_button_set_digits (spin, 2); + gtk_spin_button_set_value (spin, g_qeglobals.m_bBrushPrimitMode ? m_rotate : pt->rotate); + + adjust = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adjust->step_increment = l_pIncrement->rotate; + snprintf (buf, 10, "%g", l_pIncrement->rotate); + gtk_entry_set_text (GTK_ENTRY (GetDlgWidget ("rotate_inc")), buf); + + g_bListenChanged = true; + + // undo tricks: set the undo id to zero so we don't attempt to undo something that does not belong to us + m_nUndoId = 0; + // store the current texdef as our escape route if user hits OnCancel + g_old_texdef = g_qeglobals.d_texturewin.texdef; + // reset the Enter key behaviour flag + m_bEditingTextureWidget = false; +} + +/* +============== +GetTexMods + +Reads the fields to get the current texdef (i.e. widgets -> MAP) +in brush primitive mode, grab the fake shift scale rot and compute a new texture matrix +=============== +*/ +void SurfaceDlg::GetTexMods() +{ + char buffer[1024]; + texdef_t *pt; + +#ifdef DBG_SI + Sys_Printf("SurfaceDlg::GetTexMods\n"); +#endif + + if (g_ptrSelectedFaces.GetSize() > 0) + { + //++timo just a test, we disable the undo when working on selected faces + m_nUndoId=0; + face_t *selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(0)); + g_qeglobals.d_texturewin.texdef = selFace->texdef; +#ifdef DBG_SI + Sys_Printf("g_qeglobals.d_texturewin.texdef = selFace->texdef\n"); +#endif + } +// else +// { + pt = &g_qeglobals.d_texturewin.texdef; +#ifdef DBG_SI + Sys_Printf("pt = &g_qeglobals.d_texturewin.texdef\n"); +#endif +// } + + const char* text = gtk_entry_get_text (GTK_ENTRY (GetDlgWidget ("texture"))); + +#ifdef DBG_SI + Sys_Printf("pt->SetName(%s)\n", text ); +#endif + + // TTimo: detect and refuse invalid texture names (at least the ones with spaces) + if (text[0] <= ' ' || strchr(text, ' ')) + { + Sys_FPrintf(SYS_WRN, "WARNING: spaces in shader names are not allowed, ignoring '%s'\n", text); + pt->SetName(SHADER_NOT_FOUND); + gtk_entry_set_text (GTK_ENTRY (GetDlgWidget ("texture")), pt->GetName()); + } + else + { + strcpy(buffer, "textures/"); + strcpy(buffer+9, text); + pt->SetName(buffer); + } + + + (g_qeglobals.m_bBrushPrimitMode ? m_shift[0] : pt->shift[0]) = + gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (GetDlgWidget ("hshift"))); + (g_qeglobals.m_bBrushPrimitMode ? m_shift[1] : pt->shift[1]) = + gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (GetDlgWidget ("vshift"))); + (g_qeglobals.m_bBrushPrimitMode ? m_scale[0] : pt->scale[0]) = + gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (GetDlgWidget ("hscale"))); + (g_qeglobals.m_bBrushPrimitMode ? m_scale[1] : pt->scale[1]) = + gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (GetDlgWidget ("vscale"))); + (g_qeglobals.m_bBrushPrimitMode ? m_rotate : pt->rotate) = + gtk_spin_button_get_value_as_float (GTK_SPIN_BUTTON (GetDlgWidget ("rotate"))); + + // a local copy of the texture matrix, given for a qtexture_t with width=2 height=2 + brushprimit_texdef_t local_bp; + brushprimit_texdef_t *bpt; + if (g_qeglobals.m_bBrushPrimitMode) + { + face_t *selFace = NULL; + if (g_ptrSelectedFaces.GetSize() > 0) + { + selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(0)); + bpt = &selFace->brushprimit_texdef; + } + else + { + bpt = &g_qeglobals.d_texturewin.brushprimit_texdef; + } + // compute texture matrix + // the matrix returned must be understood as a qtexture_t with width=2 height=2 + FakeTexCoordsToTexMat( m_shift, m_rotate, m_scale, local_bp.coords ); + // copy the texture matrix in the global struct + // fit the qtexture if we have a face selected, otherwise g_qeglobals.d_texturewin.brushprimit_texdef uses the basic qtexture_t with width=2 height=2 + + ConvertTexMatWithQTexture( &local_bp, NULL, bpt, ( (selFace) ? selFace->d_texture : NULL ) ); + } + // we are gonna do stuff, if we own the last do we undo it first + if (m_nUndoId != 0) + { + // check the do we're about to undo is the one we pushed earlier + if (m_nUndoId == Undo_GetUndoId()) + { +#ifdef DBG_SI + Sys_Printf("GetTexMods calling Undo_Undo (silent)\n"); +#endif + g_bListenUpdate=false; + Undo_Undo(true); + g_bListenUpdate=true; + } + } + Select_SetTexture(pt,&local_bp); + m_nUndoId = Undo_GetUndoId(); +} + +void SurfaceDlg::FitAll() +{ + OnBtnFaceFit(NULL, NULL); + OnBtnPatchFit(NULL, NULL); +} diff --git a/radiant/surfaceplugin.cpp b/radiant/surfaceplugin.cpp index b4b73217..3a1ef306 100644 --- a/radiant/surfaceplugin.cpp +++ b/radiant/surfaceplugin.cpp @@ -1,259 +1,259 @@ -/* -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 -*/ - -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// implementation of isurfaceplugin-interface specifics - -#include "stdafx.h" - -void QERApp_GetTwoSelectedPatch( patchMesh_t **p1, patchMesh_t **p2 ) -{ - *p1 = NULL; *p2 = NULL; - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - if (!(*p1)) - *p1 = pb->pPatch; - else if (!(*p2)) - { - *p2 = pb->pPatch; - return; - } - } - } -#ifdef _DEBUG - Sys_Printf("WARNING: QERApp_GetTwoSelectedPatch failed (did not find two patches)\n"); -#endif - return; -} - -// Nurail: The following functions are used by the Surface Inspector module - -// Queries the number of faces from selected brushes -int SI_GetSelectedFaceCountfromBrushes(void) -{ - face_t *f; - brush_t *b; - int num_of_faces = 0; - - if(selected_brushes.next == &selected_brushes) - return(0); - - for(b=selected_brushes.next; b!=&selected_brushes; b=b->next) - if (!(b->patchBrush)) - for(f=b->brush_faces; f ; f=f->next, num_of_faces++); - - return num_of_faces; -} - -void SI_GetSelFacesTexdef(texdef_to_face_t *allocd_block_texdef) -{ - int i; - face_t *f; - brush_t *b; - texdef_to_face_t *position, *prev_pos; - - if(selected_brushes.next != &selected_brushes) - { - prev_pos = position = allocd_block_texdef; - for(b=selected_brushes.next; b!=&selected_brushes; b=b->next) - { - if ( !(b->patchBrush) ) - { - for(f=b->brush_faces; f ; f = f->next) - { - position->face = f; - position->brush = b; - position->texdef = f->texdef; - position->orig_texdef = f->texdef; - prev_pos->next = position; - prev_pos = position; - position++; - } - prev_pos->next = NULL; - } - } - } - else if(g_ptrSelectedFaces.GetSize() != 0) - { - f = (face_t *) g_ptrSelectedFaces.GetAt(0); - b = (brush_t *) g_ptrSelectedFaceBrushes.GetAt(0); - position = (texdef_to_face_t*) allocd_block_texdef; - position->face = f; - position->brush = b; - position->texdef = f->texdef; - position->orig_texdef = f->texdef; - prev_pos = position; - for(i=1; iface = f; - position->brush = b; - position->texdef = f->texdef; - position->orig_texdef = f->texdef; - prev_pos->next = position; - prev_pos = position; - } - position->next = NULL; - } - -} - -/* -SetFaceTexdef_Q2 - -This doesn't mess with CONTENTS_DETAIL needed for Quake2 content flag - -*/ -void SetFaceTexdef_Q2 (face_t *f, texdef_t *texdef, bool bFitScale) -{ - - if(strcmp(f->texdef.GetName(), texdef->GetName()) != 0) // set shader here instead of Brush_Build - Face_SetShader(f, texdef->GetName()); - - if (bFitScale) - { - f->texdef = *texdef; - // fit the scaling of the texture on the actual plane - vec3_t p1,p2,p3; // absolute coordinates - // compute absolute coordinates - ComputeAbsolute(f,p1,p2,p3); - // compute the scale - vec3_t vx,vy; - VectorSubtract(p2,p1,vx); - VectorNormalize(vx, vx); - VectorSubtract(p3,p1,vy); - VectorNormalize(vy, vy); - // assign scale - VectorScale(vx,texdef->scale[0],vx); - VectorScale(vy,texdef->scale[1],vy); - VectorAdd(p1,vx,p2); - VectorAdd(p1,vy,p3); - // compute back shift scale rot - AbsoluteToLocal(f->plane,f,p1,p2,p3); - } - else - { - f->texdef = *texdef; - } - } - - - -void SI_SetTexdef_FaceList(texdef_to_face_t* texdef_face_list, bool b_SetUndoPoint, bool bFit_to_Scale) -{ - texdef_to_face_t* texdef_to_face; - bool b_isQuake2; - - if ( ( g_pGameDescription->mGameFile == "q2.game" ) || ( g_pGameDescription->mGameFile == "heretic2.game" ) ) - b_isQuake2 = true; - else - b_isQuake2 = false; - - if (!texdef_face_list) - return; - - if (b_SetUndoPoint) - { - if(g_ptrSelectedFaces.GetSize() > 1) - Sys_FPrintf(SYS_WRN, "WARNING: Undo NOT supported for multiple face selections\n"); - else if( (selected_brushes.next != &selected_brushes) || (g_ptrSelectedFaces.GetSize() == 1)) - { - // Give something to undo to - for(texdef_to_face = texdef_face_list; texdef_to_face; texdef_to_face = texdef_to_face->next) - if (b_isQuake2) - SetFaceTexdef_Q2(texdef_to_face->face, &texdef_to_face->orig_texdef, bFit_to_Scale); - else - SetFaceTexdef(texdef_to_face->face, &texdef_to_face->orig_texdef, NULL); - - Undo_Start("set facelist texdefs"); - - if( selected_brushes.next != &selected_brushes ) - Undo_AddBrushList(&selected_brushes); - else - Undo_AddBrush(texdef_face_list->brush); - - } - } - - for(texdef_to_face = texdef_face_list; texdef_to_face; texdef_to_face = texdef_to_face->next) - { - if (b_isQuake2) - SetFaceTexdef_Q2(texdef_to_face->face, &texdef_to_face->texdef, bFit_to_Scale); - else - SetFaceTexdef(texdef_to_face->face, &texdef_to_face->texdef, NULL , bFit_to_Scale); - Brush_Build(texdef_to_face->brush); - if(bFit_to_Scale) - texdef_to_face->texdef = texdef_to_face->face->texdef; - } - - if ( b_SetUndoPoint ) - { - if( (selected_brushes.next != &selected_brushes) || (g_ptrSelectedFaces.GetSize() == 1) ) - { - if(selected_brushes.next != &selected_brushes) - Undo_EndBrushList(&selected_brushes); - else - Undo_EndBrush(texdef_face_list->brush); - - Undo_End(); - // Over-write the orig_texdef list, cementing the change. - for(texdef_to_face = texdef_face_list; texdef_to_face; texdef_to_face = texdef_to_face->next) - texdef_to_face->orig_texdef = texdef_to_face->texdef; - } - } - - Sys_UpdateWindows (W_ALL); -} - -void SI_FaceList_FitTexture(texdef_to_face_t* si_texdef_face_list, int nHeight, int nWidth) -{ - texdef_to_face_t* temp_texdef_face_list; - - if (!si_texdef_face_list) - return; - - for (temp_texdef_face_list = si_texdef_face_list; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) - { - Face_FitTexture(temp_texdef_face_list->face, nHeight, nWidth); - Brush_Build(temp_texdef_face_list->brush,true,true,false,false); - // Write changes to our working Texdef list - temp_texdef_face_list->texdef = temp_texdef_face_list->face->texdef; - } - - Sys_UpdateWindows (W_CAMERA); - -} - -GtkWindow* SI_GetMainWindow(void) -{ - return GTK_WINDOW(g_qeglobals_gui.d_main_window); -} - -void SI_SetWinPos_from_Prefs(GtkWidget *win) -{ - load_window_pos (win, g_PrefsDlg.mWindowInfo.posSurfaceWnd); -} +/* +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 +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// implementation of isurfaceplugin-interface specifics + +#include "stdafx.h" + +void QERApp_GetTwoSelectedPatch( patchMesh_t **p1, patchMesh_t **p2 ) +{ + *p1 = NULL; *p2 = NULL; + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + if (!(*p1)) + *p1 = pb->pPatch; + else if (!(*p2)) + { + *p2 = pb->pPatch; + return; + } + } + } +#ifdef _DEBUG + Sys_Printf("WARNING: QERApp_GetTwoSelectedPatch failed (did not find two patches)\n"); +#endif + return; +} + +// Nurail: The following functions are used by the Surface Inspector module + +// Queries the number of faces from selected brushes +int SI_GetSelectedFaceCountfromBrushes(void) +{ + face_t *f; + brush_t *b; + int num_of_faces = 0; + + if(selected_brushes.next == &selected_brushes) + return(0); + + for(b=selected_brushes.next; b!=&selected_brushes; b=b->next) + if (!(b->patchBrush)) + for(f=b->brush_faces; f ; f=f->next, num_of_faces++); + + return num_of_faces; +} + +void SI_GetSelFacesTexdef(texdef_to_face_t *allocd_block_texdef) +{ + int i; + face_t *f; + brush_t *b; + texdef_to_face_t *position, *prev_pos; + + if(selected_brushes.next != &selected_brushes) + { + prev_pos = position = allocd_block_texdef; + for(b=selected_brushes.next; b!=&selected_brushes; b=b->next) + { + if ( !(b->patchBrush) ) + { + for(f=b->brush_faces; f ; f = f->next) + { + position->face = f; + position->brush = b; + position->texdef = f->texdef; + position->orig_texdef = f->texdef; + prev_pos->next = position; + prev_pos = position; + position++; + } + prev_pos->next = NULL; + } + } + } + else if(g_ptrSelectedFaces.GetSize() != 0) + { + f = (face_t *) g_ptrSelectedFaces.GetAt(0); + b = (brush_t *) g_ptrSelectedFaceBrushes.GetAt(0); + position = (texdef_to_face_t*) allocd_block_texdef; + position->face = f; + position->brush = b; + position->texdef = f->texdef; + position->orig_texdef = f->texdef; + prev_pos = position; + for(i=1; iface = f; + position->brush = b; + position->texdef = f->texdef; + position->orig_texdef = f->texdef; + prev_pos->next = position; + prev_pos = position; + } + position->next = NULL; + } + +} + +/* +SetFaceTexdef_Q2 + +This doesn't mess with CONTENTS_DETAIL needed for Quake2 content flag + +*/ +void SetFaceTexdef_Q2 (face_t *f, texdef_t *texdef, bool bFitScale) +{ + + if(strcmp(f->texdef.GetName(), texdef->GetName()) != 0) // set shader here instead of Brush_Build + Face_SetShader(f, texdef->GetName()); + + if (bFitScale) + { + f->texdef = *texdef; + // fit the scaling of the texture on the actual plane + vec3_t p1,p2,p3; // absolute coordinates + // compute absolute coordinates + ComputeAbsolute(f,p1,p2,p3); + // compute the scale + vec3_t vx,vy; + VectorSubtract(p2,p1,vx); + VectorNormalize(vx, vx); + VectorSubtract(p3,p1,vy); + VectorNormalize(vy, vy); + // assign scale + VectorScale(vx,texdef->scale[0],vx); + VectorScale(vy,texdef->scale[1],vy); + VectorAdd(p1,vx,p2); + VectorAdd(p1,vy,p3); + // compute back shift scale rot + AbsoluteToLocal(f->plane,f,p1,p2,p3); + } + else + { + f->texdef = *texdef; + } + } + + + +void SI_SetTexdef_FaceList(texdef_to_face_t* texdef_face_list, bool b_SetUndoPoint, bool bFit_to_Scale) +{ + texdef_to_face_t* texdef_to_face; + bool b_isQuake2; + + if ( ( g_pGameDescription->mGameFile == "q2.game" ) || ( g_pGameDescription->mGameFile == "heretic2.game" ) ) + b_isQuake2 = true; + else + b_isQuake2 = false; + + if (!texdef_face_list) + return; + + if (b_SetUndoPoint) + { + if(g_ptrSelectedFaces.GetSize() > 1) + Sys_FPrintf(SYS_WRN, "WARNING: Undo NOT supported for multiple face selections\n"); + else if( (selected_brushes.next != &selected_brushes) || (g_ptrSelectedFaces.GetSize() == 1)) + { + // Give something to undo to + for(texdef_to_face = texdef_face_list; texdef_to_face; texdef_to_face = texdef_to_face->next) + if (b_isQuake2) + SetFaceTexdef_Q2(texdef_to_face->face, &texdef_to_face->orig_texdef, bFit_to_Scale); + else + SetFaceTexdef(texdef_to_face->face, &texdef_to_face->orig_texdef, NULL); + + Undo_Start("set facelist texdefs"); + + if( selected_brushes.next != &selected_brushes ) + Undo_AddBrushList(&selected_brushes); + else + Undo_AddBrush(texdef_face_list->brush); + + } + } + + for(texdef_to_face = texdef_face_list; texdef_to_face; texdef_to_face = texdef_to_face->next) + { + if (b_isQuake2) + SetFaceTexdef_Q2(texdef_to_face->face, &texdef_to_face->texdef, bFit_to_Scale); + else + SetFaceTexdef(texdef_to_face->face, &texdef_to_face->texdef, NULL , bFit_to_Scale); + Brush_Build(texdef_to_face->brush); + if(bFit_to_Scale) + texdef_to_face->texdef = texdef_to_face->face->texdef; + } + + if ( b_SetUndoPoint ) + { + if( (selected_brushes.next != &selected_brushes) || (g_ptrSelectedFaces.GetSize() == 1) ) + { + if(selected_brushes.next != &selected_brushes) + Undo_EndBrushList(&selected_brushes); + else + Undo_EndBrush(texdef_face_list->brush); + + Undo_End(); + // Over-write the orig_texdef list, cementing the change. + for(texdef_to_face = texdef_face_list; texdef_to_face; texdef_to_face = texdef_to_face->next) + texdef_to_face->orig_texdef = texdef_to_face->texdef; + } + } + + Sys_UpdateWindows (W_ALL); +} + +void SI_FaceList_FitTexture(texdef_to_face_t* si_texdef_face_list, int nHeight, int nWidth) +{ + texdef_to_face_t* temp_texdef_face_list; + + if (!si_texdef_face_list) + return; + + for (temp_texdef_face_list = si_texdef_face_list; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next) + { + Face_FitTexture(temp_texdef_face_list->face, nHeight, nWidth); + Brush_Build(temp_texdef_face_list->brush,true,true,false,false); + // Write changes to our working Texdef list + temp_texdef_face_list->texdef = temp_texdef_face_list->face->texdef; + } + + Sys_UpdateWindows (W_CAMERA); + +} + +GtkWindow* SI_GetMainWindow(void) +{ + return GTK_WINDOW(g_qeglobals_gui.d_main_window); +} + +void SI_SetWinPos_from_Prefs(GtkWidget *win) +{ + load_window_pos (win, g_PrefsDlg.mWindowInfo.posSurfaceWnd); +} diff --git a/radiant/targetname.cpp b/radiant/targetname.cpp index f64089bb..7a5e3c9b 100644 --- a/radiant/targetname.cpp +++ b/radiant/targetname.cpp @@ -1,90 +1,90 @@ -/* -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 -*/ - -#include "stdafx.h" - -/*! -connects two entities creating a unique target/targetname value -*/ -void Entity_Connect(entity_t *e1, entity_t *e2) -{ - const char *maptarget; - char newtarget[16]; - int maxtarget=0; // highest t# value in the map - entity_t *e; // map entities - - if (e1 == e2) - { -#ifdef _DEBUG - Sys_Status ("Entity_Connect: Brushes are from same entity.", 0); -#endif - return; - } - - for (e=entities.next ; e != &entities ; e=e->next) - { - maptarget = ValueForKey (e, "target"); - if (maptarget && maptarget[0]) - { - int targetnum = atoi(maptarget+1); - if (targetnum > maxtarget) - maxtarget = targetnum; - } - } - sprintf (newtarget, "t%i", maxtarget+1); - -#ifdef _DEBUG - Sys_Printf("Connecting entities with new target/targetname: %s\n", newtarget); -#endif - - SetKeyValue (e1, "target", newtarget); - SetKeyValue (e2, "targetname", newtarget); -} - -int GetUniqueTargetId(int iHint) -{ - int iMin, iMax, i; - bool fFound; - entity_t *pe; - - fFound = FALSE; - pe = entities.next; - iMin = 0; - iMax = 0; - - for (; pe != NULL && pe != &entities ; pe = pe->next) - { - i = IntForKey(pe, "target"); - if (i) - { - iMin = MIN(i, iMin); - iMax = MAX(i, iMax); - if (i == iHint) - fFound = TRUE; - } - } - - if (fFound) - return iMax + 1; - else - return iHint; -} - +/* +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 +*/ + +#include "stdafx.h" + +/*! +connects two entities creating a unique target/targetname value +*/ +void Entity_Connect(entity_t *e1, entity_t *e2) +{ + const char *maptarget; + char newtarget[16]; + int maxtarget=0; // highest t# value in the map + entity_t *e; // map entities + + if (e1 == e2) + { +#ifdef _DEBUG + Sys_Status ("Entity_Connect: Brushes are from same entity.", 0); +#endif + return; + } + + for (e=entities.next ; e != &entities ; e=e->next) + { + maptarget = ValueForKey (e, "target"); + if (maptarget && maptarget[0]) + { + int targetnum = atoi(maptarget+1); + if (targetnum > maxtarget) + maxtarget = targetnum; + } + } + sprintf (newtarget, "t%i", maxtarget+1); + +#ifdef _DEBUG + Sys_Printf("Connecting entities with new target/targetname: %s\n", newtarget); +#endif + + SetKeyValue (e1, "target", newtarget); + SetKeyValue (e2, "targetname", newtarget); +} + +int GetUniqueTargetId(int iHint) +{ + int iMin, iMax, i; + bool fFound; + entity_t *pe; + + fFound = FALSE; + pe = entities.next; + iMin = 0; + iMax = 0; + + for (; pe != NULL && pe != &entities ; pe = pe->next) + { + i = IntForKey(pe, "target"); + if (i) + { + iMin = MIN(i, iMin); + iMax = MAX(i, iMax); + if (i == iHint) + fFound = TRUE; + } + } + + if (fFound) + return iMax + 1; + else + return iHint; +} + diff --git a/radiant/texmanip.cpp b/radiant/texmanip.cpp index 1e0c62ac..53c3b788 100644 --- a/radiant/texmanip.cpp +++ b/radiant/texmanip.cpp @@ -1,380 +1,380 @@ -/* -Copyright (c) 2002 Forest "LordHavoc" Hale - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Forest Hale nor the names of other contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "stdafx.h" -#include "str.h" - -static byte *row1 = NULL, *row2 = NULL; -static int rowsize = 0; - -void R_ResampleTextureLerpLine (byte *in, byte *out, int inwidth, int outwidth, int bytesperpixel) -{ - int j, xi, oldx = 0, f, fstep, endx, lerp; -#define LERPBYTE(i) out[i] = (byte) ((((row2[i] - row1[i]) * lerp) >> 16) + row1[i]) - - fstep = (int) (inwidth * 65536.0f / outwidth); - endx = (inwidth - 1); - if (bytesperpixel == 4) - { - for (j = 0,f = 0;j < outwidth;j++, f += fstep) - { - xi = f >> 16; - if (xi != oldx) - { - in += (xi - oldx) * 4; - oldx = xi; - } - - if (xi < endx) - { - lerp = f & 0xFFFF; - *out++ = (byte) ((((in[4] - in[0]) * lerp) >> 16) + in[0]); - *out++ = (byte) ((((in[5] - in[1]) * lerp) >> 16) + in[1]); - *out++ = (byte) ((((in[6] - in[2]) * lerp) >> 16) + in[2]); - *out++ = (byte) ((((in[7] - in[3]) * lerp) >> 16) + in[3]); - } - else // last pixel of the line has no pixel to lerp to - { - *out++ = in[0]; - *out++ = in[1]; - *out++ = in[2]; - *out++ = in[3]; - } - } - } - else if (bytesperpixel == 3) - { - for (j = 0, f = 0; j < outwidth; j++, f += fstep) - { - xi = f >> 16; - if (xi != oldx) - { - in += (xi - oldx) * 3; - oldx = xi; - } - - if (xi < endx) - { - lerp = f & 0xFFFF; - *out++ = (byte) ((((in[3] - in[0]) * lerp) >> 16) + in[0]); - *out++ = (byte) ((((in[4] - in[1]) * lerp) >> 16) + in[1]); - *out++ = (byte) ((((in[5] - in[2]) * lerp) >> 16) + in[2]); - } - else // last pixel of the line has no pixel to lerp to - { - *out++ = in[0]; - *out++ = in[1]; - *out++ = in[2]; - } - } - } - else - Sys_Printf("R_ResampleTextureLerpLine: unsupported bytesperpixel %i\n", bytesperpixel); -} - -/* -================ -R_ResampleTexture -================ -*/ -void R_ResampleTexture (void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight, int bytesperpixel) -{ - if (rowsize < outwidth * bytesperpixel) - { - if (row1) - free(row1); - if (row2) - free(row2); - - rowsize = outwidth * bytesperpixel; - row1 = (byte *)malloc(rowsize); - row2 = (byte *)malloc(rowsize); - } - - if (bytesperpixel == 4) - { - int i, j, yi, oldy, f, fstep, lerp, endy = (inheight-1), inwidth4 = inwidth*4, outwidth4 = outwidth*4; - byte *inrow, *out; - out = (byte *)outdata; - fstep = (int) (inheight * 65536.0f / outheight); -#define LERPBYTE(i) out[i] = (byte) ((((row2[i] - row1[i]) * lerp) >> 16) + row1[i]) - - inrow = (byte *)indata; - oldy = 0; - R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel); - R_ResampleTextureLerpLine (inrow + inwidth4, row2, inwidth, outwidth, bytesperpixel); - - for (i = 0, f = 0;i < outheight;i++,f += fstep) - { - yi = f >> 16; - if (yi < endy) - { - lerp = f & 0xFFFF; - if (yi != oldy) - { - inrow = (byte *)indata + inwidth4 * yi; - if (yi == oldy+1) - memcpy(row1, row2, outwidth4); - else - R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel); - - R_ResampleTextureLerpLine (inrow + inwidth4, row2, inwidth, outwidth, bytesperpixel); - oldy = yi; - } - j = outwidth - 4; - while(j >= 0) - { - LERPBYTE( 0); - LERPBYTE( 1); - LERPBYTE( 2); - LERPBYTE( 3); - LERPBYTE( 4); - LERPBYTE( 5); - LERPBYTE( 6); - LERPBYTE( 7); - LERPBYTE( 8); - LERPBYTE( 9); - LERPBYTE(10); - LERPBYTE(11); - LERPBYTE(12); - LERPBYTE(13); - LERPBYTE(14); - LERPBYTE(15); - out += 16; - row1 += 16; - row2 += 16; - j -= 4; - } - if (j & 2) - { - LERPBYTE( 0); - LERPBYTE( 1); - LERPBYTE( 2); - LERPBYTE( 3); - LERPBYTE( 4); - LERPBYTE( 5); - LERPBYTE( 6); - LERPBYTE( 7); - out += 8; - row1 += 8; - row2 += 8; - } - if (j & 1) - { - LERPBYTE( 0); - LERPBYTE( 1); - LERPBYTE( 2); - LERPBYTE( 3); - out += 4; - row1 += 4; - row2 += 4; - } - row1 -= outwidth4; - row2 -= outwidth4; - } - else - { - if (yi != oldy) - { - inrow = (byte *)indata + inwidth4*yi; - if (yi == oldy+1) - memcpy(row1, row2, outwidth4); - else - R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel); - - oldy = yi; - } - memcpy(out, row1, outwidth4); - } - } - } - else if (bytesperpixel == 3) - { - int i, j, yi, oldy, f, fstep, lerp, endy = (inheight-1), inwidth3 = inwidth * 3, outwidth3 = outwidth * 3; - byte *inrow, *out; - out = (byte *)outdata; - fstep = (int) (inheight*65536.0f/outheight); -#define LERPBYTE(i) out[i] = (byte) ((((row2[i] - row1[i]) * lerp) >> 16) + row1[i]) - - inrow = (byte *)indata; - oldy = 0; - R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel); - R_ResampleTextureLerpLine (inrow + inwidth3, row2, inwidth, outwidth, bytesperpixel); - for (i = 0, f = 0;i < outheight;i++,f += fstep) - { - yi = f >> 16; - if (yi < endy) - { - lerp = f & 0xFFFF; - if (yi != oldy) - { - inrow = (byte *)indata + inwidth3*yi; - if (yi == oldy+1) - memcpy(row1, row2, outwidth3); - else - R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel); - - R_ResampleTextureLerpLine (inrow + inwidth3, row2, inwidth, outwidth, bytesperpixel); - oldy = yi; - } - j = outwidth - 4; - while(j >= 0) - { - LERPBYTE( 0); - LERPBYTE( 1); - LERPBYTE( 2); - LERPBYTE( 3); - LERPBYTE( 4); - LERPBYTE( 5); - LERPBYTE( 6); - LERPBYTE( 7); - LERPBYTE( 8); - LERPBYTE( 9); - LERPBYTE(10); - LERPBYTE(11); - out += 12; - row1 += 12; - row2 += 12; - j -= 4; - } - if (j & 2) - { - LERPBYTE( 0); - LERPBYTE( 1); - LERPBYTE( 2); - LERPBYTE( 3); - LERPBYTE( 4); - LERPBYTE( 5); - out += 6; - row1 += 6; - row2 += 6; - } - if (j & 1) - { - LERPBYTE( 0); - LERPBYTE( 1); - LERPBYTE( 2); - out += 3; - row1 += 3; - row2 += 3; - } - row1 -= outwidth3; - row2 -= outwidth3; - } - else - { - if (yi != oldy) - { - inrow = (byte *)indata + inwidth3*yi; - if (yi == oldy+1) - memcpy(row1, row2, outwidth3); - else - R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel); - - oldy = yi; - } - memcpy(out, row1, outwidth3); - } - } - } - else - Sys_Printf("R_ResampleTexture: unsupported bytesperpixel %i\n", bytesperpixel); -} - -// in can be the same as out -void GL_MipReduce(byte *in, byte *out, int width, int height, int destwidth, int destheight) -{ - int x, y, width2, height2, nextrow; - if (width > destwidth) - { - if (height > destheight) - { - // reduce both - width2 = width >> 1; - height2 = height >> 1; - nextrow = width << 2; - for (y = 0;y < height2;y++) - { - for (x = 0;x < width2;x++) - { - out[0] = (byte) ((in[0] + in[4] + in[nextrow ] + in[nextrow+4]) >> 2); - out[1] = (byte) ((in[1] + in[5] + in[nextrow+1] + in[nextrow+5]) >> 2); - out[2] = (byte) ((in[2] + in[6] + in[nextrow+2] + in[nextrow+6]) >> 2); - out[3] = (byte) ((in[3] + in[7] + in[nextrow+3] + in[nextrow+7]) >> 2); - out += 4; - in += 8; - } - in += nextrow; // skip a line - } - } - else - { - // reduce width - width2 = width >> 1; - for (y = 0;y < height;y++) - { - for (x = 0;x < width2;x++) - { - out[0] = (byte) ((in[0] + in[4]) >> 1); - out[1] = (byte) ((in[1] + in[5]) >> 1); - out[2] = (byte) ((in[2] + in[6]) >> 1); - out[3] = (byte) ((in[3] + in[7]) >> 1); - out += 4; - in += 8; - } - } - } - } - else - { - if (height > destheight) - { - // reduce height - height2 = height >> 1; - nextrow = width << 2; - for (y = 0;y < height2;y++) - { - for (x = 0;x < width;x++) - { - out[0] = (byte) ((in[0] + in[nextrow ]) >> 1); - out[1] = (byte) ((in[1] + in[nextrow+1]) >> 1); - out[2] = (byte) ((in[2] + in[nextrow+2]) >> 1); - out[3] = (byte) ((in[3] + in[nextrow+3]) >> 1); - out += 4; - in += 4; - } - in += nextrow; // skip a line - } - } - else - Sys_Printf("GL_MipReduce: desired size already achieved\n"); - } -} +/* +Copyright (c) 2002 Forest "LordHavoc" Hale + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Forest Hale nor the names of other contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "stdafx.h" +#include "str.h" + +static byte *row1 = NULL, *row2 = NULL; +static int rowsize = 0; + +void R_ResampleTextureLerpLine (byte *in, byte *out, int inwidth, int outwidth, int bytesperpixel) +{ + int j, xi, oldx = 0, f, fstep, endx, lerp; +#define LERPBYTE(i) out[i] = (byte) ((((row2[i] - row1[i]) * lerp) >> 16) + row1[i]) + + fstep = (int) (inwidth * 65536.0f / outwidth); + endx = (inwidth - 1); + if (bytesperpixel == 4) + { + for (j = 0,f = 0;j < outwidth;j++, f += fstep) + { + xi = f >> 16; + if (xi != oldx) + { + in += (xi - oldx) * 4; + oldx = xi; + } + + if (xi < endx) + { + lerp = f & 0xFFFF; + *out++ = (byte) ((((in[4] - in[0]) * lerp) >> 16) + in[0]); + *out++ = (byte) ((((in[5] - in[1]) * lerp) >> 16) + in[1]); + *out++ = (byte) ((((in[6] - in[2]) * lerp) >> 16) + in[2]); + *out++ = (byte) ((((in[7] - in[3]) * lerp) >> 16) + in[3]); + } + else // last pixel of the line has no pixel to lerp to + { + *out++ = in[0]; + *out++ = in[1]; + *out++ = in[2]; + *out++ = in[3]; + } + } + } + else if (bytesperpixel == 3) + { + for (j = 0, f = 0; j < outwidth; j++, f += fstep) + { + xi = f >> 16; + if (xi != oldx) + { + in += (xi - oldx) * 3; + oldx = xi; + } + + if (xi < endx) + { + lerp = f & 0xFFFF; + *out++ = (byte) ((((in[3] - in[0]) * lerp) >> 16) + in[0]); + *out++ = (byte) ((((in[4] - in[1]) * lerp) >> 16) + in[1]); + *out++ = (byte) ((((in[5] - in[2]) * lerp) >> 16) + in[2]); + } + else // last pixel of the line has no pixel to lerp to + { + *out++ = in[0]; + *out++ = in[1]; + *out++ = in[2]; + } + } + } + else + Sys_Printf("R_ResampleTextureLerpLine: unsupported bytesperpixel %i\n", bytesperpixel); +} + +/* +================ +R_ResampleTexture +================ +*/ +void R_ResampleTexture (void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight, int bytesperpixel) +{ + if (rowsize < outwidth * bytesperpixel) + { + if (row1) + free(row1); + if (row2) + free(row2); + + rowsize = outwidth * bytesperpixel; + row1 = (byte *)malloc(rowsize); + row2 = (byte *)malloc(rowsize); + } + + if (bytesperpixel == 4) + { + int i, j, yi, oldy, f, fstep, lerp, endy = (inheight-1), inwidth4 = inwidth*4, outwidth4 = outwidth*4; + byte *inrow, *out; + out = (byte *)outdata; + fstep = (int) (inheight * 65536.0f / outheight); +#define LERPBYTE(i) out[i] = (byte) ((((row2[i] - row1[i]) * lerp) >> 16) + row1[i]) + + inrow = (byte *)indata; + oldy = 0; + R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel); + R_ResampleTextureLerpLine (inrow + inwidth4, row2, inwidth, outwidth, bytesperpixel); + + for (i = 0, f = 0;i < outheight;i++,f += fstep) + { + yi = f >> 16; + if (yi < endy) + { + lerp = f & 0xFFFF; + if (yi != oldy) + { + inrow = (byte *)indata + inwidth4 * yi; + if (yi == oldy+1) + memcpy(row1, row2, outwidth4); + else + R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel); + + R_ResampleTextureLerpLine (inrow + inwidth4, row2, inwidth, outwidth, bytesperpixel); + oldy = yi; + } + j = outwidth - 4; + while(j >= 0) + { + LERPBYTE( 0); + LERPBYTE( 1); + LERPBYTE( 2); + LERPBYTE( 3); + LERPBYTE( 4); + LERPBYTE( 5); + LERPBYTE( 6); + LERPBYTE( 7); + LERPBYTE( 8); + LERPBYTE( 9); + LERPBYTE(10); + LERPBYTE(11); + LERPBYTE(12); + LERPBYTE(13); + LERPBYTE(14); + LERPBYTE(15); + out += 16; + row1 += 16; + row2 += 16; + j -= 4; + } + if (j & 2) + { + LERPBYTE( 0); + LERPBYTE( 1); + LERPBYTE( 2); + LERPBYTE( 3); + LERPBYTE( 4); + LERPBYTE( 5); + LERPBYTE( 6); + LERPBYTE( 7); + out += 8; + row1 += 8; + row2 += 8; + } + if (j & 1) + { + LERPBYTE( 0); + LERPBYTE( 1); + LERPBYTE( 2); + LERPBYTE( 3); + out += 4; + row1 += 4; + row2 += 4; + } + row1 -= outwidth4; + row2 -= outwidth4; + } + else + { + if (yi != oldy) + { + inrow = (byte *)indata + inwidth4*yi; + if (yi == oldy+1) + memcpy(row1, row2, outwidth4); + else + R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel); + + oldy = yi; + } + memcpy(out, row1, outwidth4); + } + } + } + else if (bytesperpixel == 3) + { + int i, j, yi, oldy, f, fstep, lerp, endy = (inheight-1), inwidth3 = inwidth * 3, outwidth3 = outwidth * 3; + byte *inrow, *out; + out = (byte *)outdata; + fstep = (int) (inheight*65536.0f/outheight); +#define LERPBYTE(i) out[i] = (byte) ((((row2[i] - row1[i]) * lerp) >> 16) + row1[i]) + + inrow = (byte *)indata; + oldy = 0; + R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel); + R_ResampleTextureLerpLine (inrow + inwidth3, row2, inwidth, outwidth, bytesperpixel); + for (i = 0, f = 0;i < outheight;i++,f += fstep) + { + yi = f >> 16; + if (yi < endy) + { + lerp = f & 0xFFFF; + if (yi != oldy) + { + inrow = (byte *)indata + inwidth3*yi; + if (yi == oldy+1) + memcpy(row1, row2, outwidth3); + else + R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel); + + R_ResampleTextureLerpLine (inrow + inwidth3, row2, inwidth, outwidth, bytesperpixel); + oldy = yi; + } + j = outwidth - 4; + while(j >= 0) + { + LERPBYTE( 0); + LERPBYTE( 1); + LERPBYTE( 2); + LERPBYTE( 3); + LERPBYTE( 4); + LERPBYTE( 5); + LERPBYTE( 6); + LERPBYTE( 7); + LERPBYTE( 8); + LERPBYTE( 9); + LERPBYTE(10); + LERPBYTE(11); + out += 12; + row1 += 12; + row2 += 12; + j -= 4; + } + if (j & 2) + { + LERPBYTE( 0); + LERPBYTE( 1); + LERPBYTE( 2); + LERPBYTE( 3); + LERPBYTE( 4); + LERPBYTE( 5); + out += 6; + row1 += 6; + row2 += 6; + } + if (j & 1) + { + LERPBYTE( 0); + LERPBYTE( 1); + LERPBYTE( 2); + out += 3; + row1 += 3; + row2 += 3; + } + row1 -= outwidth3; + row2 -= outwidth3; + } + else + { + if (yi != oldy) + { + inrow = (byte *)indata + inwidth3*yi; + if (yi == oldy+1) + memcpy(row1, row2, outwidth3); + else + R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth, bytesperpixel); + + oldy = yi; + } + memcpy(out, row1, outwidth3); + } + } + } + else + Sys_Printf("R_ResampleTexture: unsupported bytesperpixel %i\n", bytesperpixel); +} + +// in can be the same as out +void GL_MipReduce(byte *in, byte *out, int width, int height, int destwidth, int destheight) +{ + int x, y, width2, height2, nextrow; + if (width > destwidth) + { + if (height > destheight) + { + // reduce both + width2 = width >> 1; + height2 = height >> 1; + nextrow = width << 2; + for (y = 0;y < height2;y++) + { + for (x = 0;x < width2;x++) + { + out[0] = (byte) ((in[0] + in[4] + in[nextrow ] + in[nextrow+4]) >> 2); + out[1] = (byte) ((in[1] + in[5] + in[nextrow+1] + in[nextrow+5]) >> 2); + out[2] = (byte) ((in[2] + in[6] + in[nextrow+2] + in[nextrow+6]) >> 2); + out[3] = (byte) ((in[3] + in[7] + in[nextrow+3] + in[nextrow+7]) >> 2); + out += 4; + in += 8; + } + in += nextrow; // skip a line + } + } + else + { + // reduce width + width2 = width >> 1; + for (y = 0;y < height;y++) + { + for (x = 0;x < width2;x++) + { + out[0] = (byte) ((in[0] + in[4]) >> 1); + out[1] = (byte) ((in[1] + in[5]) >> 1); + out[2] = (byte) ((in[2] + in[6]) >> 1); + out[3] = (byte) ((in[3] + in[7]) >> 1); + out += 4; + in += 8; + } + } + } + } + else + { + if (height > destheight) + { + // reduce height + height2 = height >> 1; + nextrow = width << 2; + for (y = 0;y < height2;y++) + { + for (x = 0;x < width;x++) + { + out[0] = (byte) ((in[0] + in[nextrow ]) >> 1); + out[1] = (byte) ((in[1] + in[nextrow+1]) >> 1); + out[2] = (byte) ((in[2] + in[nextrow+2]) >> 1); + out[3] = (byte) ((in[3] + in[nextrow+3]) >> 1); + out += 4; + in += 4; + } + in += nextrow; // skip a line + } + } + else + Sys_Printf("GL_MipReduce: desired size already achieved\n"); + } +} diff --git a/radiant/texwindow.cpp b/radiant/texwindow.cpp index acc259b5..0d7e54c1 100644 --- a/radiant/texwindow.cpp +++ b/radiant/texwindow.cpp @@ -1,1965 +1,1965 @@ -/* -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 -*/ - -// -// Texture Window -// -// Leonardo Zide (leo@lokigames.com) -// - -/*!\todo -Clean up texture menu. -- Remove all global variables and use some objects instead. -- Create an interface for a plugin to add texture menu items. -- Make sure the interface is not dependent on gtk. -*/ - -#ifdef _WIN32 -//#include -#include -#endif -#if defined (__linux__) || defined (__APPLE__) -#include -#include -#endif -#include -#include -#include -#include "stdafx.h" -#include "texwindow.h" -#include "str.h" -#include "missing.h" -#include "texmanip.h" - -#define TYP_MIPTEX 68 -static unsigned tex_palette[256]; - -#define FONT_HEIGHT 10 - -//int texture_mode = GL_NEAREST; -//int texture_mode = GL_NEAREST_MIPMAP_NEAREST; -//int texture_mode = GL_NEAREST_MIPMAP_LINEAR; -//int texture_mode = GL_LINEAR; -//int texture_mode = GL_LINEAR_MIPMAP_NEAREST; -int texture_mode = GL_LINEAR_MIPMAP_LINEAR; - -int g_nTextureOffset = 0; - -// current active texture directory -//++timo FIXME: I'm not sure this is used anymore -char texture_directory[128]; -// if true, the texture window will only display in-use shaders -// if false, all the shaders in memory are displayed -qboolean g_bShowAllShaders; - -bool g_bFilterEnabled = false; -CString g_strFilter; - -// texture layout functions -// TTimo: now based on shaders -int nActiveShadersCount; -int nCurrentShader; -IShader* pCurrentShader; -qtexture_t *current_texture = NULL; -int current_x, current_y, current_row; - -// globals for textures -int texture_nummenus; -char texture_menunames[MAX_TEXTUREDIRS][128]; - -// the list of scripts/*.shader files we need to work with -// those are listed in shaderlist file -// FIXME TTimo I get the feeling that those would need to move to the shaders module -// for now it's still more simple to just keep it here -GSList *l_shaderfiles = NULL; - -void SelectTexture (int mx, int my, bool bShift, bool bFitScale=false); - -void Texture_MouseDown (int x, int y, int buttons); -void Texture_MouseMoved (int x, int y, int buttons); - -CPtrArray g_lstSkinCache; - -// TTimo: modifed to add a qtexture_t, Texture_LoadSkin loads using the shader API / QERApp_TryTexture_ForName -// m_strName is a copy of qtex->name -struct SkinInfo -{ - CString m_strName; - int m_nTextureBind; - qtexture_t *m_qtex; - SkinInfo(const char *pName, int n, qtexture_t *qtex) - { - m_strName = pName; - m_nTextureBind = n; - m_qtex = qtex; - }; - SkinInfo(){}; -}; - -// ============================================================================= -// global functions - -// gets active texture extension -// -// FIXME: fix this to be generic from project file -// -int GetTextureExtensionCount() -{ - // hardcoded hack for png support - if (g_pGameDescription->mGameFile == "sof2.game") - return 3; - else - return 2; -} - -const char* GetTextureExtension(int nIndex) -{ - switch(nIndex) - { - case 0: - return "tga"; - break; - case 1: - return "jpg"; - break; - case 2: - return "png"; - break; - default: - return NULL; - } -} - -/* -============== -Texture_InitPalette -============== -*/ -void Texture_InitPalette (byte *pal) -{ - int r,g,b; - int i; - int inf; - byte gammatable[256]; - float gamma; - - gamma = g_qeglobals.d_savedinfo.fGamma; - - if (gamma == 1.0) - { - for (i=0 ; i<256 ; i++) - gammatable[i] = i; - } else - { - for (i=0 ; i<256 ; i++) - { - inf = (int)( 255.0f * pow( ( i + 0.5f ) / 255.5f , gamma ) + 0.5f ); - if (inf < 0) - inf = 0; - if (inf > 255) - inf = 255; - gammatable[i] = inf; - } - } - - for (i=0 ; i<256 ; i++) - { - r = gammatable[pal[0]]; - g = gammatable[pal[1]]; - b = gammatable[pal[2]]; - pal += 3; - - //v = (r<<24) + (g<<16) + (b<<8) + 255; - //v = BigLong (v); - - //tex_palette[i] = v; - tex_palette[i*3+0] = r; - tex_palette[i*3+1] = g; - tex_palette[i*3+2] = b; - } -} - -void SetTexParameters (void) -{ - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, texture_mode ); - - switch ( texture_mode ) - { - case GL_NEAREST: - case GL_NEAREST_MIPMAP_NEAREST: - case GL_NEAREST_MIPMAP_LINEAR: - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - break; - case GL_LINEAR: - case GL_LINEAR_MIPMAP_NEAREST: - case GL_LINEAR_MIPMAP_LINEAR: - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - break; - } -} - -/* -============ -Texture_SetMode -============ -*/ -void Texture_SetMode(int iMenu) -{ - int iMode; - qboolean texturing = true; - gpointer item = NULL; - - switch (iMenu) - { - case ID_VIEW_NEAREST: - item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_nearest"); - iMode = GL_NEAREST; - break; - case ID_VIEW_NEARESTMIPMAP: - item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_nearestmipmap"); - iMode = GL_NEAREST_MIPMAP_NEAREST; - break; - case ID_VIEW_LINEAR: - item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_linear"); - iMode = GL_LINEAR; - break; - case ID_VIEW_BILINEAR: - item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_bilinear"); - iMode = GL_NEAREST_MIPMAP_LINEAR; - break; - case ID_VIEW_BILINEARMIPMAP: - item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_bilinearmipmap"); - iMode = GL_LINEAR_MIPMAP_NEAREST; - break; - case ID_VIEW_TRILINEAR: - item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_trilinear"); - iMode = GL_LINEAR_MIPMAP_LINEAR; - break; - case ID_TEXTURES_WIREFRAME: - item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_wireframe"); - iMode = -1; - texturing = false; - break; - case ID_TEXTURES_FLATSHADE: - item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_flatshade"); - iMode = -1; - texturing = false; - break; - } - - g_qeglobals.d_savedinfo.iTexMenu = iMenu; - // NOTE: texture_mode is a GLenum used directly in glTexParameter - if(iMode!=-1) texture_mode = iMode; - - g_bIgnoreCommands++; - if (item != NULL) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - g_bIgnoreCommands--; - - if (texturing) - SetTexParameters (); - - if ( !texturing && iMenu == ID_TEXTURES_WIREFRAME) - { - g_pParentWnd->GetCamWnd()->Camera()->draw_mode = cd_wire; - Map_BuildBrushData(); - Sys_UpdateWindows (W_ALL); - return; - } else if ( !texturing && iMenu == ID_TEXTURES_FLATSHADE) - { - g_pParentWnd->GetCamWnd()->Camera()->draw_mode = cd_solid; - Map_BuildBrushData(); - Sys_UpdateWindows (W_ALL); - return; - } - - for (qtexture_t *q = g_qeglobals.d_qtextures; q; q = q->next) - { - qglBindTexture (GL_TEXTURE_2D, q->texture_number); - SetTexParameters (); - } - - // select the default texture - qglBindTexture( GL_TEXTURE_2D, 0 ); - - qglFinish(); - - if (g_pParentWnd->GetCamWnd()->Camera()->draw_mode != cd_texture) - { - g_pParentWnd->GetCamWnd()->Camera()->draw_mode = cd_texture; - Map_BuildBrushData(); - } - - Sys_UpdateWindows (W_ALL); -} - -/*! -gamma correction stuff -took out of QERApp_LoadTextureRGBA for clarity -*/ -byte g_gammatable[256]; -void ResampleGamma(float fGamma) -{ - int i,inf; - if (fGamma == 1.0) - { - for (i = 0; i < 256; i++) - g_gammatable[i] = i; - } else - { - for (i = 0; i < 256; i++) - { - inf = (int)( 255.0f * pow( (i + 0.5f) / 255.5f , fGamma ) + 0.5f ); - if (inf < 0) - inf = 0; - if (inf > 255) - inf = 255; - g_gammatable[i] = inf; - } - } -} - -/*! -this function does the actual processing of raw RGBA data into a GL texture -it will also generate the mipmaps -it looks like pPixels nWidth nHeight are the only relevant parameters -*/ -qtexture_t *QERApp_LoadTextureRGBA(unsigned char* pPixels, int nWidth, int nHeight) -{ - static float fGamma = -1; - float total[3]; - byte *outpixels = NULL; - int i, j, resampled, width2, height2, width3, height3; - int max_tex_size = 0, mip = 0; - int nCount = nWidth * nHeight; - - if (fGamma != g_qeglobals.d_savedinfo.fGamma) - { - fGamma = g_qeglobals.d_savedinfo.fGamma; - ResampleGamma(fGamma); - } - - qglGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size); - if (!max_tex_size) - max_tex_size = 1024; - - qtexture_t *q = (qtexture_t*)g_malloc(sizeof(*q)); - q->width = nWidth; - q->height = nHeight; - - total[0] = total[1] = total[2] = 0.0f; - - // resample texture gamma according to user settings - for (i = 0; i < (nCount * 4); i += 4) - { - for (j = 0; j < 3; j++) - { - total[j] += (pPixels + i)[j]; - byte b = (pPixels + i)[j]; - (pPixels + i)[j] = g_gammatable[b]; - } - } - - q->color[0] = total[0] / (nCount * 255); - q->color[1] = total[1] / (nCount * 255); - q->color[2] = total[2] / (nCount * 255); - - qglGenTextures (1, &q->texture_number); - - qglBindTexture( GL_TEXTURE_2D, q->texture_number ); - - SetTexParameters(); - - width2 = 1; while (width2 < nWidth) width2 <<= 1; - height2 = 1; while (height2 < nHeight) height2 <<= 1; - - width3 = width2; - height3 = height2; - while (width3 > max_tex_size) width3 >>= 1; - while (height3 > max_tex_size) height3 >>= 1; - if (width3 < 1) width3 = 1; - if (height3 < 1) height3 = 1; - - if (!(width2 == nWidth && height2 == nHeight)) { - resampled = 1; - outpixels = (byte *)malloc(width2 * height2 * 4); - R_ResampleTexture(pPixels, nWidth, nHeight, outpixels, width2, height2, 4); - } else { - resampled = 0; - outpixels = pPixels; - } - - while (width2 > width3 || height2 > height3) - { - GL_MipReduce(outpixels, outpixels, width2, height2, width3, height3); - - if (width2 > width3) - width2 >>= 1; - if (height2 > height3) - height2 >>= 1; - } - - qglTexImage2D(GL_TEXTURE_2D, mip++, g_qeglobals.texture_components, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, outpixels); - while (width2 > 1 || height2 > 1) - { - GL_MipReduce(outpixels, outpixels, width2, height2, 1, 1); - - if (width2 > 1) - width2 >>= 1; - if (height2 > 1) - height2 >>= 1; - - qglTexImage2D(GL_TEXTURE_2D, mip++, g_qeglobals.texture_components, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, outpixels); - } - - qglBindTexture(GL_TEXTURE_2D, 0); - if (resampled) - free(outpixels); - - return q; -} - -/* -================== -DumpUnreferencedShaders -usefull function: dumps the list of .shader files that are not referenced to the console -================== -*/ -void DumpUnreferencedShaders() -{ - GSList *lst, *sh, *files; - bool bFound = false; - - files = vfsGetFileList ("scripts", "shader"); - for (lst = files; lst; lst = lst->next) - { - bool listed = false; - - for (sh = l_shaderfiles; sh != NULL; sh = g_slist_next (sh)) - if (!strcmp ((char*)sh->data, (char*)lst->data)) - { - listed = true; - break; - } - - if (!listed) - { - if (!bFound) - { - bFound = true; - Sys_FPrintf (SYS_WRN, "Following shader files are not referenced in shaderlist.txt:\n"); - } - Sys_FPrintf (SYS_WRN, "%s\n", (char*)lst->data); - } - } - - vfsClearFileDirList (&files); -} - -/* -================== -BuildShaderList -build a CStringList of shader names -================== -*/ -void BuildShaderList() -{ - int count; - char filename[1024]; - char *pBuff; - char dirstring[NAME_MAX]; - int nLen; - if (l_shaderfiles!=NULL) - { - g_slist_free(l_shaderfiles); - l_shaderfiles = NULL; - } - - if (g_pGameDescription->mGameFile != "hl.game") - { - strcpy(filename, g_pGameDescription->mShaderlist.GetBuffer()); - count = vfsGetFileCount(filename, 0 ); - if (count==0) - { - Sys_FPrintf(SYS_ERR, "Couldn't find '%s'\n", g_pGameDescription->mShaderlist.GetBuffer()); - return; - } - // NOTE TTimo we use vfsGetFullPath solely to get the full path of the shader list we are gonna load - // but we actually send the relative path to vfsLoadFile - // so let's hope there is no disparity between the two functions - if (!vfsGetFullPath(filename, 0, 0)) - { - Sys_FPrintf(SYS_ERR, "Couldn't find full path for '%s'\n", g_pGameDescription->mShaderlist.GetBuffer()); - Sys_FPrintf(SYS_ERR, "did you hit bug http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 ?\n"); - return; - } - Sys_Printf("Parsing shader files from %s\n", vfsGetFullPath(filename, 0, 0)); - nLen = vfsLoadFile (filename, reinterpret_cast(&pBuff), 0); - if (nLen > 0) - { - StartTokenParsing(pBuff); - nLen = 0; - while (GetToken(true)) - { - GSList *tmp; - bool found = false; - - // each token should be a shader filename - sprintf(dirstring, "%s.shader", token); - - for (tmp = l_shaderfiles; tmp != NULL; tmp = tmp->next) - { - if (!strcmp (dirstring, (char*)tmp->data)) - { - found = true; - Sys_FPrintf(SYS_WRN, "duplicate entry \"%s\" in shaderlist.txt\n", (char*)tmp->data); - break; - } - } - - if (!found) - { - l_shaderfiles = g_slist_append (l_shaderfiles, strdup (dirstring)); - nLen++; - } - } - g_free(pBuff); - } - } -} - -/* -================== -FillTextureMenu - -================== -*/ -void ClearGSList (GSList* lst) -{ - GSList *p = lst; - while (p) - { - free (p->data); - p = g_slist_remove (p, p->data); - } -} - -void FillTextureMenu (GSList** pArray) -{ - GtkWidget *menu, *sep, *item; // point to the Textures GtkMenu and to the last separator - GList *lst; - GSList *texdirs = NULL; - GSList *texdirs_tmp = NULL; - GSList *p; - char dirRoot[NAME_MAX]; - // this is an index used to count the number of texture items (for splitting/avoiding to get out of window) - // we start with a != 0 value to compensate for the initial number of items in the texture menu - int nMenuCount = 12; - - // delete everything - menu = GTK_WIDGET (g_object_get_data (G_OBJECT (g_qeglobals_gui.d_main_window), "menu_textures")); - sep = GTK_WIDGET (g_object_get_data (G_OBJECT (g_qeglobals_gui.d_main_window), "menu_textures_separator")); - lst = g_list_find (gtk_container_children (GTK_CONTAINER (menu)), sep); - while (lst->next) - { - // these delete functions are recursive, it's gonna free all submenus - gtk_widget_destroy (GTK_WIDGET (lst->next->data)); - // lst is no longer relevant, need to get it again - lst = g_list_find (gtk_container_children (GTK_CONTAINER (menu)), sep); - } - - texture_nummenus = 0; - - // add everything - if (!g_qeglobals.d_project_entity) - return; - - // scan texture dirs and pak files only if not restricting to shaderlist - if (!g_PrefsDlg.m_bTexturesShaderlistOnly) - { - texdirs_tmp = vfsGetDirList ("textures/"); - for (p=texdirs_tmp; p; p=g_slist_next(p)) - { - // Hydra: erm, this didn't used to do anything except leak memory... - // For Halflife support this is required to work however. - // g_slist_append(texdirs, p->data); - texdirs = g_slist_append(texdirs, strdup((char *)p->data)); - } - vfsClearFileDirList (&texdirs_tmp); - } - - // scan the shaders in shaderlist.txt - BuildShaderList (); - PreloadShaders (); - DumpUnreferencedShaders (); - while (l_shaderfiles != NULL) - { - char shaderfile[PATH_MAX]; - gboolean found = FALSE; - - ExtractFileName ((char*)l_shaderfiles->data, shaderfile); - StripExtension (shaderfile); - g_strdown (shaderfile); - - for (GSList *tmp = texdirs; tmp; tmp = g_slist_next (tmp)) - if (!strcasecmp ((char*)tmp->data, shaderfile)) - { - found = TRUE; - break; - } - - if (!found) - texdirs = g_slist_prepend (texdirs, strdup (shaderfile)); - - free (l_shaderfiles->data); - l_shaderfiles = g_slist_remove (l_shaderfiles, l_shaderfiles->data); - } - - // sort the list - texdirs = g_slist_sort (texdirs, (GCompareFunc)strcmp); - - GSList *temp = texdirs; - while (temp) - { - char* ptr = strchr ((char*)temp->data, '_'); - - // do we shrink the menus? - if (ptr != NULL) - { - // extract the root - strcpy (dirRoot, (char*)temp->data); - dirRoot[ptr - (char*)temp->data + 1] = 0; - - // we shrink only if we have at least two things to shrink :-) - if (temp->next && (strstr ((char*)temp->next->data, dirRoot) == (char*)temp->next->data)) - { - GtkWidget *pSubMenu = gtk_menu_new (); - GtkWidget *pSubMenuRef = pSubMenu; - // keep going... - do - { - item = gtk_menu_item_new_with_label ((char*)temp->data); - gtk_widget_show (item); - CheckMenuSplitting (pSubMenu); - gtk_container_add (GTK_CONTAINER (pSubMenu), item); - gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (CMD_TEXTUREWAD+texture_nummenus)); - - strcpy (texture_menunames[texture_nummenus], (char*)temp->data); - strcat (texture_menunames[texture_nummenus], "/"); - if (pArray) - *pArray = g_slist_append (*pArray, strdup ((char*)temp->data)); - if (++texture_nummenus == MAX_TEXTUREDIRS) - { - Sys_Printf("WARNING: max texture directories count has been reached!\n"); - // push submenu and get out - item = gtk_menu_item_new_with_label (dirRoot); - gtk_widget_show (item); - gtk_container_add (GTK_CONTAINER (menu), item); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), pSubMenu); - ClearGSList (texdirs); - return; - } - temp = temp->next; - } - while (temp && (strstr((char*)temp->data, dirRoot)==temp->data)); - - ptr = strchr (dirRoot, '_'); - *ptr = 0; - item = gtk_menu_item_new_with_label (dirRoot); - gtk_widget_show (item); - CheckMenuSplitting (menu); - gtk_container_add (GTK_CONTAINER (menu), item); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), pSubMenuRef); - continue; - } - } - - item = gtk_menu_item_new_with_label ((char*)temp->data); - gtk_widget_show (item); - CheckMenuSplitting (menu); - gtk_container_add (GTK_CONTAINER (menu), item); - gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (CMD_TEXTUREWAD+texture_nummenus)); - - strcpy (texture_menunames[texture_nummenus], (char*)temp->data); - strcat (texture_menunames[texture_nummenus], "/"); - if (pArray) - *pArray = g_slist_append (*pArray, strdup ((char*)temp->data)); - if (++texture_nummenus == MAX_TEXTUREDIRS) - { - Sys_Printf("WARNING: max texture directories count has been reached!\n"); - ClearGSList (texdirs); - return; - } - - temp = temp->next; - } - ClearGSList (texdirs); -} - -/* -============== -Texture_ShowDirectory -relies on texture_directory global for the directory to use -called by - void Texture_ShowDirectory (int menunum, bool bLinked) - void Texture_ShowDirectory (char* pPath, bool bLinked) -1) Load the shaders for the given directory -2) Scan the remaining texture, load them and assign them a default shader (the "noshader" shader) -NOTE: when writing a texture plugin, or some texture extensions, this function may need to be overriden, and made - available through the IShaders interface -NOTE: for texture window layout: - all shaders are stored with alphabetical order after load - previously loaded and displayed stuff is hidden, only in-use and newly loaded is shown - ( the GL textures are not flushed though) -============== -*/ -void Texture_ShowDirectory () -{ - char name[1024]; - char dirstring[1024]; - CString strTemp; - int shaders_count = 0; - int textures_count = 0; - GSList *files = NULL, *temp; - - g_bScreenUpdates = false; - - // refresh the in-use textures: that will clear the IsDisplayed flag on unused stuff - // and leave it on in-use so they'll still be displayed - Texture_ShowInuse(); - // and textures loaded in the following lines will be displayed as well... - // NOTE: shaders that are not in use but have been loaded previously are still in memory. But they don't get displayed. - - g_qeglobals.d_texturewin.originy = 0; - // load texture_directory.shader - // NOTE: because of above call to Texture_ClearInuse, g_ActiveShaders will have the newly loaded shaders only - // we'll use that later to check if textures have a shader associated or not - // NOTE: all shaders loaded through QERApp_LoadShadersFromDir will get their InUse flag to True, we'll need a call to Texture_ShowInUse for later cleanup/adjustment - // NOTE: QERApp_LoadShadersFromDir has two criterions for loading a shader: - // the shaderfile is texture_directory (like "museum" will load everything in museum.shader) - // the shader name contains texture_directory (like "base_floor" will load museum.shader::base_floor/concfloor_rain) - shaders_count = QERApp_LoadShadersFromDir(texture_directory); - // load remaining texture files - // if a texture is already in use to represent a shader, ignore it - - // need this function "GSList *lst SynapseServer::GetMinorList(char *major_name);" - - sprintf (dirstring, "textures/%s", texture_directory); - g_ImageManager.BeginExtensionsScan(); - const char* ext; - while(ext=g_ImageManager.GetNextExtension()) - { - files = g_slist_concat(files, vfsGetFileList (dirstring, ext)); - } - - for (temp = files; temp; temp = temp->next) - { - sprintf(name, "%s%s", texture_directory, (char*)temp->data); - - StripExtension (name); - strTemp = name; - strTemp.MakeLower(); - - if (strTemp.Find(".specular") >= 0 || - strTemp.Find(".glow") >= 0 || - strTemp.Find(".bump") >= 0 || - strTemp.Find(".diffuse") >= 0 || - strTemp.Find(".blend") >= 0 || - strTemp.Find(".alpha") >= 0) - continue; - - // avoid ever loading a texture name with spaces - if (strTemp.Find(" ") >= 0) - { - Sys_FPrintf(SYS_WRN, "WARNING: Skipping texture name with spaces [%s]\n", strTemp.GetBuffer()); - continue; - } - - // build a texture name that fits the conventions for qtexture_t::name - char stdName[1024]; - sprintf( stdName, "textures/%s", name ); - // check if this texture doesn't have a shader - if (!QERApp_ActiveShader_ForTextureName( stdName )) - { - QERApp_CreateShader_ForTextureName (stdName); - textures_count++; - } - } - - Sys_Printf("Loaded %d shaders and created default shader for %d orphan textures.\n", - shaders_count, textures_count ); - - vfsClearFileDirList (&files); - - // sort for displaying - QERApp_SortActiveShaders(); - - sprintf (name, "Textures: %s", texture_directory); - gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_entity), name); - - // select the first texture in the list - if (!g_qeglobals.d_texturewin.texdef.GetName()[0]) - SelectTexture (16, g_qeglobals.d_texturewin.height -16, false); - - g_bScreenUpdates = true; - - Sys_UpdateWindows (W_TEXTURE); -} - -/* -============== -Texture_ShowDirectory -1) Load the shaders for the given directory -2) Scan the remaining texture, load them and assign them a default shader (the "noshader" shader) -NOTE: when writing a texture plugin, or some texture extensions, this function may need to be overriden, and made - available through the IShaders interface -============== -*/ -void Texture_ShowDirectory (int menunum) -{ - strcpy (texture_directory, texture_menunames[menunum-CMD_TEXTUREWAD]); - Texture_ShowDirectory(); -} - -// scroll origin so the current texture is completely on screen -// if current texture is not displayed, nothing is changed -void Texture_ResetPosition() -{ - qtexture_t *q; - int x,y; - - //this shouldn't ever happen, we startup with notex - if (!g_qeglobals.d_texturewin.texdef.GetName()[0]) { - return; - } - - // otherwise position with current texture shown - // this used to be in Texture_SetTexture - Texture_StartPos (); - while (1) - { - // NOTE: return value is == pCurrentShader and pCurrentShader->getTexture == current_texture - Texture_NextPos (&x, &y); - q = current_texture; - // if the current texture never found (because // 'show shaders' is off, - // for example), do nothing - if (!q) - break; - - int nHeight = (int)(q->height * ((float)g_PrefsDlg.m_nTextureScale / 100)); - // we have found when texdef->name and the shader name match - // NOTE: as everywhere else for our comparisons, we are not case sensitive - if (!strcmpi( g_qeglobals.d_texturewin.texdef.GetName(), pCurrentShader->getName() )) - { - // take care of calls before initialized - if ( !g_qeglobals.d_texturewin.height) { - g_qeglobals.d_texturewin.originy = 0; - break; - } - // if the bottom of our selected texture will fit with origin 0, use that - // to prevent scrolling uglyness (stuff scrolled off screen when - // everything would fit) - if ( -(y -nHeight-2*FONT_HEIGHT) < g_qeglobals.d_texturewin.height) { - g_qeglobals.d_texturewin.originy = 0; - break; - } - // if current is off the top of the window, move it to the top - if (y > g_qeglobals.d_texturewin.originy) - { - g_qeglobals.d_texturewin.originy = y; - break; - } - - // if current is off the bottom, put it on the bottom - if (y-nHeight-2*FONT_HEIGHT < g_qeglobals.d_texturewin.originy-g_qeglobals.d_texturewin.height) - { - g_qeglobals.d_texturewin.originy = y-nHeight-2*FONT_HEIGHT+g_qeglobals.d_texturewin.height; - break; - } - // if we made it here, it should already be in view - break; - } - } - Sys_UpdateWindows (W_TEXTURE); -} - -/* -============== -Texture_ShowAll -will set the IsDisplayed flag on all the active shaders, so we see everything that's currently in memory -============== -*/ -void Texture_ShowAll() -{ - char name[1024]; - -#ifdef _DEBUG - if (g_bShowAllShaders) - Sys_Printf("WARNING: already showing all shaders\n"); -#endif - QERApp_ActiveShaders_SetDisplayed(true); - g_bShowAllShaders = true; - // put some information in the texture window title? - sprintf (name, "Textures: in use"); - gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_entity), name); - Sys_UpdateWindows (W_TEXTURE); -} - -/* -============== -Texture_ShowInuse -clear all IsDisplayed flags -scan the map, set IsInUse (will set IsDisplayed on the way) -NOTE: don't sort the textures, don't update the windows (it's used in several contexts, not always necessary to do either) -============== -*/ -void WINAPI Texture_ShowInuse (void) -{ - face_t *f; - brush_t *b; - char name[1024]; - - g_qeglobals.d_texturewin.originy = 0; - - // purge - QERApp_ActiveShaders_SetDisplayed(false); - // scan and only display in-use stuff - Sys_Status("Selecting active textures", 0); - - for (b=active_brushes.next ; b != NULL && b != &active_brushes ; b=b->next) - { - if (b->patchBrush) - { - b->pPatch->pShader->SetInUse(true); - } else - { - for (f=b->brush_faces ; f ; f=f->next) - { - f->pShader->SetInUse(true); - } - } - } - for (b=selected_brushes.next ; b != NULL && b != &selected_brushes ; b=b->next) - { - if (b->patchBrush) - { - b->pPatch->pShader->SetInUse(true); - } else - { - for (f=b->brush_faces ; f ; f=f->next) - { - f->pShader->SetInUse(true); - } - } - } - - // we are no longer showing everything - g_bShowAllShaders = false; - // put some information in the texture window title? - sprintf (name, "Textures: in use"); - gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_entity), name); - - - // select the first texture in the list - if (!g_qeglobals.d_texturewin.texdef.GetName()[0]) - { - SelectTexture (16, g_qeglobals.d_texturewin.height -16, false); - } -} - -void Texture_ShowStartupShaders() -{ - if (g_PrefsDlg.m_nShader == PrefsDlg::SHADER_COMMON) - { - // RIANT - // HACK FOR JK2 SUPPORT - if (g_pGameDescription->mGameFile == "jk2.game" || g_pGameDescription->mGameFile == "ja.game") - { - strcpy (texture_directory, "system/"); - } - // RIANT - // HACK FOR SOF2 SUPPORT - else if (g_pGameDescription->mGameFile == "sof2.game") - { - strcpy (texture_directory, "tools/"); - } - else strcpy (texture_directory, "common/"); - Texture_ShowDirectory (); - } - - if (g_PrefsDlg.m_nShader == PrefsDlg::SHADER_ALL) { - int count; - char filename[1024]; - char *pBuff; - char dirstring[NAME_MAX]; - int nLen; - GSList *shaderfiles = NULL; - - strcpy(filename, g_pGameDescription->mShaderlist.GetBuffer()); - count = vfsGetFileCount(filename, 0); - if (count == 0) - { - Sys_FPrintf(SYS_ERR, "Couldn't find '%s'\n", g_pGameDescription->mShaderlist.GetBuffer()); - return; - } - - if (!vfsGetFullPath(filename, 0, 0)) - { - Sys_FPrintf(SYS_ERR, "Couldn't find full path for '%s'\n", g_pGameDescription->mShaderlist.GetBuffer()); - Sys_FPrintf(SYS_ERR, "did you hit bug http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 ?\n"); - return; - } - - Sys_Printf("Parsing shader files from %s\n", vfsGetFullPath(filename, 0, 0)); - nLen = vfsLoadFile (filename, reinterpret_cast(&pBuff), 0); - if (nLen > 0) - { - StartTokenParsing(pBuff); - nLen = 0; - while (GetToken(true)) - { - GSList *tmp; - bool found = false; - - // each token should be a shader filename - sprintf(dirstring, "%s.shader", token); - - for (tmp = shaderfiles; tmp != NULL; tmp = tmp->next) - { - if (!strcmp (dirstring, (char*)tmp->data)) - { - found = true; - Sys_FPrintf(SYS_WRN, "duplicate entry \"%s\" in shaderlist.txt\n", (char*)tmp->data); - break; - } - } - - if (!found) - { - shaderfiles = g_slist_append (l_shaderfiles, strdup (dirstring)); - strcpy (texture_directory, dirstring); - Texture_ShowDirectory (); - nLen++; - } - } - g_free(pBuff); - } - } -} - -/* -============================================================================ - -TEXTURE LAYOUT - -TTimo: now based on a rundown through all the shaders -nActiveShadersCount: number of shader that have a qtexture_t and may be displayed in the tex window -nCurrentShader: index of active shader that has the current_texture -pCurrentShader: IShader* for current shader -NOTE: we expect the Active shaders count doesn't change during a Texture_StartPos .. Texture_NextPos cycle - otherwise we may need to rely on a list instead of an array storage -============================================================================ -*/ - -void Texture_StartPos (void) -{ - //++timo TODO: check use of current_texture and current_row? - current_x = 8; - current_y = -8; - current_row = 0; - nActiveShadersCount = QERApp_GetActiveShaderCount(); - nCurrentShader = -1; - current_texture = NULL; - pCurrentShader = NULL; -} - -// if texture_showinuse jump over non in-use textures -// it's not very clear what should be done here and what in Texture_Draw .. maybe merging the two would do good -IShader* Texture_NextPos (int *x, int *y) -{ - qtexture_t* q; - while (1) - { - if (nCurrentShader >= nActiveShadersCount - 1) - { - // no more shaders - current_texture = NULL; - pCurrentShader = NULL; - return NULL; - } - nCurrentShader++; - pCurrentShader = QERApp_ActiveShader_ForIndex(nCurrentShader); - if (pCurrentShader == NULL) - { - Sys_Printf("ERROR: unexpected pCurrentShader == NULL in Texture_NextPos\n"); - return NULL; - } - current_texture = pCurrentShader->getTexture(); - q = current_texture; - - if (!q) - { - Sys_Printf("WARNING: found an IShader without qtexture_t in Texture_NextPos\n"); - return NULL; - } - - /* - Never show anything other than "textures/" path, - This is for q1/q2/q3 .map format, which expects "textures/" path on everything we apply - */ - if(strncmp(pCurrentShader->getName(), "textures/", 9) != 0) - continue; - - // don't show shaders? - if (!(g_PrefsDlg.m_bShowShaders || pCurrentShader->IsDefault())) - continue; - - if (g_PrefsDlg.m_bTextureWindow) - { - // some basic filtering - if (!g_pParentWnd->GetTexWnd()->CheckFilter( pCurrentShader->getName() )) - continue; - } - - //++timo FIXME: texture_showinuse is useless? with the menu and reload we just refresh the IsDisplayed flag - // but the IsInUse is only relevant to draw the green outline - if (pCurrentShader->IsDisplayed()) - break; - - continue; - } - - int nWidth = (int)(q->width * ((float)g_PrefsDlg.m_nTextureScale / 100)); - int nHeight = (int)(q->height * ((float)g_PrefsDlg.m_nTextureScale / 100)); - if (current_x + nWidth > g_qeglobals.d_texturewin.width-8 && current_row) - { // go to the next row unless the texture is the first on the row - current_x = 8; - current_y -= current_row + FONT_HEIGHT + 4; - current_row = 0; - } - - *x = current_x; - *y = current_y; - - // Is our texture larger than the row? If so, grow the - // row height to match it - - if (current_row < nHeight) - current_row = nHeight; - - // never go less than 64, or the names get all crunched up - current_x += nWidth < 64 ? 64 : nWidth; - current_x += 8; - - return pCurrentShader; -} - -/* -============================================================================ - - MOUSE ACTIONS - -============================================================================ -*/ - -static int textures_cursorx, textures_cursory; - -/* -============ -Texture_SetTexture - -brushprimit_texdef must be understood as a qtexture_t with width=2 height=2 ( the default one ) -============ -*/ - -//++timo NOTE: this is a mix of Shader module stuff and texture explorer -// it might need to be split in parts or moved out .. dunno -void WINAPI Texture_SetTexture (texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef *pTexdef, bool bSetSelection ) -{ - if (texdef->GetName()[0] == '(') - { - Sys_Status("Can't select an entity texture", 0); - return; - } - g_qeglobals.d_texturewin.texdef = *texdef; - g_qeglobals.d_texturewin.texdef.flags &= ~SURF_KEEP; - g_qeglobals.d_texturewin.texdef.contents &= ~CONTENTS_KEEP; - // store the shader pointer - // NOTE: maybe passing the shader pointer would help? - g_qeglobals.d_texturewin.pShader->DecRef(); - g_qeglobals.d_texturewin.pShader = QERApp_Shader_ForName(texdef->GetName()); - g_qeglobals.d_texturewin.pShader->IncRef(); - // set this shader as in use - g_qeglobals.d_texturewin.pShader->SetInUse( true ); - // store the texture coordinates for new brush primitive mode - // be sure that all the callers are using the default 2x2 texture - if (g_qeglobals.m_bBrushPrimitMode) - { - g_qeglobals.d_texturewin.brushprimit_texdef = *brushprimit_texdef; - } - - g_dlgFind.updateTextures(texdef->GetName()); - if (!g_dlgFind.isOpen() && bSetSelection) - { - Select_SetTexture(texdef,brushprimit_texdef,bFitScale); - } - - //plugins: send a message telling that the selected texture may have changed - DispatchRadiantMsg( RADIANT_TEXTURE ); - - // scroll origin so the texture is completely on screen - // takes texdef from g_qeglobals.d_texturewin.texdef, set above - Texture_ResetPosition(); -} - -void ViewShader(const char *pFile, const char *pName) -{ - // ask the vfs to build the full path to the file - // (i.e. the first one found) - char *fullName = vfsGetFullPath(pFile,0,0); - if (fullName == NULL) - { - Sys_FPrintf (SYS_ERR, "Couldn't get a full path to the shader file: %s\n", pFile); - return; - } - - char* pBuff = NULL; - int nSize = vfsLoadFullPathFile(fullName, reinterpret_cast(&pBuff)); - if (nSize <= 0) - { - Sys_FPrintf (SYS_ERR, "Failed to load shader file %s\n", fullName); - return; - } - // look for the shader declaration - int nStart; - CString strFind = pName; - CString strLook = pBuff; - strLook.MakeLower(); - strFind.MakeLower(); - // offset used when jumping over commented out definitions - int nOffset = 0; - while (true) - { - nStart = strLook.Find(strFind, nOffset); - if (nStart == -1) - break; - // we have found something, maybe it's a commented out shader name? - char *strCheck = new char[strLook.GetLength()+1]; - strcpy( strCheck, strLook.GetBuffer() ); - strCheck[nStart] = 0; - char *pCheck = strrchr( strCheck, '\n' ); - // if there's a commentary sign in-between we'll continue - if (pCheck && strstr( pCheck, "//" )) - { - delete[] strCheck; - nOffset = nStart + 1; - continue; - } - delete[] strCheck; - nOffset = nStart; - break; - } - // now close the file - g_free(pBuff); - - DoTextEditor (fullName, nOffset); -} - -/* -============== -SelectTexture - - By mouse click -============== -*/ -void SelectTexture (int mx, int my, bool bShift, bool bFitScale) -{ - int x, y; - qtexture_t *q; - texdef_t tex; - brushprimit_texdef_t brushprimit_tex; - - my += g_qeglobals.d_texturewin.originy-g_qeglobals.d_texturewin.height; - - Texture_StartPos (); - while (1) - { - // NOTE: return value is == pCurrentShader and pCurrentShader->getTexture == current_texture - Texture_NextPos (&x, &y); - q = current_texture; - if (!q) - break; - int nWidth = (int)(q->width * ((float)g_PrefsDlg.m_nTextureScale / 100)); - int nHeight = (int)(q->height * ((float)g_PrefsDlg.m_nTextureScale / 100)); - if (mx > x && mx - x < nWidth - && my < y && y - my < nHeight + FONT_HEIGHT) - { - if (bShift) - { - if (pCurrentShader->IsDefault()) - Sys_Printf("ERROR: %s is not a shader, it's a texture.\n", pCurrentShader->getName() ); - else - ViewShader( pCurrentShader->getShaderFileName(), pCurrentShader->getName() ); - } - else - { - memset (&tex, 0, sizeof(tex)); - memset (&brushprimit_tex, 0, sizeof(brushprimit_tex)); - if (g_qeglobals.m_bBrushPrimitMode) - { - // brushprimit fitted to a 2x2 texture - brushprimit_tex.coords[0][0] = 1.0f; - brushprimit_tex.coords[1][1] = 1.0f; - } - else - { - tex.scale[0] = g_pGameDescription->mTextureDefaultScale; - tex.scale[1] = g_pGameDescription->mTextureDefaultScale; - } - tex.flags = pCurrentShader->getFlags(); - // TTimo - shader code cleanup - // texdef.name is the name of the shader, not the name of the actual texture file - tex.SetName(pCurrentShader->getName()); - // NOTE WARNING: Texture_SetTexture uses Texture_NextPos stuff to move the window position on to the texture - // if there's some kind of fuckup in Texture_SetTexture you may end up with different pCurrentShader or even pCurrentShader == NULL - // so we just consider pCurrentShader and current_texture are not valid after this point - IShader *pAuxShader = pCurrentShader; - Texture_SetTexture ( &tex, &brushprimit_tex, bFitScale, NULL); // Nurail - CString strTex; - CString strName; - // if shader, print shader name, otherwise texture name - //++timo FIXME: maybe CShader needs some properties between color / default / actual shader -#ifdef _DEBUG - // this one is never supposed to be set as current one - if (pAuxShader->IsColor()) - Sys_Printf("ERROR: unexpected pCurrentShader->IsColor() in SelectTexture\n"); -#endif - // NOTE: IsColor is false, IsDefault the only remaining property - if (pAuxShader->IsDefault()) - { - strName = q->name; - // remove the "textures/" if needed - if (strName.Find("textures/")!=-1) - strName = strName.Mid(9); - } - else - { - strName = pAuxShader->getName(); - } - strTex.Format("%s W: %i H: %i", strName.GetBuffer(), q->width, q->height); - g_pParentWnd->SetStatusText(3, strTex); - } - return; - } - } - - Sys_Status("Did not select a texture", 0); -} - -/* -============== -Texture_MouseDown -============== -*/ -void Texture_MouseDown (int x, int y, int buttons) -{ - Sys_GetCursorPos (&textures_cursorx, &textures_cursory); - - // lbutton = select texture - if (buttons == MK_LBUTTON || buttons == (MK_LBUTTON | MK_SHIFT) || buttons == (MK_LBUTTON | MK_CONTROL)) - { - SelectTexture (x, g_qeglobals.d_texturewin.height - 1 - y, buttons & MK_SHIFT, buttons & MK_CONTROL); - UpdateSurfaceDialog(); - UpdatePatchInspector(); - } -} - -/* -============== -Texture_MouseMoved -============== -*/ - -void Texture_MouseMoved (int x, int y, int buttons) -{ - int scale = 1; - - if ( buttons & MK_SHIFT ) - scale = 4; - - // rbutton = drag texture origin - if (buttons & MK_RBUTTON) - { - Sys_GetCursorPos (&x, &y); - if ( y != textures_cursory) - { - g_qeglobals.d_texturewin.originy += ( y-textures_cursory) * scale; - if (g_qeglobals.d_texturewin.originy > 0) - g_qeglobals.d_texturewin.originy = 0; - Sys_SetCursorPos (textures_cursorx, textures_cursory); - - // (g_PrefsDlg.m_bTextureScrollbar && g_qeglobals_gui.d_texture_scroll != NULL) - // fixes broken texture scrolling when scrollbar is disabled - GtkAdjustment *vadjustment = gtk_range_get_adjustment (GTK_RANGE (g_qeglobals_gui.d_texture_scroll)); - gtk_adjustment_set_value (vadjustment, abs(g_qeglobals.d_texturewin.originy)); - // - } - return; - } -} - -/* -============================================================================ - -DRAWING - -============================================================================ -*/ - -int imax(int iFloor, int i) { if (i>iFloor) return iFloor;return i;} - -/* -============ -Texture_Draw -TTimo: relying on the shaders list to display the textures -we must query all qtexture_t* to manage and display through the IShaders interface -this allows a plugin to completely override the texture system -============ -*/ -void Texture_Draw (int width, int height) -{ - int x, y, last_y = 0, last_height = 0, nWidth, nHeight; - qtexture_t *q; - char *name; - - qglClearColor (g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][0], - g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][1], - g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][2], 0); - qglViewport (0,0,width,height); - qglMatrixMode(GL_PROJECTION); - qglLoadIdentity (); - - qglClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - qglDisable (GL_DEPTH_TEST); - qglDisable(GL_BLEND); - qglOrtho (0, width, g_qeglobals.d_texturewin.originy-height, g_qeglobals.d_texturewin.originy, -100, 100); - qglEnable (GL_TEXTURE_2D); - - qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); - g_qeglobals.d_texturewin.width = width; - g_qeglobals.d_texturewin.height = height; - - Texture_StartPos(); - for (;;) - { - // NOTE: return value is == pCurrentShader and pCurrentShader->getTexture == current_texture - Texture_NextPos (&x, &y); - q = current_texture; - if (!q) - break; - - nWidth = (int)(q->width * ((float)g_PrefsDlg.m_nTextureScale / 100)); - nHeight = (int)(q->height * ((float)g_PrefsDlg.m_nTextureScale / 100)); - - if (y != last_y) - { - last_y = y; - last_height = 0; - } - last_height = MAX (nHeight, last_height); - - // Is this texture visible? - if ((y-nHeight-FONT_HEIGHT < g_qeglobals.d_texturewin.originy) - && (y > g_qeglobals.d_texturewin.originy - height)) - { - // borders rules: - // if it's the current texture, draw a thick red line, else: - // shaders have a white border, simple textures don't - // if !texture_showinuse: (some textures displayed may not be in use) - // draw an additional square around with 0.5 1 0.5 color - if (!strcmpi(g_qeglobals.d_texturewin.texdef.GetName(), pCurrentShader->getName())) - { - qglLineWidth (3); - qglColor3f (1,0,0); - qglDisable (GL_TEXTURE_2D); - - qglBegin (GL_LINE_LOOP); - qglVertex2f (x-4,y-FONT_HEIGHT+4); - qglVertex2f (x-4,y-FONT_HEIGHT-nHeight-4); - qglVertex2f (x+4+nWidth,y-FONT_HEIGHT-nHeight-4); - qglVertex2f (x+4+nWidth,y-FONT_HEIGHT+4); - qglEnd (); - - qglEnable (GL_TEXTURE_2D); - qglLineWidth (1); - } - else - { - qglLineWidth (1); - // shader border: - if (!pCurrentShader->IsDefault()) - { - qglColor3f (1,1,1); - qglDisable (GL_TEXTURE_2D); - - qglBegin (GL_LINE_LOOP); - qglVertex2f (x-1,y+1-FONT_HEIGHT); - qglVertex2f (x-1,y-nHeight-1-FONT_HEIGHT); - qglVertex2f (x+1+nWidth,y-nHeight-1-FONT_HEIGHT); - qglVertex2f (x+1+nWidth,y+1-FONT_HEIGHT); - qglEnd (); - qglEnable (GL_TEXTURE_2D); - } - - // highlight in-use textures - if (pCurrentShader->IsInUse()) - { - qglColor3f (0.5,1,0.5); - qglDisable (GL_TEXTURE_2D); - qglBegin (GL_LINE_LOOP); - qglVertex2f (x-3,y+3-FONT_HEIGHT); - qglVertex2f (x-3,y-nHeight-3-FONT_HEIGHT); - qglVertex2f (x+3+nWidth,y-nHeight-3-FONT_HEIGHT); - qglVertex2f (x+3+nWidth,y+3-FONT_HEIGHT); - qglEnd (); - qglEnable (GL_TEXTURE_2D); - } - } - - // Draw the texture - qglBindTexture (GL_TEXTURE_2D, q->texture_number); - QE_CheckOpenGLForErrors(); - qglColor3f (1,1,1); - qglBegin (GL_QUADS); - qglTexCoord2f (0,0); - qglVertex2f (x,y-FONT_HEIGHT); - qglTexCoord2f (1,0); - qglVertex2f (x+nWidth,y-FONT_HEIGHT); - qglTexCoord2f (1,1); - qglVertex2f (x+nWidth,y-FONT_HEIGHT-nHeight); - qglTexCoord2f (0,1); - qglVertex2f (x,y-FONT_HEIGHT-nHeight); - qglEnd (); - - // draw the texture name - qglDisable (GL_TEXTURE_2D); - qglColor3f (1,1,1); - - qglRasterPos2f (x, y-FONT_HEIGHT+2); - - // don't draw the directory name - name = (char*)pCurrentShader->getName(); - name += strlen(name); - while(name != (char*)pCurrentShader->getName() && *(name-1) != '/' && *(name-1) != '\\') - name--; - - gtk_glwidget_print_string(name); - qglEnable (GL_TEXTURE_2D); - } - } - - g_qeglobals.d_texturewin.m_nTotalHeight = abs(y) + last_height + FONT_HEIGHT + 4; - - // reset the current texture - qglBindTexture(GL_TEXTURE_2D, 0); - qglFinish(); -} - -//++timo seems we only know hard inits now.. -//void Texture_Init (bool bHardInit) -void Texture_Init() -{ - g_qeglobals.d_qtextures = NULL; - // initialize the qtexture map - if (g_qeglobals.d_qtexmap) - { - Sys_FPrintf(SYS_ERR, "TODO: delete g_qeglobals.d_qtexmap in Texture_Init\n"); - } - g_qeglobals.d_qtexmap = g_hash_table_new (g_str_hash, g_str_equal); - // initialize .. in some cases if no default texture / project loaded it crashes - memset( &g_qeglobals.d_texturewin.texdef, 0, sizeof(g_qeglobals.d_texturewin.texdef) ); - g_qeglobals.d_texturewin.texdef.SetName(SHADER_NOT_FOUND); - g_qeglobals.d_texturewin.pShader = QERApp_Shader_ForName(SHADER_NOT_FOUND); -} - -// FIXME TTimo this needs to move to the shader module along with l_shaderlist move -// preload shader files that have been listed in shaderlist.txt -void PreloadShaders() -{ - GSList *lst = l_shaderfiles; - Str shadername; - while (lst) - { - shadername = g_pGameDescription->mShaderPath; - shadername += (char*)lst->data; - QERApp_LoadShaderFile(shadername.GetBuffer()); - lst = lst->next; - } -} - -// TTimo: modified to expect the reletive path to the skin as input -// will look into pak files if necessary -// uses the shader code to load the texture Try_Texture_ForName -// modified SkinInfo accordingly to store the qtexture_t and shader name (reletive version) -// the .md3 have bundled filetype extension, but they don't fit with the actual data -// ex: models/mapobjects/gargoyle.tga doesn't exist, but models/mapobjects/gargoyle.jpg can be used instead -// so we remove the extension before load attempt -int WINAPI Texture_LoadSkin(char *pName, int *pnWidth, int *pnHeight) -{ - // byte *pic = NULL; - // byte *pic32 = NULL; - int nTex = -1; - qtexture_t *qtex; - SkinInfo *pInfo; - const char *pCleanName; - - int nSize = g_lstSkinCache.GetSize(); - pCleanName = QERApp_CleanTextureName( pName, false ); - for (int i = 0; i < nSize; i++) - { - SkinInfo *pInfo = reinterpret_cast(g_lstSkinCache.GetAt(i)); - if (pInfo) - { - if (stricmp(pCleanName, pInfo->m_strName) == 0) - { - return pInfo->m_nTextureBind; - } - } - } - - // if the load is successfull, we get back a qtexture_t - // we don't need to free it, it's in g_qeglobals.d_qtextures - // NOTE: we need to free the SkinInfo though.. - qtex = QERApp_Try_Texture_ForName( pCleanName ); - if (qtex) - { - nTex = qtex->texture_number; - pInfo = new SkinInfo(qtex->name, nTex, qtex); - } else - { - pInfo = new SkinInfo(pCleanName, -1, NULL); - } - g_lstSkinCache.Add(pInfo); - - return nTex; -} - -bool TexWnd::CheckFilter( const char* name ) -{ - const char* buf = gtk_entry_get_text (GTK_ENTRY (m_pFilter)); - if (strstr( name, buf ) != 0) - return true; - return false; -} - -// ============================================================================= -// static functions - -static void vertical_scroll (GtkWidget *widget, gpointer data) -{ - ((TexWnd*)data)->OnVScroll (); -} - -static void filter_changed (GtkWidget *widget, gpointer data) -{ - CString str; - str = gtk_entry_get_text (GTK_ENTRY (widget)); - ((TexWnd*)data)->UpdateFilter (str); -} - -// ============================================================================= -// TexWnd class - -TexWnd::TexWnd() -: GLWindow (FALSE) -{ - m_pFilter = NULL; - m_bNeedRange = true; -} - -TexWnd::~TexWnd() -{ -} - -void TexWnd::OnCreate () -{ - if (!MakeCurrent ()) - Error ("glMakeCurrent in TexWnd::OnCreate failed"); - - g_qeglobals_gui.d_texture = m_pWidget; - g_nTextureOffset = 0; - - GtkAdjustment *vadjustment = gtk_range_get_adjustment (GTK_RANGE (g_qeglobals_gui.d_texture_scroll)); - gtk_signal_connect (GTK_OBJECT (vadjustment), "value_changed", GTK_SIGNAL_FUNC (vertical_scroll), this); - - if (g_PrefsDlg.m_bTextureScrollbar) - gtk_widget_show (g_qeglobals_gui.d_texture_scroll); - else - gtk_widget_hide (g_qeglobals_gui.d_texture_scroll); - m_bNeedRange = true; - - gtk_signal_connect (GTK_OBJECT (m_pFilter), "changed", GTK_SIGNAL_FUNC (filter_changed), this); - if (g_PrefsDlg.m_bTextureWindow) - gtk_widget_show (m_pFilter); -} - -void TexWnd::UpdateFilter(const char* pFilter) -{ - g_bFilterEnabled = false; - if (pFilter) - { - g_strFilter = pFilter; - if (g_strFilter.GetLength() > 0) - g_bFilterEnabled = true; - QERApp_SortActiveShaders(); - } - Sys_UpdateWindows (W_TEXTURE); -} - -void TexWnd::OnSize (int cx, int cy) -{ - m_bNeedRange = true; -} - -void TexWnd::OnExpose () -{ - int nOld = g_qeglobals.d_texturewin.m_nTotalHeight; - if (!MakeCurrent ()) - { - Sys_Printf("ERROR: glXMakeCurrent failed..\n "); - Sys_Printf("Please restart Radiant if the Texture view is not working\n"); - } else - { - QE_CheckOpenGLForErrors(); - Texture_Draw (m_pWidget->allocation.width, m_pWidget->allocation.height - g_nTextureOffset); - QE_CheckOpenGLForErrors(); - SwapBuffers (); - } - if (g_PrefsDlg.m_bTextureScrollbar && (m_bNeedRange || g_qeglobals.d_texturewin.m_nTotalHeight != nOld)) - { - GtkAdjustment *vadjustment = gtk_range_get_adjustment (GTK_RANGE (g_qeglobals_gui.d_texture_scroll)); - - vadjustment->value = -g_qeglobals.d_texturewin.originy; - vadjustment->page_size = m_pWidget->allocation.height; - vadjustment->page_increment = m_pWidget->allocation.height/2; - vadjustment->step_increment = 20; - vadjustment->lower = 0; - vadjustment->upper = g_qeglobals.d_texturewin.m_nTotalHeight; - - gtk_signal_emit_by_name (GTK_OBJECT (vadjustment), "changed"); - - m_bNeedRange = false; - } -} - -void TexWnd::OnLButtonDown (guint32 flags, int pointx, int pointy) -{ - SetCapture (); - Texture_MouseDown (pointx, pointy - g_nTextureOffset, flags); -} - -void TexWnd::OnRButtonDown (guint32 flags, int pointx, int pointy) -{ - SetCapture (); - Texture_MouseDown (pointx, pointy - g_nTextureOffset, flags); -} - -void TexWnd::OnMButtonDown (guint32 flags, int pointx, int pointy) -{ - SetCapture (); - Texture_MouseDown (pointx, pointy - g_nTextureOffset, flags); -} - -void TexWnd::OnLButtonUp (guint32 flags, int pointx, int pointy) -{ - ReleaseCapture (); - // NOTE TTimo http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=23 - DragDropTexture (flags, pointx, pointy); -} - -void TexWnd::OnRButtonUp (guint32 flags, int pointx, int pointy) -{ - ReleaseCapture (); -} - -void TexWnd::OnMButtonUp (guint32 flags, int pointx, int pointy) -{ - ReleaseCapture (); -} - -void TexWnd::OnMouseMove (guint32 flags, int pointx, int pointy) -{ - Texture_MouseMoved (pointx, pointy - g_nTextureOffset, flags); - // if scrollbar is hidden, we don't seem to get an update - if( !g_PrefsDlg.m_bTextureScrollbar ) - RedrawWindow (); -} - -void TexWnd::OnVScroll () -{ - GtkAdjustment *vadjustment = gtk_range_get_adjustment (GTK_RANGE (g_qeglobals_gui.d_texture_scroll)); - - g_qeglobals.d_texturewin.originy = - (int)vadjustment->value; - RedrawWindow (); -} - -void TexWnd::UpdatePrefs() -{ - if (g_PrefsDlg.m_bTextureWindow) - gtk_widget_show (m_pFilter); - else - gtk_widget_hide (m_pFilter); - - if (g_PrefsDlg.m_bTextureScrollbar) - gtk_widget_show (g_qeglobals_gui.d_texture_scroll); - else - gtk_widget_hide (g_qeglobals_gui.d_texture_scroll); - m_bNeedRange = true; - RedrawWindow (); -} - -void TexWnd::FocusEdit() -{ - if (GTK_WIDGET_VISIBLE (m_pFilter)) - gtk_window_set_focus (GTK_WINDOW (g_pParentWnd->m_pWidget), m_pFilter); -} - -void TexWnd::OnMouseWheel(bool bUp) -{ - if (bUp) - { - if(g_qeglobals.d_texturewin.originy < 0) { - g_qeglobals.d_texturewin.originy += g_PrefsDlg.m_nWheelInc; - // clamp so we don't get jiggle if moved by less than scrollwheel increment - if(g_qeglobals.d_texturewin.originy > 0) { - g_qeglobals.d_texturewin.originy = 0; - } - } - } - else - { - if(g_qeglobals.d_texturewin.originy > (-g_qeglobals.d_texturewin.m_nTotalHeight + g_qeglobals.d_texturewin.height)) - g_qeglobals.d_texturewin.originy -= g_PrefsDlg.m_nWheelInc; - } - GtkAdjustment *vadjustment = gtk_range_get_adjustment (GTK_RANGE (g_qeglobals_gui.d_texture_scroll)); - gtk_adjustment_set_value (vadjustment, abs(g_qeglobals.d_texturewin.originy)); - - RedrawWindow(); -} - -// NOTE TTimo -// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=23 -void TexWnd::DragDropTexture (guint32 flags, int pointx, int pointy) -{ - // This gets called from leftmouse up event. We see if the mouseup is above - // the camwindow. If this is the case do a trace for a surface. If we hit a - // surface, texture it with the current texture. - - int m_ptXcheck, m_ptYcheck; - int m_ptX, m_ptY; - GtkWidget *widget; - gint x, y; - vec3_t dir; - float f, r, u; - int i; - - // we only want to catch a plain mouseevent - if (flags) - return; - - // see if we are above the camwindow - Sys_GetCursorPos (&m_ptX, &m_ptY); - - if (g_pParentWnd->CurrentStyle() == MainFrame::eFloating) - widget = g_pParentWnd->GetCamWnd()->m_pParent; - else - widget = g_pParentWnd->GetCamWnd()->GetWidget(); - - get_window_pos (widget, &x, &y); - - if (m_ptX < x || m_ptY < y || - m_ptX > x + widget->allocation.width || - m_ptY > y + widget->allocation.height) - return; - - // check if the camwindow isn't being partially hidden by another window at this point - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=187 - m_ptXcheck = m_ptX; - m_ptYcheck = m_ptY; - - if( g_pParentWnd->GetCamWnd()->GetWidget()->window != gdk_window_at_pointer( &m_ptXcheck, &m_ptYcheck ) ) - return; - - // calc ray direction - x = m_ptX - x; - y = g_pParentWnd->GetCamWnd()->Camera()->height - 1 - (m_ptY - y); - u = (float)( y - ( g_pParentWnd->GetCamWnd()->Camera()->height * .5f ) ) / ( g_pParentWnd->GetCamWnd()->Camera()->height * .5f ); - r = (float)( x - ( g_pParentWnd->GetCamWnd()->Camera()->width * .5f ) ) / ( g_pParentWnd->GetCamWnd()->Camera()->width * .5f ); - f = 1; - - for (i=0 ; i<3 ; i++) - dir[i] = g_pParentWnd->GetCamWnd()->Camera()->vpn[i] * f + - g_pParentWnd->GetCamWnd()->Camera()->vright[i] * r + - g_pParentWnd->GetCamWnd()->Camera()->vup[i] * u; - VectorNormalize (dir, dir); - - // do a trace for a surface - trace_t t; - - t = Test_Ray (g_pParentWnd->GetCamWnd()->Camera()->origin, dir, SF_SINGLEFACE); - - if (t.brush) - { - texdef_t tex; - brushprimit_texdef_t brushprimit_tex; - - memset (&tex, 0, sizeof(tex)); - memset (&brushprimit_tex, 0, sizeof(brushprimit_tex)); - if (g_qeglobals.m_bBrushPrimitMode) - { - // brushprimit fitted to a 2x2 texture - brushprimit_tex.coords[0][0] = 1.0f; - brushprimit_tex.coords[1][1] = 1.0f; - } else - { - tex.scale[0] = g_pGameDescription->mTextureDefaultScale; - tex.scale[1] = g_pGameDescription->mTextureDefaultScale; - } - tex.flags = g_qeglobals.d_texturewin.texdef.flags; - tex.value = g_qeglobals.d_texturewin.texdef.value; - tex.contents = g_qeglobals.d_texturewin.texdef.contents; - // TTimo - shader code cleanup - // texdef.name is the name of the shader, not the name of the actual texture file - tex.SetName(g_qeglobals.d_texturewin.texdef.GetName()); - - Undo_Start("set face textures"); - Undo_AddBrush(t.brush); - SetFaceTexdef (t.face, &tex, &brushprimit_tex, false, NULL ); - Brush_Build(t.brush, false); - Undo_EndBrush(t.brush); - Undo_End(); - - Sys_UpdateWindows (W_CAMERA); - g_pParentWnd->OnTimer (); - } -} +/* +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 +*/ + +// +// Texture Window +// +// Leonardo Zide (leo@lokigames.com) +// + +/*!\todo +Clean up texture menu. +- Remove all global variables and use some objects instead. +- Create an interface for a plugin to add texture menu items. +- Make sure the interface is not dependent on gtk. +*/ + +#ifdef _WIN32 +//#include +#include +#endif +#if defined (__linux__) || defined (__APPLE__) +#include +#include +#endif +#include +#include +#include +#include "stdafx.h" +#include "texwindow.h" +#include "str.h" +#include "missing.h" +#include "texmanip.h" + +#define TYP_MIPTEX 68 +static unsigned tex_palette[256]; + +#define FONT_HEIGHT 10 + +//int texture_mode = GL_NEAREST; +//int texture_mode = GL_NEAREST_MIPMAP_NEAREST; +//int texture_mode = GL_NEAREST_MIPMAP_LINEAR; +//int texture_mode = GL_LINEAR; +//int texture_mode = GL_LINEAR_MIPMAP_NEAREST; +int texture_mode = GL_LINEAR_MIPMAP_LINEAR; + +int g_nTextureOffset = 0; + +// current active texture directory +//++timo FIXME: I'm not sure this is used anymore +char texture_directory[128]; +// if true, the texture window will only display in-use shaders +// if false, all the shaders in memory are displayed +qboolean g_bShowAllShaders; + +bool g_bFilterEnabled = false; +CString g_strFilter; + +// texture layout functions +// TTimo: now based on shaders +int nActiveShadersCount; +int nCurrentShader; +IShader* pCurrentShader; +qtexture_t *current_texture = NULL; +int current_x, current_y, current_row; + +// globals for textures +int texture_nummenus; +char texture_menunames[MAX_TEXTUREDIRS][128]; + +// the list of scripts/*.shader files we need to work with +// those are listed in shaderlist file +// FIXME TTimo I get the feeling that those would need to move to the shaders module +// for now it's still more simple to just keep it here +GSList *l_shaderfiles = NULL; + +void SelectTexture (int mx, int my, bool bShift, bool bFitScale=false); + +void Texture_MouseDown (int x, int y, int buttons); +void Texture_MouseMoved (int x, int y, int buttons); + +CPtrArray g_lstSkinCache; + +// TTimo: modifed to add a qtexture_t, Texture_LoadSkin loads using the shader API / QERApp_TryTexture_ForName +// m_strName is a copy of qtex->name +struct SkinInfo +{ + CString m_strName; + int m_nTextureBind; + qtexture_t *m_qtex; + SkinInfo(const char *pName, int n, qtexture_t *qtex) + { + m_strName = pName; + m_nTextureBind = n; + m_qtex = qtex; + }; + SkinInfo(){}; +}; + +// ============================================================================= +// global functions + +// gets active texture extension +// +// FIXME: fix this to be generic from project file +// +int GetTextureExtensionCount() +{ + // hardcoded hack for png support + if (g_pGameDescription->mGameFile == "sof2.game") + return 3; + else + return 2; +} + +const char* GetTextureExtension(int nIndex) +{ + switch(nIndex) + { + case 0: + return "tga"; + break; + case 1: + return "jpg"; + break; + case 2: + return "png"; + break; + default: + return NULL; + } +} + +/* +============== +Texture_InitPalette +============== +*/ +void Texture_InitPalette (byte *pal) +{ + int r,g,b; + int i; + int inf; + byte gammatable[256]; + float gamma; + + gamma = g_qeglobals.d_savedinfo.fGamma; + + if (gamma == 1.0) + { + for (i=0 ; i<256 ; i++) + gammatable[i] = i; + } else + { + for (i=0 ; i<256 ; i++) + { + inf = (int)( 255.0f * pow( ( i + 0.5f ) / 255.5f , gamma ) + 0.5f ); + if (inf < 0) + inf = 0; + if (inf > 255) + inf = 255; + gammatable[i] = inf; + } + } + + for (i=0 ; i<256 ; i++) + { + r = gammatable[pal[0]]; + g = gammatable[pal[1]]; + b = gammatable[pal[2]]; + pal += 3; + + //v = (r<<24) + (g<<16) + (b<<8) + 255; + //v = BigLong (v); + + //tex_palette[i] = v; + tex_palette[i*3+0] = r; + tex_palette[i*3+1] = g; + tex_palette[i*3+2] = b; + } +} + +void SetTexParameters (void) +{ + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, texture_mode ); + + switch ( texture_mode ) + { + case GL_NEAREST: + case GL_NEAREST_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + break; + case GL_LINEAR: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_LINEAR: + qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + break; + } +} + +/* +============ +Texture_SetMode +============ +*/ +void Texture_SetMode(int iMenu) +{ + int iMode; + qboolean texturing = true; + gpointer item = NULL; + + switch (iMenu) + { + case ID_VIEW_NEAREST: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_nearest"); + iMode = GL_NEAREST; + break; + case ID_VIEW_NEARESTMIPMAP: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_nearestmipmap"); + iMode = GL_NEAREST_MIPMAP_NEAREST; + break; + case ID_VIEW_LINEAR: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_linear"); + iMode = GL_LINEAR; + break; + case ID_VIEW_BILINEAR: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_bilinear"); + iMode = GL_NEAREST_MIPMAP_LINEAR; + break; + case ID_VIEW_BILINEARMIPMAP: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_bilinearmipmap"); + iMode = GL_LINEAR_MIPMAP_NEAREST; + break; + case ID_VIEW_TRILINEAR: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_trilinear"); + iMode = GL_LINEAR_MIPMAP_LINEAR; + break; + case ID_TEXTURES_WIREFRAME: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_wireframe"); + iMode = -1; + texturing = false; + break; + case ID_TEXTURES_FLATSHADE: + item = g_object_get_data (G_OBJECT (g_pParentWnd->m_pWidget), "menu_view_flatshade"); + iMode = -1; + texturing = false; + break; + } + + g_qeglobals.d_savedinfo.iTexMenu = iMenu; + // NOTE: texture_mode is a GLenum used directly in glTexParameter + if(iMode!=-1) texture_mode = iMode; + + g_bIgnoreCommands++; + if (item != NULL) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + g_bIgnoreCommands--; + + if (texturing) + SetTexParameters (); + + if ( !texturing && iMenu == ID_TEXTURES_WIREFRAME) + { + g_pParentWnd->GetCamWnd()->Camera()->draw_mode = cd_wire; + Map_BuildBrushData(); + Sys_UpdateWindows (W_ALL); + return; + } else if ( !texturing && iMenu == ID_TEXTURES_FLATSHADE) + { + g_pParentWnd->GetCamWnd()->Camera()->draw_mode = cd_solid; + Map_BuildBrushData(); + Sys_UpdateWindows (W_ALL); + return; + } + + for (qtexture_t *q = g_qeglobals.d_qtextures; q; q = q->next) + { + qglBindTexture (GL_TEXTURE_2D, q->texture_number); + SetTexParameters (); + } + + // select the default texture + qglBindTexture( GL_TEXTURE_2D, 0 ); + + qglFinish(); + + if (g_pParentWnd->GetCamWnd()->Camera()->draw_mode != cd_texture) + { + g_pParentWnd->GetCamWnd()->Camera()->draw_mode = cd_texture; + Map_BuildBrushData(); + } + + Sys_UpdateWindows (W_ALL); +} + +/*! +gamma correction stuff +took out of QERApp_LoadTextureRGBA for clarity +*/ +byte g_gammatable[256]; +void ResampleGamma(float fGamma) +{ + int i,inf; + if (fGamma == 1.0) + { + for (i = 0; i < 256; i++) + g_gammatable[i] = i; + } else + { + for (i = 0; i < 256; i++) + { + inf = (int)( 255.0f * pow( (i + 0.5f) / 255.5f , fGamma ) + 0.5f ); + if (inf < 0) + inf = 0; + if (inf > 255) + inf = 255; + g_gammatable[i] = inf; + } + } +} + +/*! +this function does the actual processing of raw RGBA data into a GL texture +it will also generate the mipmaps +it looks like pPixels nWidth nHeight are the only relevant parameters +*/ +qtexture_t *QERApp_LoadTextureRGBA(unsigned char* pPixels, int nWidth, int nHeight) +{ + static float fGamma = -1; + float total[3]; + byte *outpixels = NULL; + int i, j, resampled, width2, height2, width3, height3; + int max_tex_size = 0, mip = 0; + int nCount = nWidth * nHeight; + + if (fGamma != g_qeglobals.d_savedinfo.fGamma) + { + fGamma = g_qeglobals.d_savedinfo.fGamma; + ResampleGamma(fGamma); + } + + qglGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size); + if (!max_tex_size) + max_tex_size = 1024; + + qtexture_t *q = (qtexture_t*)g_malloc(sizeof(*q)); + q->width = nWidth; + q->height = nHeight; + + total[0] = total[1] = total[2] = 0.0f; + + // resample texture gamma according to user settings + for (i = 0; i < (nCount * 4); i += 4) + { + for (j = 0; j < 3; j++) + { + total[j] += (pPixels + i)[j]; + byte b = (pPixels + i)[j]; + (pPixels + i)[j] = g_gammatable[b]; + } + } + + q->color[0] = total[0] / (nCount * 255); + q->color[1] = total[1] / (nCount * 255); + q->color[2] = total[2] / (nCount * 255); + + qglGenTextures (1, &q->texture_number); + + qglBindTexture( GL_TEXTURE_2D, q->texture_number ); + + SetTexParameters(); + + width2 = 1; while (width2 < nWidth) width2 <<= 1; + height2 = 1; while (height2 < nHeight) height2 <<= 1; + + width3 = width2; + height3 = height2; + while (width3 > max_tex_size) width3 >>= 1; + while (height3 > max_tex_size) height3 >>= 1; + if (width3 < 1) width3 = 1; + if (height3 < 1) height3 = 1; + + if (!(width2 == nWidth && height2 == nHeight)) { + resampled = 1; + outpixels = (byte *)malloc(width2 * height2 * 4); + R_ResampleTexture(pPixels, nWidth, nHeight, outpixels, width2, height2, 4); + } else { + resampled = 0; + outpixels = pPixels; + } + + while (width2 > width3 || height2 > height3) + { + GL_MipReduce(outpixels, outpixels, width2, height2, width3, height3); + + if (width2 > width3) + width2 >>= 1; + if (height2 > height3) + height2 >>= 1; + } + + qglTexImage2D(GL_TEXTURE_2D, mip++, g_qeglobals.texture_components, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, outpixels); + while (width2 > 1 || height2 > 1) + { + GL_MipReduce(outpixels, outpixels, width2, height2, 1, 1); + + if (width2 > 1) + width2 >>= 1; + if (height2 > 1) + height2 >>= 1; + + qglTexImage2D(GL_TEXTURE_2D, mip++, g_qeglobals.texture_components, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, outpixels); + } + + qglBindTexture(GL_TEXTURE_2D, 0); + if (resampled) + free(outpixels); + + return q; +} + +/* +================== +DumpUnreferencedShaders +usefull function: dumps the list of .shader files that are not referenced to the console +================== +*/ +void DumpUnreferencedShaders() +{ + GSList *lst, *sh, *files; + bool bFound = false; + + files = vfsGetFileList ("scripts", "shader"); + for (lst = files; lst; lst = lst->next) + { + bool listed = false; + + for (sh = l_shaderfiles; sh != NULL; sh = g_slist_next (sh)) + if (!strcmp ((char*)sh->data, (char*)lst->data)) + { + listed = true; + break; + } + + if (!listed) + { + if (!bFound) + { + bFound = true; + Sys_FPrintf (SYS_WRN, "Following shader files are not referenced in shaderlist.txt:\n"); + } + Sys_FPrintf (SYS_WRN, "%s\n", (char*)lst->data); + } + } + + vfsClearFileDirList (&files); +} + +/* +================== +BuildShaderList +build a CStringList of shader names +================== +*/ +void BuildShaderList() +{ + int count; + char filename[1024]; + char *pBuff; + char dirstring[NAME_MAX]; + int nLen; + if (l_shaderfiles!=NULL) + { + g_slist_free(l_shaderfiles); + l_shaderfiles = NULL; + } + + if (g_pGameDescription->mGameFile != "hl.game") + { + strcpy(filename, g_pGameDescription->mShaderlist.GetBuffer()); + count = vfsGetFileCount(filename, 0 ); + if (count==0) + { + Sys_FPrintf(SYS_ERR, "Couldn't find '%s'\n", g_pGameDescription->mShaderlist.GetBuffer()); + return; + } + // NOTE TTimo we use vfsGetFullPath solely to get the full path of the shader list we are gonna load + // but we actually send the relative path to vfsLoadFile + // so let's hope there is no disparity between the two functions + if (!vfsGetFullPath(filename, 0, 0)) + { + Sys_FPrintf(SYS_ERR, "Couldn't find full path for '%s'\n", g_pGameDescription->mShaderlist.GetBuffer()); + Sys_FPrintf(SYS_ERR, "did you hit bug http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 ?\n"); + return; + } + Sys_Printf("Parsing shader files from %s\n", vfsGetFullPath(filename, 0, 0)); + nLen = vfsLoadFile (filename, reinterpret_cast(&pBuff), 0); + if (nLen > 0) + { + StartTokenParsing(pBuff); + nLen = 0; + while (GetToken(true)) + { + GSList *tmp; + bool found = false; + + // each token should be a shader filename + sprintf(dirstring, "%s.shader", token); + + for (tmp = l_shaderfiles; tmp != NULL; tmp = tmp->next) + { + if (!strcmp (dirstring, (char*)tmp->data)) + { + found = true; + Sys_FPrintf(SYS_WRN, "duplicate entry \"%s\" in shaderlist.txt\n", (char*)tmp->data); + break; + } + } + + if (!found) + { + l_shaderfiles = g_slist_append (l_shaderfiles, strdup (dirstring)); + nLen++; + } + } + g_free(pBuff); + } + } +} + +/* +================== +FillTextureMenu + +================== +*/ +void ClearGSList (GSList* lst) +{ + GSList *p = lst; + while (p) + { + free (p->data); + p = g_slist_remove (p, p->data); + } +} + +void FillTextureMenu (GSList** pArray) +{ + GtkWidget *menu, *sep, *item; // point to the Textures GtkMenu and to the last separator + GList *lst; + GSList *texdirs = NULL; + GSList *texdirs_tmp = NULL; + GSList *p; + char dirRoot[NAME_MAX]; + // this is an index used to count the number of texture items (for splitting/avoiding to get out of window) + // we start with a != 0 value to compensate for the initial number of items in the texture menu + int nMenuCount = 12; + + // delete everything + menu = GTK_WIDGET (g_object_get_data (G_OBJECT (g_qeglobals_gui.d_main_window), "menu_textures")); + sep = GTK_WIDGET (g_object_get_data (G_OBJECT (g_qeglobals_gui.d_main_window), "menu_textures_separator")); + lst = g_list_find (gtk_container_children (GTK_CONTAINER (menu)), sep); + while (lst->next) + { + // these delete functions are recursive, it's gonna free all submenus + gtk_widget_destroy (GTK_WIDGET (lst->next->data)); + // lst is no longer relevant, need to get it again + lst = g_list_find (gtk_container_children (GTK_CONTAINER (menu)), sep); + } + + texture_nummenus = 0; + + // add everything + if (!g_qeglobals.d_project_entity) + return; + + // scan texture dirs and pak files only if not restricting to shaderlist + if (!g_PrefsDlg.m_bTexturesShaderlistOnly) + { + texdirs_tmp = vfsGetDirList ("textures/"); + for (p=texdirs_tmp; p; p=g_slist_next(p)) + { + // Hydra: erm, this didn't used to do anything except leak memory... + // For Halflife support this is required to work however. + // g_slist_append(texdirs, p->data); + texdirs = g_slist_append(texdirs, strdup((char *)p->data)); + } + vfsClearFileDirList (&texdirs_tmp); + } + + // scan the shaders in shaderlist.txt + BuildShaderList (); + PreloadShaders (); + DumpUnreferencedShaders (); + while (l_shaderfiles != NULL) + { + char shaderfile[PATH_MAX]; + gboolean found = FALSE; + + ExtractFileName ((char*)l_shaderfiles->data, shaderfile); + StripExtension (shaderfile); + g_strdown (shaderfile); + + for (GSList *tmp = texdirs; tmp; tmp = g_slist_next (tmp)) + if (!strcasecmp ((char*)tmp->data, shaderfile)) + { + found = TRUE; + break; + } + + if (!found) + texdirs = g_slist_prepend (texdirs, strdup (shaderfile)); + + free (l_shaderfiles->data); + l_shaderfiles = g_slist_remove (l_shaderfiles, l_shaderfiles->data); + } + + // sort the list + texdirs = g_slist_sort (texdirs, (GCompareFunc)strcmp); + + GSList *temp = texdirs; + while (temp) + { + char* ptr = strchr ((char*)temp->data, '_'); + + // do we shrink the menus? + if (ptr != NULL) + { + // extract the root + strcpy (dirRoot, (char*)temp->data); + dirRoot[ptr - (char*)temp->data + 1] = 0; + + // we shrink only if we have at least two things to shrink :-) + if (temp->next && (strstr ((char*)temp->next->data, dirRoot) == (char*)temp->next->data)) + { + GtkWidget *pSubMenu = gtk_menu_new (); + GtkWidget *pSubMenuRef = pSubMenu; + // keep going... + do + { + item = gtk_menu_item_new_with_label ((char*)temp->data); + gtk_widget_show (item); + CheckMenuSplitting (pSubMenu); + gtk_container_add (GTK_CONTAINER (pSubMenu), item); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (CMD_TEXTUREWAD+texture_nummenus)); + + strcpy (texture_menunames[texture_nummenus], (char*)temp->data); + strcat (texture_menunames[texture_nummenus], "/"); + if (pArray) + *pArray = g_slist_append (*pArray, strdup ((char*)temp->data)); + if (++texture_nummenus == MAX_TEXTUREDIRS) + { + Sys_Printf("WARNING: max texture directories count has been reached!\n"); + // push submenu and get out + item = gtk_menu_item_new_with_label (dirRoot); + gtk_widget_show (item); + gtk_container_add (GTK_CONTAINER (menu), item); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), pSubMenu); + ClearGSList (texdirs); + return; + } + temp = temp->next; + } + while (temp && (strstr((char*)temp->data, dirRoot)==temp->data)); + + ptr = strchr (dirRoot, '_'); + *ptr = 0; + item = gtk_menu_item_new_with_label (dirRoot); + gtk_widget_show (item); + CheckMenuSplitting (menu); + gtk_container_add (GTK_CONTAINER (menu), item); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), pSubMenuRef); + continue; + } + } + + item = gtk_menu_item_new_with_label ((char*)temp->data); + gtk_widget_show (item); + CheckMenuSplitting (menu); + gtk_container_add (GTK_CONTAINER (menu), item); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (CMD_TEXTUREWAD+texture_nummenus)); + + strcpy (texture_menunames[texture_nummenus], (char*)temp->data); + strcat (texture_menunames[texture_nummenus], "/"); + if (pArray) + *pArray = g_slist_append (*pArray, strdup ((char*)temp->data)); + if (++texture_nummenus == MAX_TEXTUREDIRS) + { + Sys_Printf("WARNING: max texture directories count has been reached!\n"); + ClearGSList (texdirs); + return; + } + + temp = temp->next; + } + ClearGSList (texdirs); +} + +/* +============== +Texture_ShowDirectory +relies on texture_directory global for the directory to use +called by + void Texture_ShowDirectory (int menunum, bool bLinked) + void Texture_ShowDirectory (char* pPath, bool bLinked) +1) Load the shaders for the given directory +2) Scan the remaining texture, load them and assign them a default shader (the "noshader" shader) +NOTE: when writing a texture plugin, or some texture extensions, this function may need to be overriden, and made + available through the IShaders interface +NOTE: for texture window layout: + all shaders are stored with alphabetical order after load + previously loaded and displayed stuff is hidden, only in-use and newly loaded is shown + ( the GL textures are not flushed though) +============== +*/ +void Texture_ShowDirectory () +{ + char name[1024]; + char dirstring[1024]; + CString strTemp; + int shaders_count = 0; + int textures_count = 0; + GSList *files = NULL, *temp; + + g_bScreenUpdates = false; + + // refresh the in-use textures: that will clear the IsDisplayed flag on unused stuff + // and leave it on in-use so they'll still be displayed + Texture_ShowInuse(); + // and textures loaded in the following lines will be displayed as well... + // NOTE: shaders that are not in use but have been loaded previously are still in memory. But they don't get displayed. + + g_qeglobals.d_texturewin.originy = 0; + // load texture_directory.shader + // NOTE: because of above call to Texture_ClearInuse, g_ActiveShaders will have the newly loaded shaders only + // we'll use that later to check if textures have a shader associated or not + // NOTE: all shaders loaded through QERApp_LoadShadersFromDir will get their InUse flag to True, we'll need a call to Texture_ShowInUse for later cleanup/adjustment + // NOTE: QERApp_LoadShadersFromDir has two criterions for loading a shader: + // the shaderfile is texture_directory (like "museum" will load everything in museum.shader) + // the shader name contains texture_directory (like "base_floor" will load museum.shader::base_floor/concfloor_rain) + shaders_count = QERApp_LoadShadersFromDir(texture_directory); + // load remaining texture files + // if a texture is already in use to represent a shader, ignore it + + // need this function "GSList *lst SynapseServer::GetMinorList(char *major_name);" + + sprintf (dirstring, "textures/%s", texture_directory); + g_ImageManager.BeginExtensionsScan(); + const char* ext; + while(ext=g_ImageManager.GetNextExtension()) + { + files = g_slist_concat(files, vfsGetFileList (dirstring, ext)); + } + + for (temp = files; temp; temp = temp->next) + { + sprintf(name, "%s%s", texture_directory, (char*)temp->data); + + StripExtension (name); + strTemp = name; + strTemp.MakeLower(); + + if (strTemp.Find(".specular") >= 0 || + strTemp.Find(".glow") >= 0 || + strTemp.Find(".bump") >= 0 || + strTemp.Find(".diffuse") >= 0 || + strTemp.Find(".blend") >= 0 || + strTemp.Find(".alpha") >= 0) + continue; + + // avoid ever loading a texture name with spaces + if (strTemp.Find(" ") >= 0) + { + Sys_FPrintf(SYS_WRN, "WARNING: Skipping texture name with spaces [%s]\n", strTemp.GetBuffer()); + continue; + } + + // build a texture name that fits the conventions for qtexture_t::name + char stdName[1024]; + sprintf( stdName, "textures/%s", name ); + // check if this texture doesn't have a shader + if (!QERApp_ActiveShader_ForTextureName( stdName )) + { + QERApp_CreateShader_ForTextureName (stdName); + textures_count++; + } + } + + Sys_Printf("Loaded %d shaders and created default shader for %d orphan textures.\n", + shaders_count, textures_count ); + + vfsClearFileDirList (&files); + + // sort for displaying + QERApp_SortActiveShaders(); + + sprintf (name, "Textures: %s", texture_directory); + gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_entity), name); + + // select the first texture in the list + if (!g_qeglobals.d_texturewin.texdef.GetName()[0]) + SelectTexture (16, g_qeglobals.d_texturewin.height -16, false); + + g_bScreenUpdates = true; + + Sys_UpdateWindows (W_TEXTURE); +} + +/* +============== +Texture_ShowDirectory +1) Load the shaders for the given directory +2) Scan the remaining texture, load them and assign them a default shader (the "noshader" shader) +NOTE: when writing a texture plugin, or some texture extensions, this function may need to be overriden, and made + available through the IShaders interface +============== +*/ +void Texture_ShowDirectory (int menunum) +{ + strcpy (texture_directory, texture_menunames[menunum-CMD_TEXTUREWAD]); + Texture_ShowDirectory(); +} + +// scroll origin so the current texture is completely on screen +// if current texture is not displayed, nothing is changed +void Texture_ResetPosition() +{ + qtexture_t *q; + int x,y; + + //this shouldn't ever happen, we startup with notex + if (!g_qeglobals.d_texturewin.texdef.GetName()[0]) { + return; + } + + // otherwise position with current texture shown + // this used to be in Texture_SetTexture + Texture_StartPos (); + while (1) + { + // NOTE: return value is == pCurrentShader and pCurrentShader->getTexture == current_texture + Texture_NextPos (&x, &y); + q = current_texture; + // if the current texture never found (because // 'show shaders' is off, + // for example), do nothing + if (!q) + break; + + int nHeight = (int)(q->height * ((float)g_PrefsDlg.m_nTextureScale / 100)); + // we have found when texdef->name and the shader name match + // NOTE: as everywhere else for our comparisons, we are not case sensitive + if (!strcmpi( g_qeglobals.d_texturewin.texdef.GetName(), pCurrentShader->getName() )) + { + // take care of calls before initialized + if ( !g_qeglobals.d_texturewin.height) { + g_qeglobals.d_texturewin.originy = 0; + break; + } + // if the bottom of our selected texture will fit with origin 0, use that + // to prevent scrolling uglyness (stuff scrolled off screen when + // everything would fit) + if ( -(y -nHeight-2*FONT_HEIGHT) < g_qeglobals.d_texturewin.height) { + g_qeglobals.d_texturewin.originy = 0; + break; + } + // if current is off the top of the window, move it to the top + if (y > g_qeglobals.d_texturewin.originy) + { + g_qeglobals.d_texturewin.originy = y; + break; + } + + // if current is off the bottom, put it on the bottom + if (y-nHeight-2*FONT_HEIGHT < g_qeglobals.d_texturewin.originy-g_qeglobals.d_texturewin.height) + { + g_qeglobals.d_texturewin.originy = y-nHeight-2*FONT_HEIGHT+g_qeglobals.d_texturewin.height; + break; + } + // if we made it here, it should already be in view + break; + } + } + Sys_UpdateWindows (W_TEXTURE); +} + +/* +============== +Texture_ShowAll +will set the IsDisplayed flag on all the active shaders, so we see everything that's currently in memory +============== +*/ +void Texture_ShowAll() +{ + char name[1024]; + +#ifdef _DEBUG + if (g_bShowAllShaders) + Sys_Printf("WARNING: already showing all shaders\n"); +#endif + QERApp_ActiveShaders_SetDisplayed(true); + g_bShowAllShaders = true; + // put some information in the texture window title? + sprintf (name, "Textures: in use"); + gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_entity), name); + Sys_UpdateWindows (W_TEXTURE); +} + +/* +============== +Texture_ShowInuse +clear all IsDisplayed flags +scan the map, set IsInUse (will set IsDisplayed on the way) +NOTE: don't sort the textures, don't update the windows (it's used in several contexts, not always necessary to do either) +============== +*/ +void WINAPI Texture_ShowInuse (void) +{ + face_t *f; + brush_t *b; + char name[1024]; + + g_qeglobals.d_texturewin.originy = 0; + + // purge + QERApp_ActiveShaders_SetDisplayed(false); + // scan and only display in-use stuff + Sys_Status("Selecting active textures", 0); + + for (b=active_brushes.next ; b != NULL && b != &active_brushes ; b=b->next) + { + if (b->patchBrush) + { + b->pPatch->pShader->SetInUse(true); + } else + { + for (f=b->brush_faces ; f ; f=f->next) + { + f->pShader->SetInUse(true); + } + } + } + for (b=selected_brushes.next ; b != NULL && b != &selected_brushes ; b=b->next) + { + if (b->patchBrush) + { + b->pPatch->pShader->SetInUse(true); + } else + { + for (f=b->brush_faces ; f ; f=f->next) + { + f->pShader->SetInUse(true); + } + } + } + + // we are no longer showing everything + g_bShowAllShaders = false; + // put some information in the texture window title? + sprintf (name, "Textures: in use"); + gtk_window_set_title (GTK_WINDOW (g_qeglobals_gui.d_entity), name); + + + // select the first texture in the list + if (!g_qeglobals.d_texturewin.texdef.GetName()[0]) + { + SelectTexture (16, g_qeglobals.d_texturewin.height -16, false); + } +} + +void Texture_ShowStartupShaders() +{ + if (g_PrefsDlg.m_nShader == PrefsDlg::SHADER_COMMON) + { + // RIANT + // HACK FOR JK2 SUPPORT + if (g_pGameDescription->mGameFile == "jk2.game" || g_pGameDescription->mGameFile == "ja.game") + { + strcpy (texture_directory, "system/"); + } + // RIANT + // HACK FOR SOF2 SUPPORT + else if (g_pGameDescription->mGameFile == "sof2.game") + { + strcpy (texture_directory, "tools/"); + } + else strcpy (texture_directory, "common/"); + Texture_ShowDirectory (); + } + + if (g_PrefsDlg.m_nShader == PrefsDlg::SHADER_ALL) { + int count; + char filename[1024]; + char *pBuff; + char dirstring[NAME_MAX]; + int nLen; + GSList *shaderfiles = NULL; + + strcpy(filename, g_pGameDescription->mShaderlist.GetBuffer()); + count = vfsGetFileCount(filename, 0); + if (count == 0) + { + Sys_FPrintf(SYS_ERR, "Couldn't find '%s'\n", g_pGameDescription->mShaderlist.GetBuffer()); + return; + } + + if (!vfsGetFullPath(filename, 0, 0)) + { + Sys_FPrintf(SYS_ERR, "Couldn't find full path for '%s'\n", g_pGameDescription->mShaderlist.GetBuffer()); + Sys_FPrintf(SYS_ERR, "did you hit bug http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 ?\n"); + return; + } + + Sys_Printf("Parsing shader files from %s\n", vfsGetFullPath(filename, 0, 0)); + nLen = vfsLoadFile (filename, reinterpret_cast(&pBuff), 0); + if (nLen > 0) + { + StartTokenParsing(pBuff); + nLen = 0; + while (GetToken(true)) + { + GSList *tmp; + bool found = false; + + // each token should be a shader filename + sprintf(dirstring, "%s.shader", token); + + for (tmp = shaderfiles; tmp != NULL; tmp = tmp->next) + { + if (!strcmp (dirstring, (char*)tmp->data)) + { + found = true; + Sys_FPrintf(SYS_WRN, "duplicate entry \"%s\" in shaderlist.txt\n", (char*)tmp->data); + break; + } + } + + if (!found) + { + shaderfiles = g_slist_append (l_shaderfiles, strdup (dirstring)); + strcpy (texture_directory, dirstring); + Texture_ShowDirectory (); + nLen++; + } + } + g_free(pBuff); + } + } +} + +/* +============================================================================ + +TEXTURE LAYOUT + +TTimo: now based on a rundown through all the shaders +nActiveShadersCount: number of shader that have a qtexture_t and may be displayed in the tex window +nCurrentShader: index of active shader that has the current_texture +pCurrentShader: IShader* for current shader +NOTE: we expect the Active shaders count doesn't change during a Texture_StartPos .. Texture_NextPos cycle + otherwise we may need to rely on a list instead of an array storage +============================================================================ +*/ + +void Texture_StartPos (void) +{ + //++timo TODO: check use of current_texture and current_row? + current_x = 8; + current_y = -8; + current_row = 0; + nActiveShadersCount = QERApp_GetActiveShaderCount(); + nCurrentShader = -1; + current_texture = NULL; + pCurrentShader = NULL; +} + +// if texture_showinuse jump over non in-use textures +// it's not very clear what should be done here and what in Texture_Draw .. maybe merging the two would do good +IShader* Texture_NextPos (int *x, int *y) +{ + qtexture_t* q; + while (1) + { + if (nCurrentShader >= nActiveShadersCount - 1) + { + // no more shaders + current_texture = NULL; + pCurrentShader = NULL; + return NULL; + } + nCurrentShader++; + pCurrentShader = QERApp_ActiveShader_ForIndex(nCurrentShader); + if (pCurrentShader == NULL) + { + Sys_Printf("ERROR: unexpected pCurrentShader == NULL in Texture_NextPos\n"); + return NULL; + } + current_texture = pCurrentShader->getTexture(); + q = current_texture; + + if (!q) + { + Sys_Printf("WARNING: found an IShader without qtexture_t in Texture_NextPos\n"); + return NULL; + } + + /* + Never show anything other than "textures/" path, + This is for q1/q2/q3 .map format, which expects "textures/" path on everything we apply + */ + if(strncmp(pCurrentShader->getName(), "textures/", 9) != 0) + continue; + + // don't show shaders? + if (!(g_PrefsDlg.m_bShowShaders || pCurrentShader->IsDefault())) + continue; + + if (g_PrefsDlg.m_bTextureWindow) + { + // some basic filtering + if (!g_pParentWnd->GetTexWnd()->CheckFilter( pCurrentShader->getName() )) + continue; + } + + //++timo FIXME: texture_showinuse is useless? with the menu and reload we just refresh the IsDisplayed flag + // but the IsInUse is only relevant to draw the green outline + if (pCurrentShader->IsDisplayed()) + break; + + continue; + } + + int nWidth = (int)(q->width * ((float)g_PrefsDlg.m_nTextureScale / 100)); + int nHeight = (int)(q->height * ((float)g_PrefsDlg.m_nTextureScale / 100)); + if (current_x + nWidth > g_qeglobals.d_texturewin.width-8 && current_row) + { // go to the next row unless the texture is the first on the row + current_x = 8; + current_y -= current_row + FONT_HEIGHT + 4; + current_row = 0; + } + + *x = current_x; + *y = current_y; + + // Is our texture larger than the row? If so, grow the + // row height to match it + + if (current_row < nHeight) + current_row = nHeight; + + // never go less than 64, or the names get all crunched up + current_x += nWidth < 64 ? 64 : nWidth; + current_x += 8; + + return pCurrentShader; +} + +/* +============================================================================ + + MOUSE ACTIONS + +============================================================================ +*/ + +static int textures_cursorx, textures_cursory; + +/* +============ +Texture_SetTexture + +brushprimit_texdef must be understood as a qtexture_t with width=2 height=2 ( the default one ) +============ +*/ + +//++timo NOTE: this is a mix of Shader module stuff and texture explorer +// it might need to be split in parts or moved out .. dunno +void WINAPI Texture_SetTexture (texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef *pTexdef, bool bSetSelection ) +{ + if (texdef->GetName()[0] == '(') + { + Sys_Status("Can't select an entity texture", 0); + return; + } + g_qeglobals.d_texturewin.texdef = *texdef; + g_qeglobals.d_texturewin.texdef.flags &= ~SURF_KEEP; + g_qeglobals.d_texturewin.texdef.contents &= ~CONTENTS_KEEP; + // store the shader pointer + // NOTE: maybe passing the shader pointer would help? + g_qeglobals.d_texturewin.pShader->DecRef(); + g_qeglobals.d_texturewin.pShader = QERApp_Shader_ForName(texdef->GetName()); + g_qeglobals.d_texturewin.pShader->IncRef(); + // set this shader as in use + g_qeglobals.d_texturewin.pShader->SetInUse( true ); + // store the texture coordinates for new brush primitive mode + // be sure that all the callers are using the default 2x2 texture + if (g_qeglobals.m_bBrushPrimitMode) + { + g_qeglobals.d_texturewin.brushprimit_texdef = *brushprimit_texdef; + } + + g_dlgFind.updateTextures(texdef->GetName()); + if (!g_dlgFind.isOpen() && bSetSelection) + { + Select_SetTexture(texdef,brushprimit_texdef,bFitScale); + } + + //plugins: send a message telling that the selected texture may have changed + DispatchRadiantMsg( RADIANT_TEXTURE ); + + // scroll origin so the texture is completely on screen + // takes texdef from g_qeglobals.d_texturewin.texdef, set above + Texture_ResetPosition(); +} + +void ViewShader(const char *pFile, const char *pName) +{ + // ask the vfs to build the full path to the file + // (i.e. the first one found) + char *fullName = vfsGetFullPath(pFile,0,0); + if (fullName == NULL) + { + Sys_FPrintf (SYS_ERR, "Couldn't get a full path to the shader file: %s\n", pFile); + return; + } + + char* pBuff = NULL; + int nSize = vfsLoadFullPathFile(fullName, reinterpret_cast(&pBuff)); + if (nSize <= 0) + { + Sys_FPrintf (SYS_ERR, "Failed to load shader file %s\n", fullName); + return; + } + // look for the shader declaration + int nStart; + CString strFind = pName; + CString strLook = pBuff; + strLook.MakeLower(); + strFind.MakeLower(); + // offset used when jumping over commented out definitions + int nOffset = 0; + while (true) + { + nStart = strLook.Find(strFind, nOffset); + if (nStart == -1) + break; + // we have found something, maybe it's a commented out shader name? + char *strCheck = new char[strLook.GetLength()+1]; + strcpy( strCheck, strLook.GetBuffer() ); + strCheck[nStart] = 0; + char *pCheck = strrchr( strCheck, '\n' ); + // if there's a commentary sign in-between we'll continue + if (pCheck && strstr( pCheck, "//" )) + { + delete[] strCheck; + nOffset = nStart + 1; + continue; + } + delete[] strCheck; + nOffset = nStart; + break; + } + // now close the file + g_free(pBuff); + + DoTextEditor (fullName, nOffset); +} + +/* +============== +SelectTexture + + By mouse click +============== +*/ +void SelectTexture (int mx, int my, bool bShift, bool bFitScale) +{ + int x, y; + qtexture_t *q; + texdef_t tex; + brushprimit_texdef_t brushprimit_tex; + + my += g_qeglobals.d_texturewin.originy-g_qeglobals.d_texturewin.height; + + Texture_StartPos (); + while (1) + { + // NOTE: return value is == pCurrentShader and pCurrentShader->getTexture == current_texture + Texture_NextPos (&x, &y); + q = current_texture; + if (!q) + break; + int nWidth = (int)(q->width * ((float)g_PrefsDlg.m_nTextureScale / 100)); + int nHeight = (int)(q->height * ((float)g_PrefsDlg.m_nTextureScale / 100)); + if (mx > x && mx - x < nWidth + && my < y && y - my < nHeight + FONT_HEIGHT) + { + if (bShift) + { + if (pCurrentShader->IsDefault()) + Sys_Printf("ERROR: %s is not a shader, it's a texture.\n", pCurrentShader->getName() ); + else + ViewShader( pCurrentShader->getShaderFileName(), pCurrentShader->getName() ); + } + else + { + memset (&tex, 0, sizeof(tex)); + memset (&brushprimit_tex, 0, sizeof(brushprimit_tex)); + if (g_qeglobals.m_bBrushPrimitMode) + { + // brushprimit fitted to a 2x2 texture + brushprimit_tex.coords[0][0] = 1.0f; + brushprimit_tex.coords[1][1] = 1.0f; + } + else + { + tex.scale[0] = g_pGameDescription->mTextureDefaultScale; + tex.scale[1] = g_pGameDescription->mTextureDefaultScale; + } + tex.flags = pCurrentShader->getFlags(); + // TTimo - shader code cleanup + // texdef.name is the name of the shader, not the name of the actual texture file + tex.SetName(pCurrentShader->getName()); + // NOTE WARNING: Texture_SetTexture uses Texture_NextPos stuff to move the window position on to the texture + // if there's some kind of fuckup in Texture_SetTexture you may end up with different pCurrentShader or even pCurrentShader == NULL + // so we just consider pCurrentShader and current_texture are not valid after this point + IShader *pAuxShader = pCurrentShader; + Texture_SetTexture ( &tex, &brushprimit_tex, bFitScale, NULL); // Nurail + CString strTex; + CString strName; + // if shader, print shader name, otherwise texture name + //++timo FIXME: maybe CShader needs some properties between color / default / actual shader +#ifdef _DEBUG + // this one is never supposed to be set as current one + if (pAuxShader->IsColor()) + Sys_Printf("ERROR: unexpected pCurrentShader->IsColor() in SelectTexture\n"); +#endif + // NOTE: IsColor is false, IsDefault the only remaining property + if (pAuxShader->IsDefault()) + { + strName = q->name; + // remove the "textures/" if needed + if (strName.Find("textures/")!=-1) + strName = strName.Mid(9); + } + else + { + strName = pAuxShader->getName(); + } + strTex.Format("%s W: %i H: %i", strName.GetBuffer(), q->width, q->height); + g_pParentWnd->SetStatusText(3, strTex); + } + return; + } + } + + Sys_Status("Did not select a texture", 0); +} + +/* +============== +Texture_MouseDown +============== +*/ +void Texture_MouseDown (int x, int y, int buttons) +{ + Sys_GetCursorPos (&textures_cursorx, &textures_cursory); + + // lbutton = select texture + if (buttons == MK_LBUTTON || buttons == (MK_LBUTTON | MK_SHIFT) || buttons == (MK_LBUTTON | MK_CONTROL)) + { + SelectTexture (x, g_qeglobals.d_texturewin.height - 1 - y, buttons & MK_SHIFT, buttons & MK_CONTROL); + UpdateSurfaceDialog(); + UpdatePatchInspector(); + } +} + +/* +============== +Texture_MouseMoved +============== +*/ + +void Texture_MouseMoved (int x, int y, int buttons) +{ + int scale = 1; + + if ( buttons & MK_SHIFT ) + scale = 4; + + // rbutton = drag texture origin + if (buttons & MK_RBUTTON) + { + Sys_GetCursorPos (&x, &y); + if ( y != textures_cursory) + { + g_qeglobals.d_texturewin.originy += ( y-textures_cursory) * scale; + if (g_qeglobals.d_texturewin.originy > 0) + g_qeglobals.d_texturewin.originy = 0; + Sys_SetCursorPos (textures_cursorx, textures_cursory); + + // (g_PrefsDlg.m_bTextureScrollbar && g_qeglobals_gui.d_texture_scroll != NULL) + // fixes broken texture scrolling when scrollbar is disabled + GtkAdjustment *vadjustment = gtk_range_get_adjustment (GTK_RANGE (g_qeglobals_gui.d_texture_scroll)); + gtk_adjustment_set_value (vadjustment, abs(g_qeglobals.d_texturewin.originy)); + // + } + return; + } +} + +/* +============================================================================ + +DRAWING + +============================================================================ +*/ + +int imax(int iFloor, int i) { if (i>iFloor) return iFloor;return i;} + +/* +============ +Texture_Draw +TTimo: relying on the shaders list to display the textures +we must query all qtexture_t* to manage and display through the IShaders interface +this allows a plugin to completely override the texture system +============ +*/ +void Texture_Draw (int width, int height) +{ + int x, y, last_y = 0, last_height = 0, nWidth, nHeight; + qtexture_t *q; + char *name; + + qglClearColor (g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][0], + g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][1], + g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][2], 0); + qglViewport (0,0,width,height); + qglMatrixMode(GL_PROJECTION); + qglLoadIdentity (); + + qglClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + qglDisable (GL_DEPTH_TEST); + qglDisable(GL_BLEND); + qglOrtho (0, width, g_qeglobals.d_texturewin.originy-height, g_qeglobals.d_texturewin.originy, -100, 100); + qglEnable (GL_TEXTURE_2D); + + qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + g_qeglobals.d_texturewin.width = width; + g_qeglobals.d_texturewin.height = height; + + Texture_StartPos(); + for (;;) + { + // NOTE: return value is == pCurrentShader and pCurrentShader->getTexture == current_texture + Texture_NextPos (&x, &y); + q = current_texture; + if (!q) + break; + + nWidth = (int)(q->width * ((float)g_PrefsDlg.m_nTextureScale / 100)); + nHeight = (int)(q->height * ((float)g_PrefsDlg.m_nTextureScale / 100)); + + if (y != last_y) + { + last_y = y; + last_height = 0; + } + last_height = MAX (nHeight, last_height); + + // Is this texture visible? + if ((y-nHeight-FONT_HEIGHT < g_qeglobals.d_texturewin.originy) + && (y > g_qeglobals.d_texturewin.originy - height)) + { + // borders rules: + // if it's the current texture, draw a thick red line, else: + // shaders have a white border, simple textures don't + // if !texture_showinuse: (some textures displayed may not be in use) + // draw an additional square around with 0.5 1 0.5 color + if (!strcmpi(g_qeglobals.d_texturewin.texdef.GetName(), pCurrentShader->getName())) + { + qglLineWidth (3); + qglColor3f (1,0,0); + qglDisable (GL_TEXTURE_2D); + + qglBegin (GL_LINE_LOOP); + qglVertex2f (x-4,y-FONT_HEIGHT+4); + qglVertex2f (x-4,y-FONT_HEIGHT-nHeight-4); + qglVertex2f (x+4+nWidth,y-FONT_HEIGHT-nHeight-4); + qglVertex2f (x+4+nWidth,y-FONT_HEIGHT+4); + qglEnd (); + + qglEnable (GL_TEXTURE_2D); + qglLineWidth (1); + } + else + { + qglLineWidth (1); + // shader border: + if (!pCurrentShader->IsDefault()) + { + qglColor3f (1,1,1); + qglDisable (GL_TEXTURE_2D); + + qglBegin (GL_LINE_LOOP); + qglVertex2f (x-1,y+1-FONT_HEIGHT); + qglVertex2f (x-1,y-nHeight-1-FONT_HEIGHT); + qglVertex2f (x+1+nWidth,y-nHeight-1-FONT_HEIGHT); + qglVertex2f (x+1+nWidth,y+1-FONT_HEIGHT); + qglEnd (); + qglEnable (GL_TEXTURE_2D); + } + + // highlight in-use textures + if (pCurrentShader->IsInUse()) + { + qglColor3f (0.5,1,0.5); + qglDisable (GL_TEXTURE_2D); + qglBegin (GL_LINE_LOOP); + qglVertex2f (x-3,y+3-FONT_HEIGHT); + qglVertex2f (x-3,y-nHeight-3-FONT_HEIGHT); + qglVertex2f (x+3+nWidth,y-nHeight-3-FONT_HEIGHT); + qglVertex2f (x+3+nWidth,y+3-FONT_HEIGHT); + qglEnd (); + qglEnable (GL_TEXTURE_2D); + } + } + + // Draw the texture + qglBindTexture (GL_TEXTURE_2D, q->texture_number); + QE_CheckOpenGLForErrors(); + qglColor3f (1,1,1); + qglBegin (GL_QUADS); + qglTexCoord2f (0,0); + qglVertex2f (x,y-FONT_HEIGHT); + qglTexCoord2f (1,0); + qglVertex2f (x+nWidth,y-FONT_HEIGHT); + qglTexCoord2f (1,1); + qglVertex2f (x+nWidth,y-FONT_HEIGHT-nHeight); + qglTexCoord2f (0,1); + qglVertex2f (x,y-FONT_HEIGHT-nHeight); + qglEnd (); + + // draw the texture name + qglDisable (GL_TEXTURE_2D); + qglColor3f (1,1,1); + + qglRasterPos2f (x, y-FONT_HEIGHT+2); + + // don't draw the directory name + name = (char*)pCurrentShader->getName(); + name += strlen(name); + while(name != (char*)pCurrentShader->getName() && *(name-1) != '/' && *(name-1) != '\\') + name--; + + gtk_glwidget_print_string(name); + qglEnable (GL_TEXTURE_2D); + } + } + + g_qeglobals.d_texturewin.m_nTotalHeight = abs(y) + last_height + FONT_HEIGHT + 4; + + // reset the current texture + qglBindTexture(GL_TEXTURE_2D, 0); + qglFinish(); +} + +//++timo seems we only know hard inits now.. +//void Texture_Init (bool bHardInit) +void Texture_Init() +{ + g_qeglobals.d_qtextures = NULL; + // initialize the qtexture map + if (g_qeglobals.d_qtexmap) + { + Sys_FPrintf(SYS_ERR, "TODO: delete g_qeglobals.d_qtexmap in Texture_Init\n"); + } + g_qeglobals.d_qtexmap = g_hash_table_new (g_str_hash, g_str_equal); + // initialize .. in some cases if no default texture / project loaded it crashes + memset( &g_qeglobals.d_texturewin.texdef, 0, sizeof(g_qeglobals.d_texturewin.texdef) ); + g_qeglobals.d_texturewin.texdef.SetName(SHADER_NOT_FOUND); + g_qeglobals.d_texturewin.pShader = QERApp_Shader_ForName(SHADER_NOT_FOUND); +} + +// FIXME TTimo this needs to move to the shader module along with l_shaderlist move +// preload shader files that have been listed in shaderlist.txt +void PreloadShaders() +{ + GSList *lst = l_shaderfiles; + Str shadername; + while (lst) + { + shadername = g_pGameDescription->mShaderPath; + shadername += (char*)lst->data; + QERApp_LoadShaderFile(shadername.GetBuffer()); + lst = lst->next; + } +} + +// TTimo: modified to expect the reletive path to the skin as input +// will look into pak files if necessary +// uses the shader code to load the texture Try_Texture_ForName +// modified SkinInfo accordingly to store the qtexture_t and shader name (reletive version) +// the .md3 have bundled filetype extension, but they don't fit with the actual data +// ex: models/mapobjects/gargoyle.tga doesn't exist, but models/mapobjects/gargoyle.jpg can be used instead +// so we remove the extension before load attempt +int WINAPI Texture_LoadSkin(char *pName, int *pnWidth, int *pnHeight) +{ + // byte *pic = NULL; + // byte *pic32 = NULL; + int nTex = -1; + qtexture_t *qtex; + SkinInfo *pInfo; + const char *pCleanName; + + int nSize = g_lstSkinCache.GetSize(); + pCleanName = QERApp_CleanTextureName( pName, false ); + for (int i = 0; i < nSize; i++) + { + SkinInfo *pInfo = reinterpret_cast(g_lstSkinCache.GetAt(i)); + if (pInfo) + { + if (stricmp(pCleanName, pInfo->m_strName) == 0) + { + return pInfo->m_nTextureBind; + } + } + } + + // if the load is successfull, we get back a qtexture_t + // we don't need to free it, it's in g_qeglobals.d_qtextures + // NOTE: we need to free the SkinInfo though.. + qtex = QERApp_Try_Texture_ForName( pCleanName ); + if (qtex) + { + nTex = qtex->texture_number; + pInfo = new SkinInfo(qtex->name, nTex, qtex); + } else + { + pInfo = new SkinInfo(pCleanName, -1, NULL); + } + g_lstSkinCache.Add(pInfo); + + return nTex; +} + +bool TexWnd::CheckFilter( const char* name ) +{ + const char* buf = gtk_entry_get_text (GTK_ENTRY (m_pFilter)); + if (strstr( name, buf ) != 0) + return true; + return false; +} + +// ============================================================================= +// static functions + +static void vertical_scroll (GtkWidget *widget, gpointer data) +{ + ((TexWnd*)data)->OnVScroll (); +} + +static void filter_changed (GtkWidget *widget, gpointer data) +{ + CString str; + str = gtk_entry_get_text (GTK_ENTRY (widget)); + ((TexWnd*)data)->UpdateFilter (str); +} + +// ============================================================================= +// TexWnd class + +TexWnd::TexWnd() +: GLWindow (FALSE) +{ + m_pFilter = NULL; + m_bNeedRange = true; +} + +TexWnd::~TexWnd() +{ +} + +void TexWnd::OnCreate () +{ + if (!MakeCurrent ()) + Error ("glMakeCurrent in TexWnd::OnCreate failed"); + + g_qeglobals_gui.d_texture = m_pWidget; + g_nTextureOffset = 0; + + GtkAdjustment *vadjustment = gtk_range_get_adjustment (GTK_RANGE (g_qeglobals_gui.d_texture_scroll)); + gtk_signal_connect (GTK_OBJECT (vadjustment), "value_changed", GTK_SIGNAL_FUNC (vertical_scroll), this); + + if (g_PrefsDlg.m_bTextureScrollbar) + gtk_widget_show (g_qeglobals_gui.d_texture_scroll); + else + gtk_widget_hide (g_qeglobals_gui.d_texture_scroll); + m_bNeedRange = true; + + gtk_signal_connect (GTK_OBJECT (m_pFilter), "changed", GTK_SIGNAL_FUNC (filter_changed), this); + if (g_PrefsDlg.m_bTextureWindow) + gtk_widget_show (m_pFilter); +} + +void TexWnd::UpdateFilter(const char* pFilter) +{ + g_bFilterEnabled = false; + if (pFilter) + { + g_strFilter = pFilter; + if (g_strFilter.GetLength() > 0) + g_bFilterEnabled = true; + QERApp_SortActiveShaders(); + } + Sys_UpdateWindows (W_TEXTURE); +} + +void TexWnd::OnSize (int cx, int cy) +{ + m_bNeedRange = true; +} + +void TexWnd::OnExpose () +{ + int nOld = g_qeglobals.d_texturewin.m_nTotalHeight; + if (!MakeCurrent ()) + { + Sys_Printf("ERROR: glXMakeCurrent failed..\n "); + Sys_Printf("Please restart Radiant if the Texture view is not working\n"); + } else + { + QE_CheckOpenGLForErrors(); + Texture_Draw (m_pWidget->allocation.width, m_pWidget->allocation.height - g_nTextureOffset); + QE_CheckOpenGLForErrors(); + SwapBuffers (); + } + if (g_PrefsDlg.m_bTextureScrollbar && (m_bNeedRange || g_qeglobals.d_texturewin.m_nTotalHeight != nOld)) + { + GtkAdjustment *vadjustment = gtk_range_get_adjustment (GTK_RANGE (g_qeglobals_gui.d_texture_scroll)); + + vadjustment->value = -g_qeglobals.d_texturewin.originy; + vadjustment->page_size = m_pWidget->allocation.height; + vadjustment->page_increment = m_pWidget->allocation.height/2; + vadjustment->step_increment = 20; + vadjustment->lower = 0; + vadjustment->upper = g_qeglobals.d_texturewin.m_nTotalHeight; + + gtk_signal_emit_by_name (GTK_OBJECT (vadjustment), "changed"); + + m_bNeedRange = false; + } +} + +void TexWnd::OnLButtonDown (guint32 flags, int pointx, int pointy) +{ + SetCapture (); + Texture_MouseDown (pointx, pointy - g_nTextureOffset, flags); +} + +void TexWnd::OnRButtonDown (guint32 flags, int pointx, int pointy) +{ + SetCapture (); + Texture_MouseDown (pointx, pointy - g_nTextureOffset, flags); +} + +void TexWnd::OnMButtonDown (guint32 flags, int pointx, int pointy) +{ + SetCapture (); + Texture_MouseDown (pointx, pointy - g_nTextureOffset, flags); +} + +void TexWnd::OnLButtonUp (guint32 flags, int pointx, int pointy) +{ + ReleaseCapture (); + // NOTE TTimo http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=23 + DragDropTexture (flags, pointx, pointy); +} + +void TexWnd::OnRButtonUp (guint32 flags, int pointx, int pointy) +{ + ReleaseCapture (); +} + +void TexWnd::OnMButtonUp (guint32 flags, int pointx, int pointy) +{ + ReleaseCapture (); +} + +void TexWnd::OnMouseMove (guint32 flags, int pointx, int pointy) +{ + Texture_MouseMoved (pointx, pointy - g_nTextureOffset, flags); + // if scrollbar is hidden, we don't seem to get an update + if( !g_PrefsDlg.m_bTextureScrollbar ) + RedrawWindow (); +} + +void TexWnd::OnVScroll () +{ + GtkAdjustment *vadjustment = gtk_range_get_adjustment (GTK_RANGE (g_qeglobals_gui.d_texture_scroll)); + + g_qeglobals.d_texturewin.originy = - (int)vadjustment->value; + RedrawWindow (); +} + +void TexWnd::UpdatePrefs() +{ + if (g_PrefsDlg.m_bTextureWindow) + gtk_widget_show (m_pFilter); + else + gtk_widget_hide (m_pFilter); + + if (g_PrefsDlg.m_bTextureScrollbar) + gtk_widget_show (g_qeglobals_gui.d_texture_scroll); + else + gtk_widget_hide (g_qeglobals_gui.d_texture_scroll); + m_bNeedRange = true; + RedrawWindow (); +} + +void TexWnd::FocusEdit() +{ + if (GTK_WIDGET_VISIBLE (m_pFilter)) + gtk_window_set_focus (GTK_WINDOW (g_pParentWnd->m_pWidget), m_pFilter); +} + +void TexWnd::OnMouseWheel(bool bUp) +{ + if (bUp) + { + if(g_qeglobals.d_texturewin.originy < 0) { + g_qeglobals.d_texturewin.originy += g_PrefsDlg.m_nWheelInc; + // clamp so we don't get jiggle if moved by less than scrollwheel increment + if(g_qeglobals.d_texturewin.originy > 0) { + g_qeglobals.d_texturewin.originy = 0; + } + } + } + else + { + if(g_qeglobals.d_texturewin.originy > (-g_qeglobals.d_texturewin.m_nTotalHeight + g_qeglobals.d_texturewin.height)) + g_qeglobals.d_texturewin.originy -= g_PrefsDlg.m_nWheelInc; + } + GtkAdjustment *vadjustment = gtk_range_get_adjustment (GTK_RANGE (g_qeglobals_gui.d_texture_scroll)); + gtk_adjustment_set_value (vadjustment, abs(g_qeglobals.d_texturewin.originy)); + + RedrawWindow(); +} + +// NOTE TTimo +// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=23 +void TexWnd::DragDropTexture (guint32 flags, int pointx, int pointy) +{ + // This gets called from leftmouse up event. We see if the mouseup is above + // the camwindow. If this is the case do a trace for a surface. If we hit a + // surface, texture it with the current texture. + + int m_ptXcheck, m_ptYcheck; + int m_ptX, m_ptY; + GtkWidget *widget; + gint x, y; + vec3_t dir; + float f, r, u; + int i; + + // we only want to catch a plain mouseevent + if (flags) + return; + + // see if we are above the camwindow + Sys_GetCursorPos (&m_ptX, &m_ptY); + + if (g_pParentWnd->CurrentStyle() == MainFrame::eFloating) + widget = g_pParentWnd->GetCamWnd()->m_pParent; + else + widget = g_pParentWnd->GetCamWnd()->GetWidget(); + + get_window_pos (widget, &x, &y); + + if (m_ptX < x || m_ptY < y || + m_ptX > x + widget->allocation.width || + m_ptY > y + widget->allocation.height) + return; + + // check if the camwindow isn't being partially hidden by another window at this point + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=187 + m_ptXcheck = m_ptX; + m_ptYcheck = m_ptY; + + if( g_pParentWnd->GetCamWnd()->GetWidget()->window != gdk_window_at_pointer( &m_ptXcheck, &m_ptYcheck ) ) + return; + + // calc ray direction + x = m_ptX - x; + y = g_pParentWnd->GetCamWnd()->Camera()->height - 1 - (m_ptY - y); + u = (float)( y - ( g_pParentWnd->GetCamWnd()->Camera()->height * .5f ) ) / ( g_pParentWnd->GetCamWnd()->Camera()->height * .5f ); + r = (float)( x - ( g_pParentWnd->GetCamWnd()->Camera()->width * .5f ) ) / ( g_pParentWnd->GetCamWnd()->Camera()->width * .5f ); + f = 1; + + for (i=0 ; i<3 ; i++) + dir[i] = g_pParentWnd->GetCamWnd()->Camera()->vpn[i] * f + + g_pParentWnd->GetCamWnd()->Camera()->vright[i] * r + + g_pParentWnd->GetCamWnd()->Camera()->vup[i] * u; + VectorNormalize (dir, dir); + + // do a trace for a surface + trace_t t; + + t = Test_Ray (g_pParentWnd->GetCamWnd()->Camera()->origin, dir, SF_SINGLEFACE); + + if (t.brush) + { + texdef_t tex; + brushprimit_texdef_t brushprimit_tex; + + memset (&tex, 0, sizeof(tex)); + memset (&brushprimit_tex, 0, sizeof(brushprimit_tex)); + if (g_qeglobals.m_bBrushPrimitMode) + { + // brushprimit fitted to a 2x2 texture + brushprimit_tex.coords[0][0] = 1.0f; + brushprimit_tex.coords[1][1] = 1.0f; + } else + { + tex.scale[0] = g_pGameDescription->mTextureDefaultScale; + tex.scale[1] = g_pGameDescription->mTextureDefaultScale; + } + tex.flags = g_qeglobals.d_texturewin.texdef.flags; + tex.value = g_qeglobals.d_texturewin.texdef.value; + tex.contents = g_qeglobals.d_texturewin.texdef.contents; + // TTimo - shader code cleanup + // texdef.name is the name of the shader, not the name of the actual texture file + tex.SetName(g_qeglobals.d_texturewin.texdef.GetName()); + + Undo_Start("set face textures"); + Undo_AddBrush(t.brush); + SetFaceTexdef (t.face, &tex, &brushprimit_tex, false, NULL ); + Brush_Build(t.brush, false); + Undo_EndBrush(t.brush); + Undo_End(); + + Sys_UpdateWindows (W_CAMERA); + g_pParentWnd->OnTimer (); + } +} diff --git a/radiant/ui.cpp b/radiant/ui.cpp index 661c6f9b..83966dd9 100644 --- a/radiant/ui.cpp +++ b/radiant/ui.cpp @@ -1,268 +1,268 @@ -/* -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 -*/ - -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// implementation of IMessaging specific interface -// - -#include "stdafx.h" - -CPtrArray l_Listeners[RADIANT_MSGCOUNT]; -CPtrArray l_WindowListeners; -CXYWndWrapper l_XYWndWrapper; - -// CGtkWindow implementation ------------------------------------- - -static void button_press (GtkWidget *widget, GdkEventButton *event, gpointer data) -{ - IWindowListener *pListen = static_cast(data); - switch (event->button) - { - case 1: - pListen->OnLButtonDown(event->state, event->x, event->y); break; - case 3: - pListen->OnRButtonDown(event->state, event->x, event->y); break; - } -} - -static void button_release (GtkWidget *widget, GdkEventButton *event, gpointer data) -{ - IWindowListener *pListen = static_cast(data); - switch (event->button) - { - case 1: - pListen->OnLButtonUp(event->state, event->x, event->y); break; - case 3: - pListen->OnRButtonUp(event->state, event->x, event->y); break; - } -} - -static void motion (GtkWidget *widget, GdkEventMotion *event, gpointer data) -{ - IWindowListener *pListen = static_cast(data); - pListen->OnMouseMove(event->state, event->x, event->y); -} - -static gint expose (GtkWidget *widget, GdkEventExpose *event, gpointer data) -{ - if (event->count > 0) - return TRUE; - - CGtkWindow *pWindow = static_cast(data); - pWindow->DoExpose(); - - return TRUE; -} - -// we use the string versions of the keys for now.. -static gint keypress (GtkWidget* widget, GdkEventKey* event, gpointer data) -{ - gint ret; - - IWindowListener *pListen = static_cast(data); - ret = pListen->OnKeyPressed(gdk_keyval_name(event->keyval)); - if (ret) - { - gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event"); - } - return ret; -} - -// close_widget is not hooked on the listener but on the CGtkWindow object to handle the closure -static gint close_widget (GtkWidget *widget, GdkEvent* event, gpointer data) -{ - CGtkWindow *pWindow = static_cast(data); - pWindow->Close(); - - return TRUE; -} - -void CGtkWindow::DoExpose() -{ - gtk_glwidget_make_current(m_pGLWidget); - if (m_pListen->Paint()) - gtk_glwidget_swap_buffers(m_pGLWidget); -} - -void CGtkWindow::Redraw() -{ - gtk_widget_queue_draw(m_pGLWidget); -} - -void CGtkWindow::Close() -{ - // similar to a destructor, except we warn first - m_pListen->Close(); - m_pListen->DecRef(); m_pListen = NULL; - gtk_widget_destroy(m_pWnd); m_pWnd = NULL; -} - -bool CGtkWindow::Show() -{ - // check we got everything and are reading to instanciate - if (m_nWidthParam == 0 || m_nHeightParam == 0) - { - Sys_FPrintf(SYS_ERR, "Height and Width params not set in CGtkWindow::Show\n"); - return false; - } - if (!m_pListen) - { - Sys_FPrintf(SYS_ERR, "No listener set in CGtkWindow::Show\n"); - return false; - } - - // seems all good, here we go - m_pWnd = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (m_pWnd), m_Name.GetBuffer()); - gtk_window_set_default_size (GTK_WINDOW (m_pWnd), m_nWidthParam, m_nHeightParam); - gtk_widget_show (m_pWnd); - - // GL widget creation - m_pGLWidget = gtk_glwidget_new(FALSE, g_qeglobals_gui.d_glBase); - - gtk_widget_set_events (m_pGLWidget, GDK_DESTROY | GDK_EXPOSURE_MASK | GDK_KEY_PRESS_MASK | - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK); - - // Connect signal handlers - gtk_signal_connect (GTK_OBJECT (m_pGLWidget), "expose_event", GTK_SIGNAL_FUNC (expose), this); - gtk_signal_connect (GTK_OBJECT (m_pGLWidget), "motion_notify_event", - GTK_SIGNAL_FUNC (motion), m_pListen); - gtk_signal_connect (GTK_OBJECT (m_pGLWidget), "button_press_event", - GTK_SIGNAL_FUNC (button_press), m_pListen); - gtk_signal_connect (GTK_OBJECT (m_pGLWidget), "button_release_event", - GTK_SIGNAL_FUNC (button_release), m_pListen); - - gtk_signal_connect (GTK_OBJECT (m_pWnd), "delete_event", GTK_SIGNAL_FUNC (close_widget), this); - gtk_signal_connect (GTK_OBJECT (m_pWnd), "key_press_event", - GTK_SIGNAL_FUNC (keypress), m_pListen); - - gtk_widget_show (m_pGLWidget); - gtk_container_add (GTK_CONTAINER (m_pWnd), m_pGLWidget); - - return true; -} - -IWindow* WINAPI QERApp_CreateGLWindow() -{ - return new CGtkWindow; -} - -void WINAPI QERApp_HookWindow(IWindowListener* pListen) -{ - l_WindowListeners.Add( pListen ); - pListen->IncRef(); -} - -void WINAPI QERApp_UnHookWindow(IWindowListener* pListen) -{ - for ( int i = 0; i < l_WindowListeners.GetSize(); i++ ) - { - if (l_WindowListeners.GetAt(i) == pListen) - { - l_WindowListeners.RemoveAt(i); - pListen->DecRef(); - return; - } - } -#ifdef _DEBUG - Sys_Printf("WARNING: IWindowListener not found in QERApp_UnHookWindow\n"); -#endif -} - -void DispatchOnMouseMove(guint32 nFlags, int x, int y) -{ - for( int i = 0; i < l_WindowListeners.GetSize(); i++ ) - static_cast(l_WindowListeners.GetAt(i))->OnMouseMove( nFlags, x, y ); -} - -bool DispatchOnLButtonDown(guint32 nFlags, int x, int y) -{ - for( int i = 0; i < l_WindowListeners.GetSize(); i++ ) - if (static_cast(l_WindowListeners.GetAt(i))->OnLButtonDown( nFlags, x, y )) - return true; - return false; -} - -bool DispatchOnLButtonUp(guint32 nFlags, int x, int y) -{ - for( int i = 0; i < l_WindowListeners.GetSize(); i++ ) - if (static_cast(l_WindowListeners.GetAt(i))->OnLButtonUp( nFlags, x, y )) - return true; - return false; -} - -void WINAPI QERApp_HookListener(IListener* pListen, int Msg) -{ -#ifdef _DEBUG - if (Msg >= RADIANT_MSGCOUNT) - { - Sys_Printf("ERROR: bad index in QERApp_HookListener\n"); - return; - } -#endif - l_Listeners[Msg].Add( pListen ); - pListen->IncRef(); -} - -int WINAPI QERApp_UnHookListener(IListener* pListen) -{ - int count = 0; - for( int i = 0; iDecRef(); - count++; - } - return count; -} - -void DispatchRadiantMsg( int Msg ) -{ -#ifdef _DEBUG - if (Msg >= RADIANT_MSGCOUNT) - { - Sys_Printf("ERROR: bad index in DispatchRadiantMsg\n"); - return; - } -#endif - for(int i = 0; i(l_Listeners[Msg].GetAt(i))->DispatchRadiantMsg(Msg); -} - -void CXYWndWrapper::SnapToGrid( int x1, int y1, vec3_t pt ) -{ - int height = g_pParentWnd->ActiveXY()->GetWidget()->allocation.height; - g_pParentWnd->ActiveXY()->SnapToPoint( x1, height - 1 - y1, pt ); -} - -VIEWTYPE CXYWndWrapper::GetViewType( void ) -{ - return (VIEWTYPE)g_pParentWnd->ActiveXY()->GetViewType(); -} - -IXYWndWrapper* WINAPI QERApp_GetXYWndWrapper() -{ - return &l_XYWndWrapper; -} +/* +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 +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// implementation of IMessaging specific interface +// + +#include "stdafx.h" + +CPtrArray l_Listeners[RADIANT_MSGCOUNT]; +CPtrArray l_WindowListeners; +CXYWndWrapper l_XYWndWrapper; + +// CGtkWindow implementation ------------------------------------- + +static void button_press (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + IWindowListener *pListen = static_cast(data); + switch (event->button) + { + case 1: + pListen->OnLButtonDown(event->state, event->x, event->y); break; + case 3: + pListen->OnRButtonDown(event->state, event->x, event->y); break; + } +} + +static void button_release (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + IWindowListener *pListen = static_cast(data); + switch (event->button) + { + case 1: + pListen->OnLButtonUp(event->state, event->x, event->y); break; + case 3: + pListen->OnRButtonUp(event->state, event->x, event->y); break; + } +} + +static void motion (GtkWidget *widget, GdkEventMotion *event, gpointer data) +{ + IWindowListener *pListen = static_cast(data); + pListen->OnMouseMove(event->state, event->x, event->y); +} + +static gint expose (GtkWidget *widget, GdkEventExpose *event, gpointer data) +{ + if (event->count > 0) + return TRUE; + + CGtkWindow *pWindow = static_cast(data); + pWindow->DoExpose(); + + return TRUE; +} + +// we use the string versions of the keys for now.. +static gint keypress (GtkWidget* widget, GdkEventKey* event, gpointer data) +{ + gint ret; + + IWindowListener *pListen = static_cast(data); + ret = pListen->OnKeyPressed(gdk_keyval_name(event->keyval)); + if (ret) + { + gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event"); + } + return ret; +} + +// close_widget is not hooked on the listener but on the CGtkWindow object to handle the closure +static gint close_widget (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + CGtkWindow *pWindow = static_cast(data); + pWindow->Close(); + + return TRUE; +} + +void CGtkWindow::DoExpose() +{ + gtk_glwidget_make_current(m_pGLWidget); + if (m_pListen->Paint()) + gtk_glwidget_swap_buffers(m_pGLWidget); +} + +void CGtkWindow::Redraw() +{ + gtk_widget_queue_draw(m_pGLWidget); +} + +void CGtkWindow::Close() +{ + // similar to a destructor, except we warn first + m_pListen->Close(); + m_pListen->DecRef(); m_pListen = NULL; + gtk_widget_destroy(m_pWnd); m_pWnd = NULL; +} + +bool CGtkWindow::Show() +{ + // check we got everything and are reading to instanciate + if (m_nWidthParam == 0 || m_nHeightParam == 0) + { + Sys_FPrintf(SYS_ERR, "Height and Width params not set in CGtkWindow::Show\n"); + return false; + } + if (!m_pListen) + { + Sys_FPrintf(SYS_ERR, "No listener set in CGtkWindow::Show\n"); + return false; + } + + // seems all good, here we go + m_pWnd = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (m_pWnd), m_Name.GetBuffer()); + gtk_window_set_default_size (GTK_WINDOW (m_pWnd), m_nWidthParam, m_nHeightParam); + gtk_widget_show (m_pWnd); + + // GL widget creation + m_pGLWidget = gtk_glwidget_new(FALSE, g_qeglobals_gui.d_glBase); + + gtk_widget_set_events (m_pGLWidget, GDK_DESTROY | GDK_EXPOSURE_MASK | GDK_KEY_PRESS_MASK | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK); + + // Connect signal handlers + gtk_signal_connect (GTK_OBJECT (m_pGLWidget), "expose_event", GTK_SIGNAL_FUNC (expose), this); + gtk_signal_connect (GTK_OBJECT (m_pGLWidget), "motion_notify_event", + GTK_SIGNAL_FUNC (motion), m_pListen); + gtk_signal_connect (GTK_OBJECT (m_pGLWidget), "button_press_event", + GTK_SIGNAL_FUNC (button_press), m_pListen); + gtk_signal_connect (GTK_OBJECT (m_pGLWidget), "button_release_event", + GTK_SIGNAL_FUNC (button_release), m_pListen); + + gtk_signal_connect (GTK_OBJECT (m_pWnd), "delete_event", GTK_SIGNAL_FUNC (close_widget), this); + gtk_signal_connect (GTK_OBJECT (m_pWnd), "key_press_event", + GTK_SIGNAL_FUNC (keypress), m_pListen); + + gtk_widget_show (m_pGLWidget); + gtk_container_add (GTK_CONTAINER (m_pWnd), m_pGLWidget); + + return true; +} + +IWindow* WINAPI QERApp_CreateGLWindow() +{ + return new CGtkWindow; +} + +void WINAPI QERApp_HookWindow(IWindowListener* pListen) +{ + l_WindowListeners.Add( pListen ); + pListen->IncRef(); +} + +void WINAPI QERApp_UnHookWindow(IWindowListener* pListen) +{ + for ( int i = 0; i < l_WindowListeners.GetSize(); i++ ) + { + if (l_WindowListeners.GetAt(i) == pListen) + { + l_WindowListeners.RemoveAt(i); + pListen->DecRef(); + return; + } + } +#ifdef _DEBUG + Sys_Printf("WARNING: IWindowListener not found in QERApp_UnHookWindow\n"); +#endif +} + +void DispatchOnMouseMove(guint32 nFlags, int x, int y) +{ + for( int i = 0; i < l_WindowListeners.GetSize(); i++ ) + static_cast(l_WindowListeners.GetAt(i))->OnMouseMove( nFlags, x, y ); +} + +bool DispatchOnLButtonDown(guint32 nFlags, int x, int y) +{ + for( int i = 0; i < l_WindowListeners.GetSize(); i++ ) + if (static_cast(l_WindowListeners.GetAt(i))->OnLButtonDown( nFlags, x, y )) + return true; + return false; +} + +bool DispatchOnLButtonUp(guint32 nFlags, int x, int y) +{ + for( int i = 0; i < l_WindowListeners.GetSize(); i++ ) + if (static_cast(l_WindowListeners.GetAt(i))->OnLButtonUp( nFlags, x, y )) + return true; + return false; +} + +void WINAPI QERApp_HookListener(IListener* pListen, int Msg) +{ +#ifdef _DEBUG + if (Msg >= RADIANT_MSGCOUNT) + { + Sys_Printf("ERROR: bad index in QERApp_HookListener\n"); + return; + } +#endif + l_Listeners[Msg].Add( pListen ); + pListen->IncRef(); +} + +int WINAPI QERApp_UnHookListener(IListener* pListen) +{ + int count = 0; + for( int i = 0; iDecRef(); + count++; + } + return count; +} + +void DispatchRadiantMsg( int Msg ) +{ +#ifdef _DEBUG + if (Msg >= RADIANT_MSGCOUNT) + { + Sys_Printf("ERROR: bad index in DispatchRadiantMsg\n"); + return; + } +#endif + for(int i = 0; i(l_Listeners[Msg].GetAt(i))->DispatchRadiantMsg(Msg); +} + +void CXYWndWrapper::SnapToGrid( int x1, int y1, vec3_t pt ) +{ + int height = g_pParentWnd->ActiveXY()->GetWidget()->allocation.height; + g_pParentWnd->ActiveXY()->SnapToPoint( x1, height - 1 - y1, pt ); +} + +VIEWTYPE CXYWndWrapper::GetViewType( void ) +{ + return (VIEWTYPE)g_pParentWnd->ActiveXY()->GetViewType(); +} + +IXYWndWrapper* WINAPI QERApp_GetXYWndWrapper() +{ + return &l_XYWndWrapper; +} diff --git a/radiant/undo.cpp b/radiant/undo.cpp index d1465af1..41bad9d8 100644 --- a/radiant/undo.cpp +++ b/radiant/undo.cpp @@ -1,973 +1,973 @@ -/* -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 -*/ - - -/* - - QERadiant Undo/Redo - - -basic setup: - -<-g_undolist---------g_lastundo> <---map data---> <-g_lastredo---------g_redolist-> - - - undo/redo on the world_entity is special, only the epair changes are remembered - and the world entity never gets deleted. - - FIXME: maybe reset the Undo system at map load - maybe also reset the entityId at map load -*/ - -#include "stdafx.h" - -typedef struct undo_s -{ - double time; //time operation was performed - int id; //every undo has an unique id - int done; //true when undo is build - char *operation; //name of the operation - brush_t brushlist; //deleted brushes - entity_t entitylist; //deleted entities - struct undo_s *prev, *next; //next and prev undo in list -} undo_t; - -undo_t *g_undolist; //first undo in the list -undo_t *g_lastundo; //last undo in the list -undo_t *g_redolist; //first redo in the list -undo_t *g_lastredo; //last undo in list -int g_undoMaxSize = 64; //maximum number of undos -int g_undoSize = 0; //number of undos in the list -int g_undoMaxMemorySize = 2*1024*1024; //maximum undo memory (default 2 MB) -int g_undoMemorySize = 0; //memory size of undo buffer -int g_undoId = 1; //current undo ID (zero is invalid id) -int g_redoId = 1; //current redo ID (zero is invalid id) - -/* -============= -Undo_MemorySize -============= -*/ -int Undo_MemorySize(void) -{ - return g_undoMemorySize; -} - -/* -============= -Undo_ClearRedo -============= -*/ -void Undo_ClearRedo(void) -{ - undo_t *redo, *nextredo; - brush_t *pBrush, *pNextBrush; - entity_t *pEntity, *pNextEntity; - - for (redo = g_redolist; redo; redo = nextredo) - { - nextredo = redo->next; - for (pBrush = redo->brushlist.next ; pBrush != NULL && pBrush != &redo->brushlist ; pBrush = pNextBrush) - { - pNextBrush = pBrush->next; - Brush_Free(pBrush); - } - for (pEntity = redo->entitylist.next; pEntity != NULL && pEntity != &redo->entitylist; pEntity = pNextEntity) - { - pNextEntity = pEntity->next; - Entity_Free(pEntity); - } - free(redo); - } - g_redolist = NULL; - g_lastredo = NULL; - g_redoId = 1; -} - -/* -============= -Undo_Clear - - Clears the undo buffer. -============= -*/ -void Undo_Clear(void) -{ - undo_t *undo, *nextundo; - brush_t *pBrush, *pNextBrush; - entity_t *pEntity, *pNextEntity; - - Undo_ClearRedo(); - for (undo = g_undolist; undo; undo = nextundo) - { - nextundo = undo->next; - for (pBrush = undo->brushlist.next ; pBrush != NULL && pBrush != &undo->brushlist ; pBrush = pNextBrush) - { - pNextBrush = pBrush->next; - g_undoMemorySize -= Brush_MemorySize(pBrush); - Brush_Free(pBrush); - } - for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = pNextEntity) - { - pNextEntity = pEntity->next; - g_undoMemorySize -= Entity_MemorySize(pEntity); - Entity_Free(pEntity); - } - g_undoMemorySize -= sizeof(undo_t); - free(undo); - } - g_undolist = NULL; - g_lastundo = NULL; - g_undoSize = 0; - g_undoMemorySize = 0; - g_undoId = 1; -} - -/* -============= -Undo_SetMaxSize -============= -*/ -void Undo_SetMaxSize(int size) -{ - Undo_Clear(); - if (size < 1) g_undoMaxSize = 1; - else g_undoMaxSize = size; -} - -/* -============= -Undo_GetMaxSize -============= -*/ -int Undo_GetMaxSize(void) -{ - return g_undoMaxSize; -} - -/* -============= -Undo_SetMaxMemorySize -============= -*/ -void Undo_SetMaxMemorySize(int size) -{ - Undo_Clear(); - if (size < 1024) g_undoMaxMemorySize = 1024; - else g_undoMaxMemorySize = size; -} - -/* -============= -Undo_GetMaxMemorySize -============= -*/ -int Undo_GetMaxMemorySize(void) -{ - return g_undoMaxMemorySize; -} - -/* -============= -Undo_FreeFirstUndo -============= -*/ -void Undo_FreeFirstUndo(void) -{ - undo_t *undo; - brush_t *pBrush, *pNextBrush; - entity_t *pEntity, *pNextEntity; - - //remove the oldest undo from the undo buffer - undo = g_undolist; - g_undolist = g_undolist->next; - g_undolist->prev = NULL; - // - for (pBrush = undo->brushlist.next ; pBrush != NULL && pBrush != &undo->brushlist ; pBrush = pNextBrush) - { - pNextBrush = pBrush->next; - g_undoMemorySize -= Brush_MemorySize(pBrush); - Brush_Free(pBrush); - } - for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = pNextEntity) - { - pNextEntity = pEntity->next; - g_undoMemorySize -= Entity_MemorySize(pEntity); - Entity_Free(pEntity); - } - g_undoMemorySize -= sizeof(undo_t); - free(undo); - g_undoSize--; -} - -/* -============= -Undo_GeneralStart -============= -*/ -void Undo_GeneralStart(char *operation) -{ - undo_t *undo; - brush_t *pBrush; - entity_t *pEntity; - - - if (g_lastundo) - { - if (!g_lastundo->done) - { - Sys_Printf("Undo_Start: WARNING last undo not finished.\n"); - } - } - - undo = (undo_t *) malloc(sizeof(undo_t)); - if (!undo) - return; - memset(undo, 0, sizeof(undo_t)); - undo->brushlist.next = &undo->brushlist; - undo->brushlist.prev = &undo->brushlist; - undo->entitylist.next = &undo->entitylist; - undo->entitylist.prev = &undo->entitylist; - if (g_lastundo) - g_lastundo->next = undo; - else - g_undolist = undo; - undo->prev = g_lastundo; - undo->next = NULL; - g_lastundo = undo; - - undo->time = Sys_DoubleTime(); - // - if (g_undoId > g_undoMaxSize * 2) g_undoId = 1; - if (g_undoId <= 0) g_undoId = 1; - undo->id = g_undoId++; - undo->done = false; - undo->operation = operation; - //reset the undo IDs of all brushes using the new ID - for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush = pBrush->next) - { - if (pBrush->undoId == undo->id) - { - pBrush->undoId = 0; - } - } - for (pBrush = selected_brushes.next; pBrush != NULL && pBrush != &selected_brushes; pBrush = pBrush->next) - { - if (pBrush->undoId == undo->id) - { - pBrush->undoId = 0; - } - } - //reset the undo IDs of all entities using thew new ID - for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next) - { - if (pEntity->undoId == undo->id) - { - pEntity->undoId = 0; - } - } - g_undoMemorySize += sizeof(undo_t); - g_undoSize++; - //undo buffer is bound to a max - if (g_undoSize > g_undoMaxSize) - { - Undo_FreeFirstUndo(); - } -} - -/* -============= -Undo_BrushInUndo -============= -*/ -int Undo_BrushInUndo(undo_t *undo, brush_t *brush) -{ -/* brush_t *b; - - for (b = undo->brushlist.next; b != &undo->brushlist; b = b->next) - { - // Arnout: NOTE - can't do a pointer compare as the brushes get cloned into the undo brushlist, and not just referenced from it - // For entities we have a unique ID, for brushes we have numberID - but brush full clone increases that anyway so it's useless right now. - if (b == brush) return true; - }*/ - // Arnout: function is pointless right now, see above explanation - return false; -} - -/* -============= -Undo_EntityInUndo -============= -*/ -int Undo_EntityInUndo(undo_t *undo, entity_t *ent) -{ - entity_t *e; - - for (e = undo->entitylist.next; e != &undo->entitylist; e = e->next) - { - // Arnout: NOTE - can't do a pointer compare as the entities get cloned into the undo entitylist, and not just referenced from it - //if (e == ent) return true; - if( e->entityId == ent->entityId ) return true; - } - return false; -} - -/* -============= -Undo_Start -============= -*/ -void Undo_Start(char *operation) -{ - // spog - disable undo if undo levels = 0 - if (g_PrefsDlg.m_nUndoLevels == 0) - { -#ifdef DBG_UNDO - Sys_Printf("Undo_Start: undo is disabled.\n"); -#endif - return; - } - - Undo_ClearRedo(); - Undo_GeneralStart(operation); -} - -/* -============= -Undo_AddBrush -============= -*/ -void Undo_AddBrush(brush_t *pBrush) -{ - // spog - disable undo if undo levels = 0 - if (g_PrefsDlg.m_nUndoLevels == 0) - { -#ifdef DBG_UNDO - Sys_Printf("Undo_AddBrush: undo is disabled.\n"); -#endif - return; - } - - if (!g_lastundo) - { - Sys_Printf("Undo_AddBrushList: no last undo.\n"); - return; - } - if (g_lastundo->entitylist.next != &g_lastundo->entitylist) - { - Sys_Printf("Undo_AddBrushList: WARNING adding brushes after entity.\n"); - } - //if the brush is already in the undo - if (Undo_BrushInUndo(g_lastundo, pBrush)) - return; - //clone the brush - brush_t* pClone = Brush_FullClone(pBrush); - //save the ID of the owner entity - pClone->ownerId = pBrush->owner->entityId; - //save the old undo ID for previous undos - pClone->undoId = pBrush->undoId; - Brush_AddToList (pClone, &g_lastundo->brushlist); - // - g_undoMemorySize += Brush_MemorySize(pClone); -} - -/* -============= -Undo_AddBrushList -TTimo: some brushes are just there for UI, and the information is somewhere else -for patches it's in the patchMesh_t structure, so when we clone the brush we get that information (brush_t::pPatch) -but: models are stored in pBrush->owner->md3Class, and owner epairs and origin parameters are important - so, we detect models and push the entity in the undo session (as well as it's BBox brush) - same for other items like weapons and ammo etc. -============= -*/ -void Undo_AddBrushList(brush_t *brushlist) -{ - // spog - disable undo if undo levels = 0 - if (g_PrefsDlg.m_nUndoLevels == 0) - { -#ifdef DBG_UNDO - Sys_Printf("Undo_AddBrushList: undo is disabled.\n"); -#endif - return; - } - - brush_t *pBrush; - - if (!g_lastundo) - { - Sys_Printf("Undo_AddBrushList: no last undo.\n"); - return; - } - if (g_lastundo->entitylist.next != &g_lastundo->entitylist) - { - Sys_Printf("Undo_AddBrushList: WARNING adding brushes after entity.\n"); - } - //copy the brushes to the undo - for (pBrush = brushlist->next ; pBrush != NULL && pBrush != brushlist; pBrush=pBrush->next) - { - //if the brush is already in the undo - //++timo FIXME: when does this happen? - if (Undo_BrushInUndo(g_lastundo, pBrush)) - continue; - // do we need to store this brush's entity in the undo? - // if it's a fixed size entity, the brush that reprents it is not really relevant, it's used for selecting and moving around - // what we want to store for undo is the owner entity, epairs and origin/angle stuff - //++timo FIXME: if the entity is not fixed size I don't know, so I don't do it yet - if (pBrush->owner->eclass->fixedsize == 1) - Undo_AddEntity( pBrush->owner ); - // clone the brush - brush_t* pClone = Brush_FullClone(pBrush); - // save the ID of the owner entity - pClone->ownerId = pBrush->owner->entityId; - // save the old undo ID from previous undos - pClone->undoId = pBrush->undoId; - Brush_AddToList (pClone, &g_lastundo->brushlist); - // track memory size used by undo - g_undoMemorySize += Brush_MemorySize(pClone); - } -} - -/* -============= -Undo_EndBrush -============= -*/ -void Undo_EndBrush(brush_t *pBrush) -{ - // spog - disable undo if undo levels = 0 - if (g_PrefsDlg.m_nUndoLevels == 0) - { -#ifdef DBG_UNDO - Sys_Printf("Undo_EndBrush: undo is disabled.\n"); -#endif - return; - } - - - if (!g_lastundo) - { - //Sys_Printf("Undo_End: no last undo.\n"); - return; - } - if (g_lastundo->done) - { - //Sys_Printf("Undo_End: last undo already finished.\n"); - return; - } - pBrush->undoId = g_lastundo->id; -} - -/* -============= -Undo_EndBrushList -============= -*/ -void Undo_EndBrushList(brush_t *brushlist) -{ - // spog - disable undo if undo levels = 0 - if (g_PrefsDlg.m_nUndoLevels == 0) - { -#ifdef DBG_UNDO - Sys_Printf("Undo_EndBrushList: undo is disabled.\n"); -#endif - return; - } - - - if (!g_lastundo) - { - //Sys_Printf("Undo_End: no last undo.\n"); - return; - } - if (g_lastundo->done) - { - //Sys_Printf("Undo_End: last undo already finished.\n"); - return; - } - for (brush_t* pBrush = brushlist->next; pBrush != NULL && pBrush != brushlist; pBrush=pBrush->next) - { - pBrush->undoId = g_lastundo->id; - } -} - -/* -============= -Undo_AddEntity -============= -*/ -void Undo_AddEntity(entity_t *entity) -{ - // spog - disable undo if undo levels = 0 - if (g_PrefsDlg.m_nUndoLevels == 0) - { -#ifdef DBG_UNDO - Sys_Printf("Undo_AddEntity: undo is disabled.\n"); -#endif - return; - } - - - entity_t* pClone; - - if (!g_lastundo) - { - Sys_Printf("Undo_AddEntity: no last undo.\n"); - return; - } - //if the entity is already in the undo - if (Undo_EntityInUndo(g_lastundo, entity)) - return; - //clone the entity - pClone = Entity_Clone(entity); - //save the old undo ID for previous undos - pClone->undoId = entity->undoId; - //save the entity ID (we need a full clone) - pClone->entityId = entity->entityId; - // - Entity_AddToList(pClone, &g_lastundo->entitylist); - // - g_undoMemorySize += Entity_MemorySize(pClone); -} - -/* -============= -Undo_EndEntity -============= -*/ -void Undo_EndEntity(entity_t *entity) -{ - // spog - disable undo if undo levels = 0 - if (g_PrefsDlg.m_nUndoLevels == 0) - { -#ifdef DBG_UNDO - Sys_Printf("Undo_EndEntity: undo is disabled.\n"); -#endif - return; - } - - - if (!g_lastundo) - { -#ifdef _DEBUG - Sys_Printf("Undo_End: no last undo.\n"); -#endif - return; - } - if (g_lastundo->done) - { -#ifdef _DEBUG - Sys_Printf("Undo_End: last undo already finished.\n"); -#endif - return; - } - if (entity == world_entity) - { - //Sys_Printf("Undo_AddEntity: undo on world entity.\n"); - //NOTE: we never delete the world entity when undoing an operation - // we only transfer the epairs - return; - } - entity->undoId = g_lastundo->id; -} - -/* -============= -Undo_End -============= -*/ -void Undo_End(void) -{ - // spog - disable undo if undo levels = 0 - if (g_PrefsDlg.m_nUndoLevels == 0) - { -#ifdef DBG_UNDO - Sys_Printf("Undo_End: undo is disabled.\n"); -#endif - return; - } - - - if (!g_lastundo) - { - //Sys_Printf("Undo_End: no last undo.\n"); - return; - } - if (g_lastundo->done) - { - //Sys_Printf("Undo_End: last undo already finished.\n"); - return; - } - g_lastundo->done = true; - - //undo memory size is bound to a max - while (g_undoMemorySize > g_undoMaxMemorySize) - { - //always keep one undo - if (g_undolist == g_lastundo) break; - Undo_FreeFirstUndo(); - } - // - //Sys_Printf("undo size = %d, undo memory = %d\n", g_undoSize, g_undoMemorySize); -} - -/* -============= -Undo_Undo -============= -*/ -void Undo_Undo(boolean bSilent) -{ - // spog - disable undo if undo levels = 0 - if (g_PrefsDlg.m_nUndoLevels == 0) - { - Sys_Printf("Undo_Undo: undo is disabled.\n"); - return; - } - - undo_t *undo, *redo; - brush_t *pBrush, *pNextBrush; - entity_t *pEntity, *pNextEntity, *pUndoEntity; - - if (!g_lastundo) - { - Sys_Printf("Nothing left to undo.\n"); - return; - } - if (!g_lastundo->done) - { - Sys_Printf("Undo_Undo: WARNING: last undo not yet finished!\n"); - } - // get the last undo - undo = g_lastundo; - if (g_lastundo->prev) g_lastundo->prev->next = NULL; - else g_undolist = NULL; - g_lastundo = g_lastundo->prev; - - //allocate a new redo - redo = (undo_t *) malloc(sizeof(undo_t)); - if (!redo) return; - memset(redo, 0, sizeof(undo_t)); - redo->brushlist.next = &redo->brushlist; - redo->brushlist.prev = &redo->brushlist; - redo->entitylist.next = &redo->entitylist; - redo->entitylist.prev = &redo->entitylist; - if (g_lastredo) g_lastredo->next = redo; - else g_redolist = redo; - redo->prev = g_lastredo; - redo->next = NULL; - g_lastredo = redo; - redo->time = Sys_DoubleTime(); - redo->id = g_redoId++; - redo->done = true; - redo->operation = undo->operation; - - //reset the redo IDs of all brushes using the new ID - for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush = pBrush->next) - { - if (pBrush->redoId == redo->id) - { - pBrush->redoId = 0; - } - } - for (pBrush = selected_brushes.next; pBrush != NULL && pBrush != &selected_brushes; pBrush = pBrush->next) - { - if (pBrush->redoId == redo->id) - { - pBrush->redoId = 0; - } - } - //reset the redo IDs of all entities using thew new ID - for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next) - { - if (pEntity->redoId == redo->id) - { - pEntity->redoId = 0; - } - } - - // deselect current sutff - Select_Deselect(); - // move "created" brushes to the redo - for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush=pNextBrush) - { - pNextBrush = pBrush->next; - if (pBrush->undoId == undo->id) - { - //Brush_Free(pBrush); - //move the brush to the redo - Brush_RemoveFromList(pBrush); - Brush_AddToList(pBrush, &redo->brushlist); - //make sure the ID of the owner is stored - pBrush->ownerId = pBrush->owner->entityId; - //unlink the brush from the owner entity - Entity_UnlinkBrush(pBrush); - } - } - // move "created" entities to the redo - for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pNextEntity) - { - pNextEntity = pEntity->next; - if (pEntity->undoId == undo->id) - { - // check if this entity is in the undo - for (pUndoEntity = undo->entitylist.next; pUndoEntity != NULL && pUndoEntity != &undo->entitylist; pUndoEntity = pUndoEntity->next) - { - // move brushes to the undo entity - if (pUndoEntity->entityId == pEntity->entityId) - { - pUndoEntity->brushes.next = pEntity->brushes.next; - pUndoEntity->brushes.prev = pEntity->brushes.prev; - pEntity->brushes.next = &pEntity->brushes; - pEntity->brushes.prev = &pEntity->brushes; - } - } - // - //Entity_Free(pEntity); - //move the entity to the redo - Entity_RemoveFromList(pEntity); - Entity_AddToList(pEntity, &redo->entitylist); - } - } - // add the undo entities back into the entity list - for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = undo->entitylist.next) - { - g_undoMemorySize -= Entity_MemorySize(pEntity); - //if this is the world entity - if (pEntity->entityId == world_entity->entityId) - { - epair_t* tmp = world_entity->epairs; - world_entity->epairs = pEntity->epairs; - pEntity->epairs = tmp; - Entity_Free(pEntity); - } - else - { - Entity_RemoveFromList(pEntity); - Entity_AddToList(pEntity, &entities); - pEntity->redoId = redo->id; - } - } - // add the undo brushes back into the selected brushes - for (pBrush = undo->brushlist.next; pBrush != NULL && pBrush != &undo->brushlist; pBrush = undo->brushlist.next) - { - //Sys_Printf("Owner ID: %i\n",pBrush->ownerId); - g_undoMemorySize -= Brush_MemorySize(pBrush); - Brush_RemoveFromList(pBrush); - Brush_AddToList(pBrush, &active_brushes); - for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next) // fixes broken undo on entities - { - //Sys_Printf("Entity ID: %i\n",pEntity->entityId); - if (pEntity->entityId == pBrush->ownerId) - { - Entity_LinkBrush(pEntity, pBrush); - break; - } - } - //if the brush is not linked then it should be linked into the world entity - //++timo FIXME: maybe not, maybe we've lost this entity's owner! - if (pEntity == NULL || pEntity == &entities) - { - Entity_LinkBrush(world_entity, pBrush); - } - //build the brush - //Brush_Build(pBrush); - Select_Brush(pBrush); - pBrush->redoId = redo->id; - } - if (!bSilent) - Sys_Printf("%s undone.\n", undo->operation); - // free the undo - g_undoMemorySize -= sizeof(undo_t); - free(undo); - g_undoSize--; - g_undoId--; - if (g_undoId <= 0) g_undoId = 2 * g_undoMaxSize; - // - g_bScreenUpdates = true; - UpdateSurfaceDialog(); - Sys_UpdateWindows(W_ALL); -} - -/* -============= -Undo_Redo -============= -*/ -void Undo_Redo(void) -{ - // spog - disable undo if undo levels = 0 - if (g_PrefsDlg.m_nUndoLevels == 0) - { - Sys_Printf("Undo_Redo: undo is disabled.\n"); - return; - } - - undo_t *redo; - brush_t *pBrush, *pNextBrush; - entity_t *pEntity, *pNextEntity, *pRedoEntity; - - if (!g_lastredo) - { - Sys_Printf("Nothing left to redo.\n"); - return; - } - if (g_lastundo) - { - if (!g_lastundo->done) - { - Sys_Printf("WARNING: last undo not finished.\n"); - } - } - // get the last redo - redo = g_lastredo; - if (g_lastredo->prev) g_lastredo->prev->next = NULL; - else g_redolist = NULL; - g_lastredo = g_lastredo->prev; - // - Undo_GeneralStart(redo->operation); - // remove current selection - Select_Deselect(); - // move "created" brushes back to the last undo - for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush = pNextBrush) - { - pNextBrush = pBrush->next; - if (pBrush->redoId == redo->id) - { - //move the brush to the undo - Brush_RemoveFromList(pBrush); - Brush_AddToList(pBrush, &g_lastundo->brushlist); - g_undoMemorySize += Brush_MemorySize(pBrush); - pBrush->ownerId = pBrush->owner->entityId; - Entity_UnlinkBrush(pBrush); - } - } - // move "created" entities back to the last undo - for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pNextEntity) - { - pNextEntity = pEntity->next; - if (pEntity->redoId == redo->id) - { - // check if this entity is in the redo - for (pRedoEntity = redo->entitylist.next; pRedoEntity != NULL && pRedoEntity != &redo->entitylist; pRedoEntity = pRedoEntity->next) - { - // move brushes to the redo entity - if (pRedoEntity->entityId == pEntity->entityId) - { - pRedoEntity->brushes.next = pEntity->brushes.next; - pRedoEntity->brushes.prev = pEntity->brushes.prev; - pEntity->brushes.next = &pEntity->brushes; - pEntity->brushes.prev = &pEntity->brushes; - } - } - // - //Entity_Free(pEntity); - //move the entity to the redo - Entity_RemoveFromList(pEntity); - Entity_AddToList(pEntity, &g_lastundo->entitylist); - g_undoMemorySize += Entity_MemorySize(pEntity); - } - } - // add the undo entities back into the entity list - for (pEntity = redo->entitylist.next; pEntity != NULL && pEntity != &redo->entitylist; pEntity = redo->entitylist.next) - { - //if this is the world entity - if (pEntity->entityId == world_entity->entityId) - { - epair_t* tmp = world_entity->epairs; - world_entity->epairs = pEntity->epairs; - pEntity->epairs = tmp; - Entity_Free(pEntity); - } - else - { - Entity_RemoveFromList(pEntity); - Entity_AddToList(pEntity, &entities); - } - } - // add the redo brushes back into the selected brushes - for (pBrush = redo->brushlist.next; pBrush != NULL && pBrush != &redo->brushlist; pBrush = redo->brushlist.next) - { - Brush_RemoveFromList(pBrush); - Brush_AddToList(pBrush, &active_brushes); - for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next) // fixes broken undo on entities - { - if (pEntity->entityId == pBrush->ownerId) - { - Entity_LinkBrush(pEntity, pBrush); - break; - } - } - //if the brush is not linked then it should be linked into the world entity - if (pEntity == NULL || pEntity == &entities) - { - Entity_LinkBrush(world_entity, pBrush); - } - //build the brush - //Brush_Build(pBrush); - Select_Brush(pBrush); - } - // - Undo_End(); - // - Sys_Printf("%s redone.\n", redo->operation); - // - g_redoId--; - // free the undo - free(redo); - // - g_bScreenUpdates = true; - UpdateSurfaceDialog(); - Sys_UpdateWindows(W_ALL); -} - -/* -============= -Undo_RedoAvailable -============= -*/ -int Undo_RedoAvailable(void) -{ - if (g_lastredo) return true; - return false; -} - -int Undo_GetUndoId(void) -{ - if (g_lastundo) - return g_lastundo->id; - return 0; -} - -/* -============= -Undo_UndoAvailable -============= -*/ -int Undo_UndoAvailable(void) -{ - if (g_lastundo) - { - if (g_lastundo->done) - return true; - } - return false; -} +/* +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 +*/ + + +/* + + QERadiant Undo/Redo + + +basic setup: + +<-g_undolist---------g_lastundo> <---map data---> <-g_lastredo---------g_redolist-> + + + undo/redo on the world_entity is special, only the epair changes are remembered + and the world entity never gets deleted. + + FIXME: maybe reset the Undo system at map load + maybe also reset the entityId at map load +*/ + +#include "stdafx.h" + +typedef struct undo_s +{ + double time; //time operation was performed + int id; //every undo has an unique id + int done; //true when undo is build + char *operation; //name of the operation + brush_t brushlist; //deleted brushes + entity_t entitylist; //deleted entities + struct undo_s *prev, *next; //next and prev undo in list +} undo_t; + +undo_t *g_undolist; //first undo in the list +undo_t *g_lastundo; //last undo in the list +undo_t *g_redolist; //first redo in the list +undo_t *g_lastredo; //last undo in list +int g_undoMaxSize = 64; //maximum number of undos +int g_undoSize = 0; //number of undos in the list +int g_undoMaxMemorySize = 2*1024*1024; //maximum undo memory (default 2 MB) +int g_undoMemorySize = 0; //memory size of undo buffer +int g_undoId = 1; //current undo ID (zero is invalid id) +int g_redoId = 1; //current redo ID (zero is invalid id) + +/* +============= +Undo_MemorySize +============= +*/ +int Undo_MemorySize(void) +{ + return g_undoMemorySize; +} + +/* +============= +Undo_ClearRedo +============= +*/ +void Undo_ClearRedo(void) +{ + undo_t *redo, *nextredo; + brush_t *pBrush, *pNextBrush; + entity_t *pEntity, *pNextEntity; + + for (redo = g_redolist; redo; redo = nextredo) + { + nextredo = redo->next; + for (pBrush = redo->brushlist.next ; pBrush != NULL && pBrush != &redo->brushlist ; pBrush = pNextBrush) + { + pNextBrush = pBrush->next; + Brush_Free(pBrush); + } + for (pEntity = redo->entitylist.next; pEntity != NULL && pEntity != &redo->entitylist; pEntity = pNextEntity) + { + pNextEntity = pEntity->next; + Entity_Free(pEntity); + } + free(redo); + } + g_redolist = NULL; + g_lastredo = NULL; + g_redoId = 1; +} + +/* +============= +Undo_Clear + + Clears the undo buffer. +============= +*/ +void Undo_Clear(void) +{ + undo_t *undo, *nextundo; + brush_t *pBrush, *pNextBrush; + entity_t *pEntity, *pNextEntity; + + Undo_ClearRedo(); + for (undo = g_undolist; undo; undo = nextundo) + { + nextundo = undo->next; + for (pBrush = undo->brushlist.next ; pBrush != NULL && pBrush != &undo->brushlist ; pBrush = pNextBrush) + { + pNextBrush = pBrush->next; + g_undoMemorySize -= Brush_MemorySize(pBrush); + Brush_Free(pBrush); + } + for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = pNextEntity) + { + pNextEntity = pEntity->next; + g_undoMemorySize -= Entity_MemorySize(pEntity); + Entity_Free(pEntity); + } + g_undoMemorySize -= sizeof(undo_t); + free(undo); + } + g_undolist = NULL; + g_lastundo = NULL; + g_undoSize = 0; + g_undoMemorySize = 0; + g_undoId = 1; +} + +/* +============= +Undo_SetMaxSize +============= +*/ +void Undo_SetMaxSize(int size) +{ + Undo_Clear(); + if (size < 1) g_undoMaxSize = 1; + else g_undoMaxSize = size; +} + +/* +============= +Undo_GetMaxSize +============= +*/ +int Undo_GetMaxSize(void) +{ + return g_undoMaxSize; +} + +/* +============= +Undo_SetMaxMemorySize +============= +*/ +void Undo_SetMaxMemorySize(int size) +{ + Undo_Clear(); + if (size < 1024) g_undoMaxMemorySize = 1024; + else g_undoMaxMemorySize = size; +} + +/* +============= +Undo_GetMaxMemorySize +============= +*/ +int Undo_GetMaxMemorySize(void) +{ + return g_undoMaxMemorySize; +} + +/* +============= +Undo_FreeFirstUndo +============= +*/ +void Undo_FreeFirstUndo(void) +{ + undo_t *undo; + brush_t *pBrush, *pNextBrush; + entity_t *pEntity, *pNextEntity; + + //remove the oldest undo from the undo buffer + undo = g_undolist; + g_undolist = g_undolist->next; + g_undolist->prev = NULL; + // + for (pBrush = undo->brushlist.next ; pBrush != NULL && pBrush != &undo->brushlist ; pBrush = pNextBrush) + { + pNextBrush = pBrush->next; + g_undoMemorySize -= Brush_MemorySize(pBrush); + Brush_Free(pBrush); + } + for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = pNextEntity) + { + pNextEntity = pEntity->next; + g_undoMemorySize -= Entity_MemorySize(pEntity); + Entity_Free(pEntity); + } + g_undoMemorySize -= sizeof(undo_t); + free(undo); + g_undoSize--; +} + +/* +============= +Undo_GeneralStart +============= +*/ +void Undo_GeneralStart(char *operation) +{ + undo_t *undo; + brush_t *pBrush; + entity_t *pEntity; + + + if (g_lastundo) + { + if (!g_lastundo->done) + { + Sys_Printf("Undo_Start: WARNING last undo not finished.\n"); + } + } + + undo = (undo_t *) malloc(sizeof(undo_t)); + if (!undo) + return; + memset(undo, 0, sizeof(undo_t)); + undo->brushlist.next = &undo->brushlist; + undo->brushlist.prev = &undo->brushlist; + undo->entitylist.next = &undo->entitylist; + undo->entitylist.prev = &undo->entitylist; + if (g_lastundo) + g_lastundo->next = undo; + else + g_undolist = undo; + undo->prev = g_lastundo; + undo->next = NULL; + g_lastundo = undo; + + undo->time = Sys_DoubleTime(); + // + if (g_undoId > g_undoMaxSize * 2) g_undoId = 1; + if (g_undoId <= 0) g_undoId = 1; + undo->id = g_undoId++; + undo->done = false; + undo->operation = operation; + //reset the undo IDs of all brushes using the new ID + for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush = pBrush->next) + { + if (pBrush->undoId == undo->id) + { + pBrush->undoId = 0; + } + } + for (pBrush = selected_brushes.next; pBrush != NULL && pBrush != &selected_brushes; pBrush = pBrush->next) + { + if (pBrush->undoId == undo->id) + { + pBrush->undoId = 0; + } + } + //reset the undo IDs of all entities using thew new ID + for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next) + { + if (pEntity->undoId == undo->id) + { + pEntity->undoId = 0; + } + } + g_undoMemorySize += sizeof(undo_t); + g_undoSize++; + //undo buffer is bound to a max + if (g_undoSize > g_undoMaxSize) + { + Undo_FreeFirstUndo(); + } +} + +/* +============= +Undo_BrushInUndo +============= +*/ +int Undo_BrushInUndo(undo_t *undo, brush_t *brush) +{ +/* brush_t *b; + + for (b = undo->brushlist.next; b != &undo->brushlist; b = b->next) + { + // Arnout: NOTE - can't do a pointer compare as the brushes get cloned into the undo brushlist, and not just referenced from it + // For entities we have a unique ID, for brushes we have numberID - but brush full clone increases that anyway so it's useless right now. + if (b == brush) return true; + }*/ + // Arnout: function is pointless right now, see above explanation + return false; +} + +/* +============= +Undo_EntityInUndo +============= +*/ +int Undo_EntityInUndo(undo_t *undo, entity_t *ent) +{ + entity_t *e; + + for (e = undo->entitylist.next; e != &undo->entitylist; e = e->next) + { + // Arnout: NOTE - can't do a pointer compare as the entities get cloned into the undo entitylist, and not just referenced from it + //if (e == ent) return true; + if( e->entityId == ent->entityId ) return true; + } + return false; +} + +/* +============= +Undo_Start +============= +*/ +void Undo_Start(char *operation) +{ + // spog - disable undo if undo levels = 0 + if (g_PrefsDlg.m_nUndoLevels == 0) + { +#ifdef DBG_UNDO + Sys_Printf("Undo_Start: undo is disabled.\n"); +#endif + return; + } + + Undo_ClearRedo(); + Undo_GeneralStart(operation); +} + +/* +============= +Undo_AddBrush +============= +*/ +void Undo_AddBrush(brush_t *pBrush) +{ + // spog - disable undo if undo levels = 0 + if (g_PrefsDlg.m_nUndoLevels == 0) + { +#ifdef DBG_UNDO + Sys_Printf("Undo_AddBrush: undo is disabled.\n"); +#endif + return; + } + + if (!g_lastundo) + { + Sys_Printf("Undo_AddBrushList: no last undo.\n"); + return; + } + if (g_lastundo->entitylist.next != &g_lastundo->entitylist) + { + Sys_Printf("Undo_AddBrushList: WARNING adding brushes after entity.\n"); + } + //if the brush is already in the undo + if (Undo_BrushInUndo(g_lastundo, pBrush)) + return; + //clone the brush + brush_t* pClone = Brush_FullClone(pBrush); + //save the ID of the owner entity + pClone->ownerId = pBrush->owner->entityId; + //save the old undo ID for previous undos + pClone->undoId = pBrush->undoId; + Brush_AddToList (pClone, &g_lastundo->brushlist); + // + g_undoMemorySize += Brush_MemorySize(pClone); +} + +/* +============= +Undo_AddBrushList +TTimo: some brushes are just there for UI, and the information is somewhere else +for patches it's in the patchMesh_t structure, so when we clone the brush we get that information (brush_t::pPatch) +but: models are stored in pBrush->owner->md3Class, and owner epairs and origin parameters are important + so, we detect models and push the entity in the undo session (as well as it's BBox brush) + same for other items like weapons and ammo etc. +============= +*/ +void Undo_AddBrushList(brush_t *brushlist) +{ + // spog - disable undo if undo levels = 0 + if (g_PrefsDlg.m_nUndoLevels == 0) + { +#ifdef DBG_UNDO + Sys_Printf("Undo_AddBrushList: undo is disabled.\n"); +#endif + return; + } + + brush_t *pBrush; + + if (!g_lastundo) + { + Sys_Printf("Undo_AddBrushList: no last undo.\n"); + return; + } + if (g_lastundo->entitylist.next != &g_lastundo->entitylist) + { + Sys_Printf("Undo_AddBrushList: WARNING adding brushes after entity.\n"); + } + //copy the brushes to the undo + for (pBrush = brushlist->next ; pBrush != NULL && pBrush != brushlist; pBrush=pBrush->next) + { + //if the brush is already in the undo + //++timo FIXME: when does this happen? + if (Undo_BrushInUndo(g_lastundo, pBrush)) + continue; + // do we need to store this brush's entity in the undo? + // if it's a fixed size entity, the brush that reprents it is not really relevant, it's used for selecting and moving around + // what we want to store for undo is the owner entity, epairs and origin/angle stuff + //++timo FIXME: if the entity is not fixed size I don't know, so I don't do it yet + if (pBrush->owner->eclass->fixedsize == 1) + Undo_AddEntity( pBrush->owner ); + // clone the brush + brush_t* pClone = Brush_FullClone(pBrush); + // save the ID of the owner entity + pClone->ownerId = pBrush->owner->entityId; + // save the old undo ID from previous undos + pClone->undoId = pBrush->undoId; + Brush_AddToList (pClone, &g_lastundo->brushlist); + // track memory size used by undo + g_undoMemorySize += Brush_MemorySize(pClone); + } +} + +/* +============= +Undo_EndBrush +============= +*/ +void Undo_EndBrush(brush_t *pBrush) +{ + // spog - disable undo if undo levels = 0 + if (g_PrefsDlg.m_nUndoLevels == 0) + { +#ifdef DBG_UNDO + Sys_Printf("Undo_EndBrush: undo is disabled.\n"); +#endif + return; + } + + + if (!g_lastundo) + { + //Sys_Printf("Undo_End: no last undo.\n"); + return; + } + if (g_lastundo->done) + { + //Sys_Printf("Undo_End: last undo already finished.\n"); + return; + } + pBrush->undoId = g_lastundo->id; +} + +/* +============= +Undo_EndBrushList +============= +*/ +void Undo_EndBrushList(brush_t *brushlist) +{ + // spog - disable undo if undo levels = 0 + if (g_PrefsDlg.m_nUndoLevels == 0) + { +#ifdef DBG_UNDO + Sys_Printf("Undo_EndBrushList: undo is disabled.\n"); +#endif + return; + } + + + if (!g_lastundo) + { + //Sys_Printf("Undo_End: no last undo.\n"); + return; + } + if (g_lastundo->done) + { + //Sys_Printf("Undo_End: last undo already finished.\n"); + return; + } + for (brush_t* pBrush = brushlist->next; pBrush != NULL && pBrush != brushlist; pBrush=pBrush->next) + { + pBrush->undoId = g_lastundo->id; + } +} + +/* +============= +Undo_AddEntity +============= +*/ +void Undo_AddEntity(entity_t *entity) +{ + // spog - disable undo if undo levels = 0 + if (g_PrefsDlg.m_nUndoLevels == 0) + { +#ifdef DBG_UNDO + Sys_Printf("Undo_AddEntity: undo is disabled.\n"); +#endif + return; + } + + + entity_t* pClone; + + if (!g_lastundo) + { + Sys_Printf("Undo_AddEntity: no last undo.\n"); + return; + } + //if the entity is already in the undo + if (Undo_EntityInUndo(g_lastundo, entity)) + return; + //clone the entity + pClone = Entity_Clone(entity); + //save the old undo ID for previous undos + pClone->undoId = entity->undoId; + //save the entity ID (we need a full clone) + pClone->entityId = entity->entityId; + // + Entity_AddToList(pClone, &g_lastundo->entitylist); + // + g_undoMemorySize += Entity_MemorySize(pClone); +} + +/* +============= +Undo_EndEntity +============= +*/ +void Undo_EndEntity(entity_t *entity) +{ + // spog - disable undo if undo levels = 0 + if (g_PrefsDlg.m_nUndoLevels == 0) + { +#ifdef DBG_UNDO + Sys_Printf("Undo_EndEntity: undo is disabled.\n"); +#endif + return; + } + + + if (!g_lastundo) + { +#ifdef _DEBUG + Sys_Printf("Undo_End: no last undo.\n"); +#endif + return; + } + if (g_lastundo->done) + { +#ifdef _DEBUG + Sys_Printf("Undo_End: last undo already finished.\n"); +#endif + return; + } + if (entity == world_entity) + { + //Sys_Printf("Undo_AddEntity: undo on world entity.\n"); + //NOTE: we never delete the world entity when undoing an operation + // we only transfer the epairs + return; + } + entity->undoId = g_lastundo->id; +} + +/* +============= +Undo_End +============= +*/ +void Undo_End(void) +{ + // spog - disable undo if undo levels = 0 + if (g_PrefsDlg.m_nUndoLevels == 0) + { +#ifdef DBG_UNDO + Sys_Printf("Undo_End: undo is disabled.\n"); +#endif + return; + } + + + if (!g_lastundo) + { + //Sys_Printf("Undo_End: no last undo.\n"); + return; + } + if (g_lastundo->done) + { + //Sys_Printf("Undo_End: last undo already finished.\n"); + return; + } + g_lastundo->done = true; + + //undo memory size is bound to a max + while (g_undoMemorySize > g_undoMaxMemorySize) + { + //always keep one undo + if (g_undolist == g_lastundo) break; + Undo_FreeFirstUndo(); + } + // + //Sys_Printf("undo size = %d, undo memory = %d\n", g_undoSize, g_undoMemorySize); +} + +/* +============= +Undo_Undo +============= +*/ +void Undo_Undo(boolean bSilent) +{ + // spog - disable undo if undo levels = 0 + if (g_PrefsDlg.m_nUndoLevels == 0) + { + Sys_Printf("Undo_Undo: undo is disabled.\n"); + return; + } + + undo_t *undo, *redo; + brush_t *pBrush, *pNextBrush; + entity_t *pEntity, *pNextEntity, *pUndoEntity; + + if (!g_lastundo) + { + Sys_Printf("Nothing left to undo.\n"); + return; + } + if (!g_lastundo->done) + { + Sys_Printf("Undo_Undo: WARNING: last undo not yet finished!\n"); + } + // get the last undo + undo = g_lastundo; + if (g_lastundo->prev) g_lastundo->prev->next = NULL; + else g_undolist = NULL; + g_lastundo = g_lastundo->prev; + + //allocate a new redo + redo = (undo_t *) malloc(sizeof(undo_t)); + if (!redo) return; + memset(redo, 0, sizeof(undo_t)); + redo->brushlist.next = &redo->brushlist; + redo->brushlist.prev = &redo->brushlist; + redo->entitylist.next = &redo->entitylist; + redo->entitylist.prev = &redo->entitylist; + if (g_lastredo) g_lastredo->next = redo; + else g_redolist = redo; + redo->prev = g_lastredo; + redo->next = NULL; + g_lastredo = redo; + redo->time = Sys_DoubleTime(); + redo->id = g_redoId++; + redo->done = true; + redo->operation = undo->operation; + + //reset the redo IDs of all brushes using the new ID + for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush = pBrush->next) + { + if (pBrush->redoId == redo->id) + { + pBrush->redoId = 0; + } + } + for (pBrush = selected_brushes.next; pBrush != NULL && pBrush != &selected_brushes; pBrush = pBrush->next) + { + if (pBrush->redoId == redo->id) + { + pBrush->redoId = 0; + } + } + //reset the redo IDs of all entities using thew new ID + for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next) + { + if (pEntity->redoId == redo->id) + { + pEntity->redoId = 0; + } + } + + // deselect current sutff + Select_Deselect(); + // move "created" brushes to the redo + for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush=pNextBrush) + { + pNextBrush = pBrush->next; + if (pBrush->undoId == undo->id) + { + //Brush_Free(pBrush); + //move the brush to the redo + Brush_RemoveFromList(pBrush); + Brush_AddToList(pBrush, &redo->brushlist); + //make sure the ID of the owner is stored + pBrush->ownerId = pBrush->owner->entityId; + //unlink the brush from the owner entity + Entity_UnlinkBrush(pBrush); + } + } + // move "created" entities to the redo + for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pNextEntity) + { + pNextEntity = pEntity->next; + if (pEntity->undoId == undo->id) + { + // check if this entity is in the undo + for (pUndoEntity = undo->entitylist.next; pUndoEntity != NULL && pUndoEntity != &undo->entitylist; pUndoEntity = pUndoEntity->next) + { + // move brushes to the undo entity + if (pUndoEntity->entityId == pEntity->entityId) + { + pUndoEntity->brushes.next = pEntity->brushes.next; + pUndoEntity->brushes.prev = pEntity->brushes.prev; + pEntity->brushes.next = &pEntity->brushes; + pEntity->brushes.prev = &pEntity->brushes; + } + } + // + //Entity_Free(pEntity); + //move the entity to the redo + Entity_RemoveFromList(pEntity); + Entity_AddToList(pEntity, &redo->entitylist); + } + } + // add the undo entities back into the entity list + for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = undo->entitylist.next) + { + g_undoMemorySize -= Entity_MemorySize(pEntity); + //if this is the world entity + if (pEntity->entityId == world_entity->entityId) + { + epair_t* tmp = world_entity->epairs; + world_entity->epairs = pEntity->epairs; + pEntity->epairs = tmp; + Entity_Free(pEntity); + } + else + { + Entity_RemoveFromList(pEntity); + Entity_AddToList(pEntity, &entities); + pEntity->redoId = redo->id; + } + } + // add the undo brushes back into the selected brushes + for (pBrush = undo->brushlist.next; pBrush != NULL && pBrush != &undo->brushlist; pBrush = undo->brushlist.next) + { + //Sys_Printf("Owner ID: %i\n",pBrush->ownerId); + g_undoMemorySize -= Brush_MemorySize(pBrush); + Brush_RemoveFromList(pBrush); + Brush_AddToList(pBrush, &active_brushes); + for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next) // fixes broken undo on entities + { + //Sys_Printf("Entity ID: %i\n",pEntity->entityId); + if (pEntity->entityId == pBrush->ownerId) + { + Entity_LinkBrush(pEntity, pBrush); + break; + } + } + //if the brush is not linked then it should be linked into the world entity + //++timo FIXME: maybe not, maybe we've lost this entity's owner! + if (pEntity == NULL || pEntity == &entities) + { + Entity_LinkBrush(world_entity, pBrush); + } + //build the brush + //Brush_Build(pBrush); + Select_Brush(pBrush); + pBrush->redoId = redo->id; + } + if (!bSilent) + Sys_Printf("%s undone.\n", undo->operation); + // free the undo + g_undoMemorySize -= sizeof(undo_t); + free(undo); + g_undoSize--; + g_undoId--; + if (g_undoId <= 0) g_undoId = 2 * g_undoMaxSize; + // + g_bScreenUpdates = true; + UpdateSurfaceDialog(); + Sys_UpdateWindows(W_ALL); +} + +/* +============= +Undo_Redo +============= +*/ +void Undo_Redo(void) +{ + // spog - disable undo if undo levels = 0 + if (g_PrefsDlg.m_nUndoLevels == 0) + { + Sys_Printf("Undo_Redo: undo is disabled.\n"); + return; + } + + undo_t *redo; + brush_t *pBrush, *pNextBrush; + entity_t *pEntity, *pNextEntity, *pRedoEntity; + + if (!g_lastredo) + { + Sys_Printf("Nothing left to redo.\n"); + return; + } + if (g_lastundo) + { + if (!g_lastundo->done) + { + Sys_Printf("WARNING: last undo not finished.\n"); + } + } + // get the last redo + redo = g_lastredo; + if (g_lastredo->prev) g_lastredo->prev->next = NULL; + else g_redolist = NULL; + g_lastredo = g_lastredo->prev; + // + Undo_GeneralStart(redo->operation); + // remove current selection + Select_Deselect(); + // move "created" brushes back to the last undo + for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush = pNextBrush) + { + pNextBrush = pBrush->next; + if (pBrush->redoId == redo->id) + { + //move the brush to the undo + Brush_RemoveFromList(pBrush); + Brush_AddToList(pBrush, &g_lastundo->brushlist); + g_undoMemorySize += Brush_MemorySize(pBrush); + pBrush->ownerId = pBrush->owner->entityId; + Entity_UnlinkBrush(pBrush); + } + } + // move "created" entities back to the last undo + for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pNextEntity) + { + pNextEntity = pEntity->next; + if (pEntity->redoId == redo->id) + { + // check if this entity is in the redo + for (pRedoEntity = redo->entitylist.next; pRedoEntity != NULL && pRedoEntity != &redo->entitylist; pRedoEntity = pRedoEntity->next) + { + // move brushes to the redo entity + if (pRedoEntity->entityId == pEntity->entityId) + { + pRedoEntity->brushes.next = pEntity->brushes.next; + pRedoEntity->brushes.prev = pEntity->brushes.prev; + pEntity->brushes.next = &pEntity->brushes; + pEntity->brushes.prev = &pEntity->brushes; + } + } + // + //Entity_Free(pEntity); + //move the entity to the redo + Entity_RemoveFromList(pEntity); + Entity_AddToList(pEntity, &g_lastundo->entitylist); + g_undoMemorySize += Entity_MemorySize(pEntity); + } + } + // add the undo entities back into the entity list + for (pEntity = redo->entitylist.next; pEntity != NULL && pEntity != &redo->entitylist; pEntity = redo->entitylist.next) + { + //if this is the world entity + if (pEntity->entityId == world_entity->entityId) + { + epair_t* tmp = world_entity->epairs; + world_entity->epairs = pEntity->epairs; + pEntity->epairs = tmp; + Entity_Free(pEntity); + } + else + { + Entity_RemoveFromList(pEntity); + Entity_AddToList(pEntity, &entities); + } + } + // add the redo brushes back into the selected brushes + for (pBrush = redo->brushlist.next; pBrush != NULL && pBrush != &redo->brushlist; pBrush = redo->brushlist.next) + { + Brush_RemoveFromList(pBrush); + Brush_AddToList(pBrush, &active_brushes); + for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next) // fixes broken undo on entities + { + if (pEntity->entityId == pBrush->ownerId) + { + Entity_LinkBrush(pEntity, pBrush); + break; + } + } + //if the brush is not linked then it should be linked into the world entity + if (pEntity == NULL || pEntity == &entities) + { + Entity_LinkBrush(world_entity, pBrush); + } + //build the brush + //Brush_Build(pBrush); + Select_Brush(pBrush); + } + // + Undo_End(); + // + Sys_Printf("%s redone.\n", redo->operation); + // + g_redoId--; + // free the undo + free(redo); + // + g_bScreenUpdates = true; + UpdateSurfaceDialog(); + Sys_UpdateWindows(W_ALL); +} + +/* +============= +Undo_RedoAvailable +============= +*/ +int Undo_RedoAvailable(void) +{ + if (g_lastredo) return true; + return false; +} + +int Undo_GetUndoId(void) +{ + if (g_lastundo) + return g_lastundo->id; + return 0; +} + +/* +============= +Undo_UndoAvailable +============= +*/ +int Undo_UndoAvailable(void) +{ + if (g_lastundo) + { + if (g_lastundo->done) + return true; + } + return false; +} diff --git a/radiant/vertsel.cpp b/radiant/vertsel.cpp index 75b968e7..ae7d5362 100644 --- a/radiant/vertsel.cpp +++ b/radiant/vertsel.cpp @@ -1,386 +1,386 @@ -/* -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 -*/ - -#include "stdafx.h" -//#include "qe3.h" -#include "winding.h" - -int FindPoint (vec3_t point) -{ - int i, j; - - for (i=0 ; i 0.1) - break; - if (j == 3) - return i; - } - - VectorCopy (point, g_qeglobals.d_points[g_qeglobals.d_numpoints]); - //qeglobals.d_points[g_qeglobals.d_numpoints] = point; - if (g_qeglobals.d_numpoints < MAX_POINTS-1) - { - g_qeglobals.d_numpoints++; - } - - return g_qeglobals.d_numpoints-1; -} - -//#define DBG_WNDG -int FindEdge (int p1, int p2, face_t *f) -{ - int i; - - for (i=0 ; inumpoints ; i++) - pnum[i] = FindPoint (w->points[i]); - for (i=0 ; inumpoints ; i++) - FindEdge (pnum[i], pnum[(i+1)%w->numpoints], f); - - free (w); -} - -void SetupVertexSelection (void) -{ - face_t *f; - brush_t *b; - - g_qeglobals.d_numpoints = 0; - g_qeglobals.d_numedges = 0; - - for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - { - if (b->patchBrush || b->owner->eclass->fixedsize) - continue; // don't make edge and vertex handles for patchbrushes - for (f=b->brush_faces ; f ; f=f->next) - MakeFace (b,f); - } -} - -void SelectFaceEdge (brush_t* b, face_t *f, int p1, int p2) -{ - winding_t *w; - int i, j, k; - int pnum[128]; - -#ifdef DBG_WNDG - if (f==NULL) - Sys_Printf("SelectFaceEdge %p %p\n", b, f); -#endif - - w = Winding_Clone(f->face_winding);//Brush_MakeFaceWinding (b, f); - if (!w) - return; - for (i=0 ; inumpoints ; i++) - pnum[i] = FindPoint (w->points[i]); - - for (i=0 ; inumpoints ; i++) - if (pnum[i] == p1 && pnum[(i+1)%w->numpoints] == p2) - { - VectorCopy (g_qeglobals.d_points[pnum[i]], f->planepts[0]); - VectorCopy (g_qeglobals.d_points[pnum[(i+1)%w->numpoints]], f->planepts[1]); - VectorCopy (g_qeglobals.d_points[pnum[(i+2)%w->numpoints]], f->planepts[2]); - for (j=0 ; j<3 ; j++) - { - for (k=0 ; k<3 ; k++) - { - f->planepts[j][k] = floor(f->planepts[j][k]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; - } - } - - AddPlanept (f->planepts[0]); - AddPlanept (f->planepts[1]); - break; - } - - if (i == w->numpoints) - Sys_Printf ("SelectFaceEdge: failed\n"); - Winding_Free (w); -} - - -void SelectVertex (int p1) -{ - brush_t *b; - winding_t *w; - int i; - face_t *f; - - for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - { - for (f=b->brush_faces ; f ; f=f->next) - { - w = Brush_MakeFaceWinding (b, f); - if (!w) - continue; - for (i=0 ; inumpoints ; i++) - { - if (FindPoint (w->points[i]) == p1) - { - VectorCopy (w->points[(i+w->numpoints-1)%w->numpoints], f->planepts[0]); - VectorCopy (w->points[i], f->planepts[1]); - VectorCopy (w->points[(i+1)%w->numpoints], f->planepts[2]); - // NOTE: used to be a planepts clamping to grid here - - AddPlanept (f->planepts[1]); - - break; - } - } - free (w); - } - } -} - -#define SELECT_EPSILON 8 - -void SelectVertexByRay (vec3_t org, vec3_t dir) -{ - int i, besti; - float d, bestd = VEC_MAX; - vec_t epsilon, divergence; - ray_t ray; - ray_construct_for_vec3(&ray, org, dir); - - // find the point closest to the ray - besti = -1; - if ((fabs(org[0]) == g_MaxWorldCoord || fabs(org[1]) == g_MaxWorldCoord || fabs(org[2]) == g_MaxWorldCoord) - && (fabs(dir[0]) == 1.0f || fabs(dir[1]) == 1.0f || fabs(dir[2]) == 1.0f)) // very unlikely unless 2d view - { - divergence = 0; - epsilon = SELECT_EPSILON / g_pParentWnd->GetXYWnd()->Scale(); // compensate for zoom level - } - else - { - divergence = SELECT_EPSILON / (g_pParentWnd->GetCamWnd()->Camera()->width*0.5); // radius / focal length - epsilon = 0; - } - - for (i=0 ; iGetXYWnd()->Scale(); // compensate for zoom level - } - else - { - divergence = SELECT_EPSILON / (g_pParentWnd->GetCamWnd()->Camera()->width*0.5); // radius / focal length - epsilon = 0; - } - - - g_qeglobals.d_numpoints = 0; - - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) - { - if (pb->patchBrush) - { - patchMesh_t* p = pb->pPatch; - - for (i = 0 ; i < p->width ; i++ ) - { - for ( j = 0 ; j < p->height ; j++ ) - { - d = ray_intersect_point(&ray, p->ctrl[i][j].xyz, epsilon, divergence); - - if (d >= bestd) - continue; - - bestd = d; - - if (PointInMoveList(*pPointBest) != -1 && PointInMoveList(p->ctrl[i][j].xyz) == -1) - continue; // choose selected points with preference over unselected - - pPointBest = &p->ctrl[i][j].xyz; - - } - } - } - } - - if (pPointBest == NULL) - { - if (g_pParentWnd->ActiveXY()->AreaSelectOK()) - { - g_qeglobals.d_select_mode = sel_area; - VectorCopy(org, g_qeglobals.d_vAreaTL); - VectorCopy(org, g_qeglobals.d_vAreaBR); - } - return; - } - else - AddPatchMovePoint(pPointBest[0], buttons & MK_CONTROL, buttons & MK_SHIFT); -} - -// optimization bug: -// had to use the #define DBG_WNDG to identify -// the first loop that checks the best edge is broken in release-optimized build -// unrolled the mid[] loop and forced floating consistency on seems to fix -#ifdef _WIN32 -#pragma optimize( "p", on ) -#endif -void SelectEdgeByRay (vec3_t org, vec3_t dir) -{ - int i, besti; - float d, bestd = VEC_MAX; - vec3_t mid; - pedge_t *e; - vec_t epsilon, divergence; - ray_t ray; - ray_construct_for_vec3(&ray, org, dir); - - // find the edge closest to the ray - besti = -1; - if ((fabs(org[0]) == g_MaxWorldCoord || fabs(org[1]) == g_MaxWorldCoord || fabs(org[2]) == g_MaxWorldCoord) - && (fabs(dir[0]) == 1.0f || fabs(dir[1]) == 1.0f || fabs(dir[2]) == 1.0f)) // very unlikely unless 2d view - { - divergence = 0; - epsilon = SELECT_EPSILON / g_pParentWnd->GetXYWnd()->Scale(); // compensate for zoom level - } - else - { - divergence = SELECT_EPSILON / (g_pParentWnd->GetCamWnd()->Camera()->width*0.5); // radius / focal length - epsilon = 0; - } - - for (i=0 ; if1 == NULL) - { - Sys_Printf ("e->f1 == NULL e->f2 %p\n", e->f2); - } - if (e->f2 == NULL) - { - Sys_Printf ("e->f1 %p e->f2 == NULL\n",e->f1); - } -#endif - for (brush_t* b=selected_brushes.next ; b != &selected_brushes ; b=b->next) - { - SelectFaceEdge (b, e->f1, e->p1, e->p2); - SelectFaceEdge (b, e->f2, e->p2, e->p1); - } -} +/* +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 +*/ + +#include "stdafx.h" +//#include "qe3.h" +#include "winding.h" + +int FindPoint (vec3_t point) +{ + int i, j; + + for (i=0 ; i 0.1) + break; + if (j == 3) + return i; + } + + VectorCopy (point, g_qeglobals.d_points[g_qeglobals.d_numpoints]); + //qeglobals.d_points[g_qeglobals.d_numpoints] = point; + if (g_qeglobals.d_numpoints < MAX_POINTS-1) + { + g_qeglobals.d_numpoints++; + } + + return g_qeglobals.d_numpoints-1; +} + +//#define DBG_WNDG +int FindEdge (int p1, int p2, face_t *f) +{ + int i; + + for (i=0 ; inumpoints ; i++) + pnum[i] = FindPoint (w->points[i]); + for (i=0 ; inumpoints ; i++) + FindEdge (pnum[i], pnum[(i+1)%w->numpoints], f); + + free (w); +} + +void SetupVertexSelection (void) +{ + face_t *f; + brush_t *b; + + g_qeglobals.d_numpoints = 0; + g_qeglobals.d_numedges = 0; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + if (b->patchBrush || b->owner->eclass->fixedsize) + continue; // don't make edge and vertex handles for patchbrushes + for (f=b->brush_faces ; f ; f=f->next) + MakeFace (b,f); + } +} + +void SelectFaceEdge (brush_t* b, face_t *f, int p1, int p2) +{ + winding_t *w; + int i, j, k; + int pnum[128]; + +#ifdef DBG_WNDG + if (f==NULL) + Sys_Printf("SelectFaceEdge %p %p\n", b, f); +#endif + + w = Winding_Clone(f->face_winding);//Brush_MakeFaceWinding (b, f); + if (!w) + return; + for (i=0 ; inumpoints ; i++) + pnum[i] = FindPoint (w->points[i]); + + for (i=0 ; inumpoints ; i++) + if (pnum[i] == p1 && pnum[(i+1)%w->numpoints] == p2) + { + VectorCopy (g_qeglobals.d_points[pnum[i]], f->planepts[0]); + VectorCopy (g_qeglobals.d_points[pnum[(i+1)%w->numpoints]], f->planepts[1]); + VectorCopy (g_qeglobals.d_points[pnum[(i+2)%w->numpoints]], f->planepts[2]); + for (j=0 ; j<3 ; j++) + { + for (k=0 ; k<3 ; k++) + { + f->planepts[j][k] = floor(f->planepts[j][k]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; + } + } + + AddPlanept (f->planepts[0]); + AddPlanept (f->planepts[1]); + break; + } + + if (i == w->numpoints) + Sys_Printf ("SelectFaceEdge: failed\n"); + Winding_Free (w); +} + + +void SelectVertex (int p1) +{ + brush_t *b; + winding_t *w; + int i; + face_t *f; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + for (f=b->brush_faces ; f ; f=f->next) + { + w = Brush_MakeFaceWinding (b, f); + if (!w) + continue; + for (i=0 ; inumpoints ; i++) + { + if (FindPoint (w->points[i]) == p1) + { + VectorCopy (w->points[(i+w->numpoints-1)%w->numpoints], f->planepts[0]); + VectorCopy (w->points[i], f->planepts[1]); + VectorCopy (w->points[(i+1)%w->numpoints], f->planepts[2]); + // NOTE: used to be a planepts clamping to grid here + + AddPlanept (f->planepts[1]); + + break; + } + } + free (w); + } + } +} + +#define SELECT_EPSILON 8 + +void SelectVertexByRay (vec3_t org, vec3_t dir) +{ + int i, besti; + float d, bestd = VEC_MAX; + vec_t epsilon, divergence; + ray_t ray; + ray_construct_for_vec3(&ray, org, dir); + + // find the point closest to the ray + besti = -1; + if ((fabs(org[0]) == g_MaxWorldCoord || fabs(org[1]) == g_MaxWorldCoord || fabs(org[2]) == g_MaxWorldCoord) + && (fabs(dir[0]) == 1.0f || fabs(dir[1]) == 1.0f || fabs(dir[2]) == 1.0f)) // very unlikely unless 2d view + { + divergence = 0; + epsilon = SELECT_EPSILON / g_pParentWnd->GetXYWnd()->Scale(); // compensate for zoom level + } + else + { + divergence = SELECT_EPSILON / (g_pParentWnd->GetCamWnd()->Camera()->width*0.5); // radius / focal length + epsilon = 0; + } + + for (i=0 ; iGetXYWnd()->Scale(); // compensate for zoom level + } + else + { + divergence = SELECT_EPSILON / (g_pParentWnd->GetCamWnd()->Camera()->width*0.5); // radius / focal length + epsilon = 0; + } + + + g_qeglobals.d_numpoints = 0; + + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next) + { + if (pb->patchBrush) + { + patchMesh_t* p = pb->pPatch; + + for (i = 0 ; i < p->width ; i++ ) + { + for ( j = 0 ; j < p->height ; j++ ) + { + d = ray_intersect_point(&ray, p->ctrl[i][j].xyz, epsilon, divergence); + + if (d >= bestd) + continue; + + bestd = d; + + if (PointInMoveList(*pPointBest) != -1 && PointInMoveList(p->ctrl[i][j].xyz) == -1) + continue; // choose selected points with preference over unselected + + pPointBest = &p->ctrl[i][j].xyz; + + } + } + } + } + + if (pPointBest == NULL) + { + if (g_pParentWnd->ActiveXY()->AreaSelectOK()) + { + g_qeglobals.d_select_mode = sel_area; + VectorCopy(org, g_qeglobals.d_vAreaTL); + VectorCopy(org, g_qeglobals.d_vAreaBR); + } + return; + } + else + AddPatchMovePoint(pPointBest[0], buttons & MK_CONTROL, buttons & MK_SHIFT); +} + +// optimization bug: +// had to use the #define DBG_WNDG to identify +// the first loop that checks the best edge is broken in release-optimized build +// unrolled the mid[] loop and forced floating consistency on seems to fix +#ifdef _WIN32 +#pragma optimize( "p", on ) +#endif +void SelectEdgeByRay (vec3_t org, vec3_t dir) +{ + int i, besti; + float d, bestd = VEC_MAX; + vec3_t mid; + pedge_t *e; + vec_t epsilon, divergence; + ray_t ray; + ray_construct_for_vec3(&ray, org, dir); + + // find the edge closest to the ray + besti = -1; + if ((fabs(org[0]) == g_MaxWorldCoord || fabs(org[1]) == g_MaxWorldCoord || fabs(org[2]) == g_MaxWorldCoord) + && (fabs(dir[0]) == 1.0f || fabs(dir[1]) == 1.0f || fabs(dir[2]) == 1.0f)) // very unlikely unless 2d view + { + divergence = 0; + epsilon = SELECT_EPSILON / g_pParentWnd->GetXYWnd()->Scale(); // compensate for zoom level + } + else + { + divergence = SELECT_EPSILON / (g_pParentWnd->GetCamWnd()->Camera()->width*0.5); // radius / focal length + epsilon = 0; + } + + for (i=0 ; if1 == NULL) + { + Sys_Printf ("e->f1 == NULL e->f2 %p\n", e->f2); + } + if (e->f2 == NULL) + { + Sys_Printf ("e->f1 %p e->f2 == NULL\n",e->f1); + } +#endif + for (brush_t* b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + SelectFaceEdge (b, e->f1, e->p1, e->p2); + SelectFaceEdge (b, e->f2, e->p2, e->p1); + } +} diff --git a/radiant/watchbsp.cpp b/radiant/watchbsp.cpp index 08e3ce31..3dfd6f20 100644 --- a/radiant/watchbsp.cpp +++ b/radiant/watchbsp.cpp @@ -1,774 +1,774 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// monitoring window for running BSP processes (and possibly various other stuff) - -#include "stdafx.h" -#include "watchbsp.h" -#include "feedback.h" - -#ifdef _WIN32 -#include -#endif - -#if defined (__linux__) || defined (__APPLE__) -#include -#define SOCKET_ERROR -1 -#endif - -#ifdef __APPLE__ -#include -#endif - -#include - -// Static functions for the SAX callbacks ------------------------------------------------------- - -// utility for saxStartElement below -static void abortStream(message_info_t *data) -{ - g_pParentWnd->GetWatchBSP()->Reset(); - // tell there has been an error - if (g_pParentWnd->GetWatchBSP()->HasBSPPlugin ()) - g_BSPFrontendTable.m_pfnEndListen(2); - // yeah this doesn't look good.. but it's needed so that everything will be ignored until the stream goes out - data->ignore_depth = -1; - data->recurse++; -} - -#include "stream_version.h" - -static void saxStartElement(message_info_t *data, const xmlChar *name, const xmlChar **attrs) -{ - if (data->ignore_depth == 0) - { - if (data->bGeometry) - // we have a handler - { - data->pGeometry->saxStartElement (data, name, attrs); - } - else - { - if (strcmp ((char *)name, "q3map_feedback") == 0) - { - // check the correct version - // old q3map don't send a version attribute - // the ones we support .. send Q3MAP_STREAM_VERSION - if (!attrs[0] || !attrs[1] || (strcmp((char*)attrs[0],"version") != 0)) - { - Sys_FPrintf(SYS_ERR, "No stream version given in the feedback stream, this is an old q3map version.\n" - "Please turn off monitored compiling if you still wish to use this q3map executable\n"); - abortStream(data); - return; - } - else if (strcmp((char*)attrs[1],Q3MAP_STREAM_VERSION) != 0) - { - Sys_FPrintf(SYS_ERR, - "This version of Radiant reads version %s debug streams, I got an incoming connection with version %s\n" - "Please make sure your versions of Radiant and q3map are matching.\n", Q3MAP_STREAM_VERSION, (char*)attrs[1]); - abortStream(data); - return; - } - } - // we don't treat locally - else if (strcmp ((char *)name, "message") == 0) - { - data->msg_level = atoi ((char *)attrs[1]); - } - else if (strcmp ((char *)name, "polyline") == 0) - // polyline has a particular status .. right now we only use it for leakfile .. - { - data->bGeometry = true; - data->pGeometry = &g_pointfile; - data->pGeometry->saxStartElement (data, name, attrs); - } - else if (strcmp ((char *)name, "select") == 0) - { - CSelectMsg *pSelect = new CSelectMsg(); - data->bGeometry = true; - data->pGeometry = pSelect; - data->pGeometry->saxStartElement (data, name, attrs); - } - else if (strcmp ((char *)name, "pointmsg") == 0) - { - CPointMsg *pPoint = new CPointMsg(); - data->bGeometry = true; - data->pGeometry = pPoint; - data->pGeometry->saxStartElement (data, name, attrs); - } - else if (strcmp ((char *)name, "windingmsg") == 0) - { - CWindingMsg *pWinding = new CWindingMsg(); - data->bGeometry = true; - data->pGeometry = pWinding; - data->pGeometry->saxStartElement (data, name, attrs); - } - else - { - Sys_FPrintf (SYS_WRN, "WARNING: ignoring unrecognized node in XML stream (%s)\n", name); - // we don't recognize this node, jump over it - // (NOTE: the ignore mechanism is a bit screwed, only works when starting an ignore at the highest level) - data->ignore_depth = data->recurse; - } - } - } - data->recurse++; -} - -static void saxEndElement(message_info_t *data, const xmlChar *name) -{ - data->recurse--; - // we are out of an ignored chunk - if (data->recurse == data->ignore_depth) - { - data->ignore_depth = 0; - return; - } - if (data->bGeometry) - { - data->pGeometry->saxEndElement (data, name); - // we add the object to the debug window - if (!data->bGeometry) - { - g_DbgDlg.Push (data->pGeometry); - } - } - if (data->recurse == data->stop_depth) - { -#ifdef _DEBUG - Sys_Printf ("Received error msg .. shutting down..\n"); -#endif - g_pParentWnd->GetWatchBSP()->Reset(); - // tell there has been an error - if (g_pParentWnd->GetWatchBSP()->HasBSPPlugin ()) - g_BSPFrontendTable.m_pfnEndListen(2); - return; - } -} - -static void saxCharacters(message_info_t *data, const xmlChar *ch, int len) -{ - if (data->bGeometry) - { - data->pGeometry->saxCharacters (data, ch, len); - } - else - { - if (data->ignore_depth != 0) - return; - // output the message using the level - char buf[1024]; - memcpy( buf, ch, len ); - buf[len] = '\0'; - Sys_FPrintf (data->msg_level, "%s", buf); - // if this message has error level flag, we mark the depth to stop the compilation when we get out - // we don't set the msg level if we don't stop on leak - if (data->msg_level == 3) - { - data->stop_depth = data->recurse-1; - } - } -} - -static void saxComment(void *ctx, const xmlChar *msg) -{ - Sys_Printf("XML comment: %s\n", msg); -} - -static void saxWarning(void *ctx, const char *msg, ...) -{ - char saxMsgBuffer[4096]; - va_list args; - - va_start(args, msg); - vsprintf (saxMsgBuffer, msg, args); - va_end(args); - Sys_FPrintf(SYS_WRN, "XML warning: %s\n", saxMsgBuffer); -} - -static void saxError(void *ctx, const char *msg, ...) -{ - char saxMsgBuffer[4096]; - va_list args; - - va_start(args, msg); - vsprintf (saxMsgBuffer, msg, args); - va_end(args); - Sys_FPrintf(SYS_ERR, "XML error: %s\n", saxMsgBuffer); -} - -static void saxFatal(void *ctx, const char *msg, ...) -{ - char buffer[4096]; - - va_list args; - - va_start(args, msg); - vsprintf (buffer, msg, args); - va_end(args); - Sys_FPrintf(SYS_ERR, "XML fatal error: %s\n", buffer); -} - -static xmlSAXHandler saxParser = { - 0, /* internalSubset */ - 0, /* isStandalone */ - 0, /* hasInternalSubset */ - 0, /* hasExternalSubset */ - 0, /* resolveEntity */ - 0, /* getEntity */ - 0, /* entityDecl */ - 0, /* notationDecl */ - 0, /* attributeDecl */ - 0, /* elementDecl */ - 0, /* unparsedEntityDecl */ - 0, /* setDocumentLocator */ - 0, /* startDocument */ - 0, /* endDocument */ - (startElementSAXFunc)saxStartElement, /* startElement */ - (endElementSAXFunc)saxEndElement, /* endElement */ - 0, /* reference */ - (charactersSAXFunc)saxCharacters, /* characters */ - 0, /* ignorableWhitespace */ - 0, /* processingInstruction */ - (commentSAXFunc)saxComment, /* comment */ - (warningSAXFunc)saxWarning, /* warning */ - (errorSAXFunc)saxError, /* error */ - (fatalErrorSAXFunc)saxFatal, /* fatalError */ -}; - -// ------------------------------------------------------------------------------------------------ - -CWatchBSP::~CWatchBSP() -{ - Reset(); - if (m_sBSPName) - { - delete[] m_sBSPName; - m_sBSPName = NULL; - } - Net_Shutdown(); -} - -void CWatchBSP::Reset() -{ - if (m_pInSocket) - { - Net_Disconnect(m_pInSocket); - m_pInSocket = NULL; - } - if (m_pListenSocket) - { - Net_Disconnect(m_pListenSocket); - m_pListenSocket = NULL; - } - if (m_xmlInputBuffer) - { - xmlFreeParserInputBuffer (m_xmlInputBuffer); - m_xmlInputBuffer = NULL; - } - m_eState = EIdle; -} - -bool CWatchBSP::SetupListening() -{ -#ifdef _DEBUG - if (m_pListenSocket) - { - Sys_Printf("ERROR: m_pListenSocket != NULL in CWatchBSP::SetupListening\n"); - return false; - } -#endif - Sys_Printf("Setting up\n"); - Net_Setup(); - m_pListenSocket = Net_ListenSocket(39000); - if (m_pListenSocket == NULL) - return false; - Sys_Printf("Listening...\n"); - return true; -} - -void CWatchBSP::DoEBeginStep() -{ - Reset(); - if (SetupListening() == false) - { - CString msg; - msg = "Failed to get a listening socket on port 39000.\nTry running with BSP monitoring disabled if you can't fix this.\n"; - Sys_Printf (msg); - gtk_MessageBox (g_pParentWnd->m_pWidget, msg, "BSP monitoring", MB_OK | MB_ICONERROR); - return; - } - // set the timer for timeouts and step cancellation - g_timer_reset( m_pTimer ); - g_timer_start( m_pTimer ); - - if (!m_bBSPPlugin) - { - Sys_Printf("=== running BSP command ===\n%s\n", g_ptr_array_index( m_pCmd, m_iCurrentStep ) ); - - if (!Q_Exec(NULL, (char *)g_ptr_array_index( m_pCmd, m_iCurrentStep ), NULL, true )) - { - CString msg; - msg = "Failed to execute the following command: "; - msg += (char *)g_ptr_array_index( m_pCmd, m_iCurrentStep ); - msg += "\nCheck that the file exists and that you don't run out of system resources.\n"; - Sys_Printf(msg); - gtk_MessageBox(g_pParentWnd->m_pWidget, msg, "BSP monitoring", MB_OK | MB_ICONERROR ); - return; - } - // re-initialise the debug window - if (m_iCurrentStep == 0) - g_DbgDlg.Init(); - } - m_eState = EBeginStep; -} - -void CWatchBSP::RoutineProcessing() -{ - // used for select() -#ifdef _WIN32 - TIMEVAL tout = { 0, 0 }; -#endif -#if defined (__linux__) || defined (__APPLE__) - timeval tout; - tout.tv_sec = 0; - tout.tv_usec = 0; -#endif - - switch (m_eState) - { - case EBeginStep: - // timeout: if we don't get an incoming connection fast enough, go back to idle - if ( g_timer_elapsed( m_pTimer, NULL ) > g_PrefsDlg.m_iTimeout ) - { - gtk_MessageBox(g_pParentWnd->m_pWidget, "The connection timed out, assuming the BSP process failed\nMake sure you are using a networked version of Q3Map?\nOtherwise you need to disable BSP Monitoring in prefs.", "BSP process monitoring", MB_OK ); - Reset(); - if (m_bBSPPlugin) - { - // status == 1 : didn't get the connection - g_BSPFrontendTable.m_pfnEndListen(1); - } - return; - } -#ifdef _DEBUG - // some debug checks - if (!m_pListenSocket) - { - Sys_Printf("ERROR: m_pListenSocket == NULL in CWatchBSP::RoutineProcessing EBeginStep state\n"); - return; - } -#endif - // we are not connected yet, accept any incoming connection - m_pInSocket = Net_Accept(m_pListenSocket); - if (m_pInSocket) - { - Sys_Printf("Connected.\n"); - // prepare the message info struct for diving in - memset (&m_message_info, 0, sizeof(message_info_s)); - // a dumb flag to make sure we init the push parser context when first getting a msg - m_bNeedCtxtInit = true; - m_eState = EWatching; - } - break; - case EWatching: -#ifdef _DEBUG - // some debug checks - if (!m_pInSocket) - { - Sys_Printf("ERROR: m_pInSocket == NULL in CWatchBSP::RoutineProcessing EWatching state\n"); - return; - } -#endif - // select() will identify if the socket needs an update - // if the socket is identified that means there's either a message or the connection has been closed/reset/terminated - fd_set readfds; - int ret; - FD_ZERO(&readfds); - FD_SET(((unsigned int)m_pInSocket->socket), &readfds); - // from select man page: - // n is the highest-numbered descriptor in any of the three sets, plus 1 - // (no use on windows) - ret = select( m_pInSocket->socket + 1, &readfds, NULL, NULL, &tout ); - if (ret == SOCKET_ERROR) - { - Sys_Printf("WARNING: SOCKET_ERROR in CWatchBSP::RoutineProcessing\n"); - Sys_Printf("Terminating the connection.\n"); - Reset(); - return; - } -#ifdef _DEBUG - if (ret == -1) - { - // we are non-blocking?? we should never get timeout errors - Sys_Printf("WARNING: unexpected timeout expired in CWatchBSP::Processing\n"); - Sys_Printf("Terminating the connection.\n"); - Reset(); - return; - } -#endif - if (ret == 1) - { - // the socket has been identified, there's something (message or disconnection) - // see if there's anything in input - ret = Net_Receive( m_pInSocket, &msg ); - if (ret > 0) - { - // unsigned int size = msg.size; //++timo just a check - strcpy (m_xmlBuf, NMSG_ReadString (&msg)); - if (m_bNeedCtxtInit) - { - m_xmlParserCtxt = NULL; - m_xmlParserCtxt = xmlCreatePushParserCtxt (&saxParser, &m_message_info, m_xmlBuf, strlen(m_xmlBuf), NULL); - if (m_xmlParserCtxt == NULL) - { - Sys_FPrintf (SYS_ERR, "Failed to create the XML parser (incoming stream began with: %s)\n", m_xmlBuf); - Reset(); - } - m_bNeedCtxtInit = false; - } - else - { - xmlParseChunk (m_xmlParserCtxt, m_xmlBuf, strlen(m_xmlBuf), 0); - } - } - else - { - // error or connection closed/reset - // NOTE: if we get an error down the XML stream we don't reach here - Net_Disconnect( m_pInSocket ); - m_pInSocket = NULL; - Sys_Printf("Connection closed.\n"); - if (m_bBSPPlugin) - { - Reset(); - // let the BSP plugin know that the job is done - g_BSPFrontendTable.m_pfnEndListen(0); - return; - } - // move to next step or finish - m_iCurrentStep++; - if (m_iCurrentStep < m_pCmd->len ) - { - DoEBeginStep(); - } - else - { - // release the GPtrArray and the strings - if (m_pCmd != NULL) - { - for (m_iCurrentStep=0; m_iCurrentStep < m_pCmd->len; m_iCurrentStep++ ) - { - delete[] (char *)g_ptr_array_index( m_pCmd, m_iCurrentStep ); - } - g_ptr_array_free( m_pCmd, false ); - } - m_pCmd = NULL; - // launch the engine .. OMG - if (g_PrefsDlg.m_bRunQuake) - { - // do we enter sleep mode before? - if (g_PrefsDlg.m_bDoSleep) - { - Sys_Printf("Going into sleep mode..\n"); - g_pParentWnd->OnSleep(); - } - Sys_Printf("Running engine...\n"); - Str cmd; - // build the command line - cmd = g_pGameDescription->mEnginePath.GetBuffer(); - // this is game dependant - //!\todo Read the engine binary name from a config file. - if (g_pGameDescription->mGameFile == "wolf.game") - { - if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"),"mp")) - { - // MP -#if defined(WIN32) - cmd += "WolfMP.exe"; -#elif defined(__linux__) - cmd += "wolfmp"; -#elif defined(__APPLE__) - cmd += "wolfmp.app"; -#else -#error "WTF are you compiling on" -#endif - } - else - { - // SP -#if defined(WIN32) - cmd += "WolfSP.exe"; -#elif defined(__linux__) - cmd += "wolfsp"; -#elif defined(__APPLE__) - cmd += "wolfsp.app"; -#else -#error "WTF are you compiling on" -#endif - } - } else if (g_pGameDescription->mGameFile == "et.game") - { -#if defined(WIN32) - cmd += "et.exe"; -#elif defined(__linux__) - cmd += "et"; -#elif defined(__APPLE__) - cmd += "et.app"; -#else -#error "WTF are you compiling on" -#endif - } - // RIANT - // JK2 HACK - else if (g_pGameDescription->mGameFile == "jk2.game") - { - if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"),"mp")) - { - // MP -#if defined(WIN32) - cmd += "jk2MP.exe"; -#elif defined(__linux__) - cmd += "jk2mp"; -#elif defined(__APPLE__) - cmd += "jk2mp.app"; -#else -#error "WTF are you compiling on" -#endif - } - else - { - // SP -#if defined(WIN32) - cmd += "jk2SP.exe"; -#elif defined(__linux__) - cmd += "jk2sp"; -#elif defined(__APPLE__) - cmd += "jk2sp.app"; -#else -#error "WTF are you compiling on" -#endif - } - } - // TTimo - // JA HACK - else if (g_pGameDescription->mGameFile == "ja.game") - { - if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"),"mp")) - { - // MP -#if defined(WIN32) - cmd += "jamp.exe"; -#elif !defined(__linux__) && !defined(__APPLE__) -#error "WTF are you compiling on" -#endif - } - else - { - // SP -#if defined(WIN32) - cmd += "jasp.exe"; -#elif !defined(__linux__) && !defined(__APPLE__) -#error "WTF are you compiling on" -#endif - } - } - // RIANT - // STVEF HACK - else if (g_pGameDescription->mGameFile == "stvef.game") - { - if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"),"mp")) - { - // MP -#if defined(WIN32) - cmd += "stvoyHM.exe"; -#elif defined(__linux__) - cmd += "stvoyHM"; -#elif defined(__APPLE__) - cmd += "stvoyHM.app"; -#else -#error "WTF are you compiling on" -#endif - } - else - { - // SP -#if defined(WIN32) - cmd += "stvoy.exe"; -#elif defined(__linux__) - cmd += "stvoy"; -#elif defined(__APPLE__) - cmd += "stvoy.app"; -#else -#error "WTF are you compiling on" -#endif - } - } - // RIANT - // SOF2 HACK - else if (g_pGameDescription->mGameFile == "sof2.game") - { - if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"),"mp")) - { - // MP -#if defined(WIN32) - cmd += "sof2MP.exe"; -#elif defined(__linux__) - cmd += "b00gus"; -#elif defined(__APPLE__) - cmd += "sof2MP.app"; -#else -#error "WTF are you compiling on" -#endif - } - else - { - // SP -#if defined(WIN32) - cmd += "sof2.exe"; -#elif defined(__linux__) - cmd += "b00gus"; -#elif defined(__APPLE__) - cmd += "sof2.app"; -#else -#error "WTF are you compiling on" -#endif - } - } - else - { - cmd += g_pGameDescription->mEngine.GetBuffer(); - } -#ifdef _WIN32 - // NOTE: we are using unix pathnames and CreateProcess doesn't like / in the program path - FindReplace( cmd, "/", "\\" ); -#endif - Str cmdline; - if ( (g_pGameDescription->mGameFile == "q2.game") || (g_pGameDescription->mGameFile == "heretic2.game") ) - { - cmdline = ". +exec radiant.cfg +map "; - cmdline += m_sBSPName; - } - else - { - cmdline = "+set sv_pure 0 "; - // TTimo: a check for vm_* but that's all fine - //cmdline = "+set sv_pure 0 +set vm_ui 0 +set vm_cgame 0 +set vm_game 0 "; - if (*ValueForKey(g_qeglobals.d_project_entity, "gamename") != '\0') - { - cmdline += "+set fs_game "; - cmdline += ValueForKey(g_qeglobals.d_project_entity, "gamename"); - cmdline += " "; - } - //!\todo Read the start-map args from a config file. - if (g_pGameDescription->mGameFile == "wolf.game") - { - if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"),"mp")) - { - // MP - cmdline += "+devmap "; - cmdline += m_sBSPName; - } - else - { - // SP - cmdline += "+set nextmap \"spdevmap "; - cmdline += m_sBSPName; - cmdline += "\""; - } - } - else - { - cmdline += "+devmap "; - cmdline += m_sBSPName; - } - } - - Sys_Printf("%s %s\n", cmd.GetBuffer(), cmdline.GetBuffer()); - - // execute now - if (!Q_Exec(cmd.GetBuffer(), (char *)cmdline.GetBuffer(), g_pGameDescription->mEnginePath.GetBuffer(), false)) - { - CString msg; - msg = "Failed to execute the following command: "; - msg += cmd; msg += cmdline; - Sys_Printf(msg); - gtk_MessageBox(g_pParentWnd->m_pWidget, msg, "BSP monitoring", MB_OK | MB_ICONERROR ); - } - } - Reset(); - } - } - } - break; - default: - break; - } -} - -void CWatchBSP::DoMonitoringLoop( GPtrArray *pCmd, char *sBSPName ) -{ - if (m_sBSPName) - { - delete[] m_sBSPName; - } - m_sBSPName = sBSPName; - if (m_eState != EIdle) - { - Sys_Printf("WatchBSP got a monitoring request while not idling...\n"); - // prompt the user, should we cancel the current process and go ahead? - if (gtk_MessageBox(g_pParentWnd->m_pWidget, "I am already monitoring a BSP process.\nDo you want me to override and start a new compilation?", - "BSP process monitoring", MB_YESNO ) == IDYES) - { - // disconnect and set EIdle state - Reset(); - } - } - m_pCmd = pCmd; - m_iCurrentStep = 0; - DoEBeginStep(); -} - -void CWatchBSP::ExternalListen() -{ - m_bBSPPlugin = true; - DoEBeginStep (); -} - -// the part of the watchbsp interface we export to plugins -// NOTE: in the long run, the whole watchbsp.cpp interface needs to go out and be handled at the BSP plugin level -// for now we provide something really basic and limited, the essential is to have something that works fine and fast (for 1.1 final) -void WINAPI QERApp_Listen() -{ - // open the listening socket - g_pParentWnd->GetWatchBSP()->ExternalListen(); -} +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// monitoring window for running BSP processes (and possibly various other stuff) + +#include "stdafx.h" +#include "watchbsp.h" +#include "feedback.h" + +#ifdef _WIN32 +#include +#endif + +#if defined (__linux__) || defined (__APPLE__) +#include +#define SOCKET_ERROR -1 +#endif + +#ifdef __APPLE__ +#include +#endif + +#include + +// Static functions for the SAX callbacks ------------------------------------------------------- + +// utility for saxStartElement below +static void abortStream(message_info_t *data) +{ + g_pParentWnd->GetWatchBSP()->Reset(); + // tell there has been an error + if (g_pParentWnd->GetWatchBSP()->HasBSPPlugin ()) + g_BSPFrontendTable.m_pfnEndListen(2); + // yeah this doesn't look good.. but it's needed so that everything will be ignored until the stream goes out + data->ignore_depth = -1; + data->recurse++; +} + +#include "stream_version.h" + +static void saxStartElement(message_info_t *data, const xmlChar *name, const xmlChar **attrs) +{ + if (data->ignore_depth == 0) + { + if (data->bGeometry) + // we have a handler + { + data->pGeometry->saxStartElement (data, name, attrs); + } + else + { + if (strcmp ((char *)name, "q3map_feedback") == 0) + { + // check the correct version + // old q3map don't send a version attribute + // the ones we support .. send Q3MAP_STREAM_VERSION + if (!attrs[0] || !attrs[1] || (strcmp((char*)attrs[0],"version") != 0)) + { + Sys_FPrintf(SYS_ERR, "No stream version given in the feedback stream, this is an old q3map version.\n" + "Please turn off monitored compiling if you still wish to use this q3map executable\n"); + abortStream(data); + return; + } + else if (strcmp((char*)attrs[1],Q3MAP_STREAM_VERSION) != 0) + { + Sys_FPrintf(SYS_ERR, + "This version of Radiant reads version %s debug streams, I got an incoming connection with version %s\n" + "Please make sure your versions of Radiant and q3map are matching.\n", Q3MAP_STREAM_VERSION, (char*)attrs[1]); + abortStream(data); + return; + } + } + // we don't treat locally + else if (strcmp ((char *)name, "message") == 0) + { + data->msg_level = atoi ((char *)attrs[1]); + } + else if (strcmp ((char *)name, "polyline") == 0) + // polyline has a particular status .. right now we only use it for leakfile .. + { + data->bGeometry = true; + data->pGeometry = &g_pointfile; + data->pGeometry->saxStartElement (data, name, attrs); + } + else if (strcmp ((char *)name, "select") == 0) + { + CSelectMsg *pSelect = new CSelectMsg(); + data->bGeometry = true; + data->pGeometry = pSelect; + data->pGeometry->saxStartElement (data, name, attrs); + } + else if (strcmp ((char *)name, "pointmsg") == 0) + { + CPointMsg *pPoint = new CPointMsg(); + data->bGeometry = true; + data->pGeometry = pPoint; + data->pGeometry->saxStartElement (data, name, attrs); + } + else if (strcmp ((char *)name, "windingmsg") == 0) + { + CWindingMsg *pWinding = new CWindingMsg(); + data->bGeometry = true; + data->pGeometry = pWinding; + data->pGeometry->saxStartElement (data, name, attrs); + } + else + { + Sys_FPrintf (SYS_WRN, "WARNING: ignoring unrecognized node in XML stream (%s)\n", name); + // we don't recognize this node, jump over it + // (NOTE: the ignore mechanism is a bit screwed, only works when starting an ignore at the highest level) + data->ignore_depth = data->recurse; + } + } + } + data->recurse++; +} + +static void saxEndElement(message_info_t *data, const xmlChar *name) +{ + data->recurse--; + // we are out of an ignored chunk + if (data->recurse == data->ignore_depth) + { + data->ignore_depth = 0; + return; + } + if (data->bGeometry) + { + data->pGeometry->saxEndElement (data, name); + // we add the object to the debug window + if (!data->bGeometry) + { + g_DbgDlg.Push (data->pGeometry); + } + } + if (data->recurse == data->stop_depth) + { +#ifdef _DEBUG + Sys_Printf ("Received error msg .. shutting down..\n"); +#endif + g_pParentWnd->GetWatchBSP()->Reset(); + // tell there has been an error + if (g_pParentWnd->GetWatchBSP()->HasBSPPlugin ()) + g_BSPFrontendTable.m_pfnEndListen(2); + return; + } +} + +static void saxCharacters(message_info_t *data, const xmlChar *ch, int len) +{ + if (data->bGeometry) + { + data->pGeometry->saxCharacters (data, ch, len); + } + else + { + if (data->ignore_depth != 0) + return; + // output the message using the level + char buf[1024]; + memcpy( buf, ch, len ); + buf[len] = '\0'; + Sys_FPrintf (data->msg_level, "%s", buf); + // if this message has error level flag, we mark the depth to stop the compilation when we get out + // we don't set the msg level if we don't stop on leak + if (data->msg_level == 3) + { + data->stop_depth = data->recurse-1; + } + } +} + +static void saxComment(void *ctx, const xmlChar *msg) +{ + Sys_Printf("XML comment: %s\n", msg); +} + +static void saxWarning(void *ctx, const char *msg, ...) +{ + char saxMsgBuffer[4096]; + va_list args; + + va_start(args, msg); + vsprintf (saxMsgBuffer, msg, args); + va_end(args); + Sys_FPrintf(SYS_WRN, "XML warning: %s\n", saxMsgBuffer); +} + +static void saxError(void *ctx, const char *msg, ...) +{ + char saxMsgBuffer[4096]; + va_list args; + + va_start(args, msg); + vsprintf (saxMsgBuffer, msg, args); + va_end(args); + Sys_FPrintf(SYS_ERR, "XML error: %s\n", saxMsgBuffer); +} + +static void saxFatal(void *ctx, const char *msg, ...) +{ + char buffer[4096]; + + va_list args; + + va_start(args, msg); + vsprintf (buffer, msg, args); + va_end(args); + Sys_FPrintf(SYS_ERR, "XML fatal error: %s\n", buffer); +} + +static xmlSAXHandler saxParser = { + 0, /* internalSubset */ + 0, /* isStandalone */ + 0, /* hasInternalSubset */ + 0, /* hasExternalSubset */ + 0, /* resolveEntity */ + 0, /* getEntity */ + 0, /* entityDecl */ + 0, /* notationDecl */ + 0, /* attributeDecl */ + 0, /* elementDecl */ + 0, /* unparsedEntityDecl */ + 0, /* setDocumentLocator */ + 0, /* startDocument */ + 0, /* endDocument */ + (startElementSAXFunc)saxStartElement, /* startElement */ + (endElementSAXFunc)saxEndElement, /* endElement */ + 0, /* reference */ + (charactersSAXFunc)saxCharacters, /* characters */ + 0, /* ignorableWhitespace */ + 0, /* processingInstruction */ + (commentSAXFunc)saxComment, /* comment */ + (warningSAXFunc)saxWarning, /* warning */ + (errorSAXFunc)saxError, /* error */ + (fatalErrorSAXFunc)saxFatal, /* fatalError */ +}; + +// ------------------------------------------------------------------------------------------------ + +CWatchBSP::~CWatchBSP() +{ + Reset(); + if (m_sBSPName) + { + delete[] m_sBSPName; + m_sBSPName = NULL; + } + Net_Shutdown(); +} + +void CWatchBSP::Reset() +{ + if (m_pInSocket) + { + Net_Disconnect(m_pInSocket); + m_pInSocket = NULL; + } + if (m_pListenSocket) + { + Net_Disconnect(m_pListenSocket); + m_pListenSocket = NULL; + } + if (m_xmlInputBuffer) + { + xmlFreeParserInputBuffer (m_xmlInputBuffer); + m_xmlInputBuffer = NULL; + } + m_eState = EIdle; +} + +bool CWatchBSP::SetupListening() +{ +#ifdef _DEBUG + if (m_pListenSocket) + { + Sys_Printf("ERROR: m_pListenSocket != NULL in CWatchBSP::SetupListening\n"); + return false; + } +#endif + Sys_Printf("Setting up\n"); + Net_Setup(); + m_pListenSocket = Net_ListenSocket(39000); + if (m_pListenSocket == NULL) + return false; + Sys_Printf("Listening...\n"); + return true; +} + +void CWatchBSP::DoEBeginStep() +{ + Reset(); + if (SetupListening() == false) + { + CString msg; + msg = "Failed to get a listening socket on port 39000.\nTry running with BSP monitoring disabled if you can't fix this.\n"; + Sys_Printf (msg); + gtk_MessageBox (g_pParentWnd->m_pWidget, msg, "BSP monitoring", MB_OK | MB_ICONERROR); + return; + } + // set the timer for timeouts and step cancellation + g_timer_reset( m_pTimer ); + g_timer_start( m_pTimer ); + + if (!m_bBSPPlugin) + { + Sys_Printf("=== running BSP command ===\n%s\n", g_ptr_array_index( m_pCmd, m_iCurrentStep ) ); + + if (!Q_Exec(NULL, (char *)g_ptr_array_index( m_pCmd, m_iCurrentStep ), NULL, true )) + { + CString msg; + msg = "Failed to execute the following command: "; + msg += (char *)g_ptr_array_index( m_pCmd, m_iCurrentStep ); + msg += "\nCheck that the file exists and that you don't run out of system resources.\n"; + Sys_Printf(msg); + gtk_MessageBox(g_pParentWnd->m_pWidget, msg, "BSP monitoring", MB_OK | MB_ICONERROR ); + return; + } + // re-initialise the debug window + if (m_iCurrentStep == 0) + g_DbgDlg.Init(); + } + m_eState = EBeginStep; +} + +void CWatchBSP::RoutineProcessing() +{ + // used for select() +#ifdef _WIN32 + TIMEVAL tout = { 0, 0 }; +#endif +#if defined (__linux__) || defined (__APPLE__) + timeval tout; + tout.tv_sec = 0; + tout.tv_usec = 0; +#endif + + switch (m_eState) + { + case EBeginStep: + // timeout: if we don't get an incoming connection fast enough, go back to idle + if ( g_timer_elapsed( m_pTimer, NULL ) > g_PrefsDlg.m_iTimeout ) + { + gtk_MessageBox(g_pParentWnd->m_pWidget, "The connection timed out, assuming the BSP process failed\nMake sure you are using a networked version of Q3Map?\nOtherwise you need to disable BSP Monitoring in prefs.", "BSP process monitoring", MB_OK ); + Reset(); + if (m_bBSPPlugin) + { + // status == 1 : didn't get the connection + g_BSPFrontendTable.m_pfnEndListen(1); + } + return; + } +#ifdef _DEBUG + // some debug checks + if (!m_pListenSocket) + { + Sys_Printf("ERROR: m_pListenSocket == NULL in CWatchBSP::RoutineProcessing EBeginStep state\n"); + return; + } +#endif + // we are not connected yet, accept any incoming connection + m_pInSocket = Net_Accept(m_pListenSocket); + if (m_pInSocket) + { + Sys_Printf("Connected.\n"); + // prepare the message info struct for diving in + memset (&m_message_info, 0, sizeof(message_info_s)); + // a dumb flag to make sure we init the push parser context when first getting a msg + m_bNeedCtxtInit = true; + m_eState = EWatching; + } + break; + case EWatching: +#ifdef _DEBUG + // some debug checks + if (!m_pInSocket) + { + Sys_Printf("ERROR: m_pInSocket == NULL in CWatchBSP::RoutineProcessing EWatching state\n"); + return; + } +#endif + // select() will identify if the socket needs an update + // if the socket is identified that means there's either a message or the connection has been closed/reset/terminated + fd_set readfds; + int ret; + FD_ZERO(&readfds); + FD_SET(((unsigned int)m_pInSocket->socket), &readfds); + // from select man page: + // n is the highest-numbered descriptor in any of the three sets, plus 1 + // (no use on windows) + ret = select( m_pInSocket->socket + 1, &readfds, NULL, NULL, &tout ); + if (ret == SOCKET_ERROR) + { + Sys_Printf("WARNING: SOCKET_ERROR in CWatchBSP::RoutineProcessing\n"); + Sys_Printf("Terminating the connection.\n"); + Reset(); + return; + } +#ifdef _DEBUG + if (ret == -1) + { + // we are non-blocking?? we should never get timeout errors + Sys_Printf("WARNING: unexpected timeout expired in CWatchBSP::Processing\n"); + Sys_Printf("Terminating the connection.\n"); + Reset(); + return; + } +#endif + if (ret == 1) + { + // the socket has been identified, there's something (message or disconnection) + // see if there's anything in input + ret = Net_Receive( m_pInSocket, &msg ); + if (ret > 0) + { + // unsigned int size = msg.size; //++timo just a check + strcpy (m_xmlBuf, NMSG_ReadString (&msg)); + if (m_bNeedCtxtInit) + { + m_xmlParserCtxt = NULL; + m_xmlParserCtxt = xmlCreatePushParserCtxt (&saxParser, &m_message_info, m_xmlBuf, strlen(m_xmlBuf), NULL); + if (m_xmlParserCtxt == NULL) + { + Sys_FPrintf (SYS_ERR, "Failed to create the XML parser (incoming stream began with: %s)\n", m_xmlBuf); + Reset(); + } + m_bNeedCtxtInit = false; + } + else + { + xmlParseChunk (m_xmlParserCtxt, m_xmlBuf, strlen(m_xmlBuf), 0); + } + } + else + { + // error or connection closed/reset + // NOTE: if we get an error down the XML stream we don't reach here + Net_Disconnect( m_pInSocket ); + m_pInSocket = NULL; + Sys_Printf("Connection closed.\n"); + if (m_bBSPPlugin) + { + Reset(); + // let the BSP plugin know that the job is done + g_BSPFrontendTable.m_pfnEndListen(0); + return; + } + // move to next step or finish + m_iCurrentStep++; + if (m_iCurrentStep < m_pCmd->len ) + { + DoEBeginStep(); + } + else + { + // release the GPtrArray and the strings + if (m_pCmd != NULL) + { + for (m_iCurrentStep=0; m_iCurrentStep < m_pCmd->len; m_iCurrentStep++ ) + { + delete[] (char *)g_ptr_array_index( m_pCmd, m_iCurrentStep ); + } + g_ptr_array_free( m_pCmd, false ); + } + m_pCmd = NULL; + // launch the engine .. OMG + if (g_PrefsDlg.m_bRunQuake) + { + // do we enter sleep mode before? + if (g_PrefsDlg.m_bDoSleep) + { + Sys_Printf("Going into sleep mode..\n"); + g_pParentWnd->OnSleep(); + } + Sys_Printf("Running engine...\n"); + Str cmd; + // build the command line + cmd = g_pGameDescription->mEnginePath.GetBuffer(); + // this is game dependant + //!\todo Read the engine binary name from a config file. + if (g_pGameDescription->mGameFile == "wolf.game") + { + if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"),"mp")) + { + // MP +#if defined(WIN32) + cmd += "WolfMP.exe"; +#elif defined(__linux__) + cmd += "wolfmp"; +#elif defined(__APPLE__) + cmd += "wolfmp.app"; +#else +#error "WTF are you compiling on" +#endif + } + else + { + // SP +#if defined(WIN32) + cmd += "WolfSP.exe"; +#elif defined(__linux__) + cmd += "wolfsp"; +#elif defined(__APPLE__) + cmd += "wolfsp.app"; +#else +#error "WTF are you compiling on" +#endif + } + } else if (g_pGameDescription->mGameFile == "et.game") + { +#if defined(WIN32) + cmd += "et.exe"; +#elif defined(__linux__) + cmd += "et"; +#elif defined(__APPLE__) + cmd += "et.app"; +#else +#error "WTF are you compiling on" +#endif + } + // RIANT + // JK2 HACK + else if (g_pGameDescription->mGameFile == "jk2.game") + { + if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"),"mp")) + { + // MP +#if defined(WIN32) + cmd += "jk2MP.exe"; +#elif defined(__linux__) + cmd += "jk2mp"; +#elif defined(__APPLE__) + cmd += "jk2mp.app"; +#else +#error "WTF are you compiling on" +#endif + } + else + { + // SP +#if defined(WIN32) + cmd += "jk2SP.exe"; +#elif defined(__linux__) + cmd += "jk2sp"; +#elif defined(__APPLE__) + cmd += "jk2sp.app"; +#else +#error "WTF are you compiling on" +#endif + } + } + // TTimo + // JA HACK + else if (g_pGameDescription->mGameFile == "ja.game") + { + if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"),"mp")) + { + // MP +#if defined(WIN32) + cmd += "jamp.exe"; +#elif !defined(__linux__) && !defined(__APPLE__) +#error "WTF are you compiling on" +#endif + } + else + { + // SP +#if defined(WIN32) + cmd += "jasp.exe"; +#elif !defined(__linux__) && !defined(__APPLE__) +#error "WTF are you compiling on" +#endif + } + } + // RIANT + // STVEF HACK + else if (g_pGameDescription->mGameFile == "stvef.game") + { + if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"),"mp")) + { + // MP +#if defined(WIN32) + cmd += "stvoyHM.exe"; +#elif defined(__linux__) + cmd += "stvoyHM"; +#elif defined(__APPLE__) + cmd += "stvoyHM.app"; +#else +#error "WTF are you compiling on" +#endif + } + else + { + // SP +#if defined(WIN32) + cmd += "stvoy.exe"; +#elif defined(__linux__) + cmd += "stvoy"; +#elif defined(__APPLE__) + cmd += "stvoy.app"; +#else +#error "WTF are you compiling on" +#endif + } + } + // RIANT + // SOF2 HACK + else if (g_pGameDescription->mGameFile == "sof2.game") + { + if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"),"mp")) + { + // MP +#if defined(WIN32) + cmd += "sof2MP.exe"; +#elif defined(__linux__) + cmd += "b00gus"; +#elif defined(__APPLE__) + cmd += "sof2MP.app"; +#else +#error "WTF are you compiling on" +#endif + } + else + { + // SP +#if defined(WIN32) + cmd += "sof2.exe"; +#elif defined(__linux__) + cmd += "b00gus"; +#elif defined(__APPLE__) + cmd += "sof2.app"; +#else +#error "WTF are you compiling on" +#endif + } + } + else + { + cmd += g_pGameDescription->mEngine.GetBuffer(); + } +#ifdef _WIN32 + // NOTE: we are using unix pathnames and CreateProcess doesn't like / in the program path + FindReplace( cmd, "/", "\\" ); +#endif + Str cmdline; + if ( (g_pGameDescription->mGameFile == "q2.game") || (g_pGameDescription->mGameFile == "heretic2.game") ) + { + cmdline = ". +exec radiant.cfg +map "; + cmdline += m_sBSPName; + } + else + { + cmdline = "+set sv_pure 0 "; + // TTimo: a check for vm_* but that's all fine + //cmdline = "+set sv_pure 0 +set vm_ui 0 +set vm_cgame 0 +set vm_game 0 "; + if (*ValueForKey(g_qeglobals.d_project_entity, "gamename") != '\0') + { + cmdline += "+set fs_game "; + cmdline += ValueForKey(g_qeglobals.d_project_entity, "gamename"); + cmdline += " "; + } + //!\todo Read the start-map args from a config file. + if (g_pGameDescription->mGameFile == "wolf.game") + { + if (!strcmp(ValueForKey(g_qeglobals.d_project_entity, "gamemode"),"mp")) + { + // MP + cmdline += "+devmap "; + cmdline += m_sBSPName; + } + else + { + // SP + cmdline += "+set nextmap \"spdevmap "; + cmdline += m_sBSPName; + cmdline += "\""; + } + } + else + { + cmdline += "+devmap "; + cmdline += m_sBSPName; + } + } + + Sys_Printf("%s %s\n", cmd.GetBuffer(), cmdline.GetBuffer()); + + // execute now + if (!Q_Exec(cmd.GetBuffer(), (char *)cmdline.GetBuffer(), g_pGameDescription->mEnginePath.GetBuffer(), false)) + { + CString msg; + msg = "Failed to execute the following command: "; + msg += cmd; msg += cmdline; + Sys_Printf(msg); + gtk_MessageBox(g_pParentWnd->m_pWidget, msg, "BSP monitoring", MB_OK | MB_ICONERROR ); + } + } + Reset(); + } + } + } + break; + default: + break; + } +} + +void CWatchBSP::DoMonitoringLoop( GPtrArray *pCmd, char *sBSPName ) +{ + if (m_sBSPName) + { + delete[] m_sBSPName; + } + m_sBSPName = sBSPName; + if (m_eState != EIdle) + { + Sys_Printf("WatchBSP got a monitoring request while not idling...\n"); + // prompt the user, should we cancel the current process and go ahead? + if (gtk_MessageBox(g_pParentWnd->m_pWidget, "I am already monitoring a BSP process.\nDo you want me to override and start a new compilation?", + "BSP process monitoring", MB_YESNO ) == IDYES) + { + // disconnect and set EIdle state + Reset(); + } + } + m_pCmd = pCmd; + m_iCurrentStep = 0; + DoEBeginStep(); +} + +void CWatchBSP::ExternalListen() +{ + m_bBSPPlugin = true; + DoEBeginStep (); +} + +// the part of the watchbsp interface we export to plugins +// NOTE: in the long run, the whole watchbsp.cpp interface needs to go out and be handled at the BSP plugin level +// for now we provide something really basic and limited, the essential is to have something that works fine and fast (for 1.1 final) +void WINAPI QERApp_Listen() +{ + // open the listening socket + g_pParentWnd->GetWatchBSP()->ExternalListen(); +} diff --git a/radiant/winding.cpp b/radiant/winding.cpp index 65393ce9..6fc608ca 100644 --- a/radiant/winding.cpp +++ b/radiant/winding.cpp @@ -1,822 +1,822 @@ -/* -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 -*/ - - - -#include "stdafx.h" -#include -#include "winding.h" - -#define BOGUS_RANGE (g_MaxWorldCoord+1) - -/* -============= -Plane_Equal -============= -*/ -#define NORMAL_EPSILON 0.0001 -#define DIST_EPSILON 0.02 - -int Plane_Equal(plane_t *a, plane_t *b, int flip) -{ - vec3_t normal; - float dist; - - if (flip) { - normal[0] = - b->normal[0]; - normal[1] = - b->normal[1]; - normal[2] = - b->normal[2]; - dist = - b->dist; - } - else { - normal[0] = b->normal[0]; - normal[1] = b->normal[1]; - normal[2] = b->normal[2]; - dist = b->dist; - } - if ( - fabs(a->normal[0] - normal[0]) < NORMAL_EPSILON - && fabs(a->normal[1] - normal[1]) < NORMAL_EPSILON - && fabs(a->normal[2] - normal[2]) < NORMAL_EPSILON - && fabs(a->dist - dist) < DIST_EPSILON ) - return true; - return false; -} - -/* -============ -Plane_FromPoints -============ -*/ -int Plane_FromPoints(vec3_t p1, vec3_t p2, vec3_t p3, plane_t *plane) -{ - vec3_t v1, v2; - - VectorSubtract(p2, p1, v1); - VectorSubtract(p3, p1, v2); - //CrossProduct(v2, v1, plane->normal); - CrossProduct(v1, v2, plane->normal); - if (VectorNormalize(plane->normal, plane->normal) < 0.1) return false; - plane->dist = DotProduct(p1, plane->normal); - return true; -} - -/* -================= -Point_Equal -================= -*/ -int Point_Equal(vec3_t p1, vec3_t p2, float epsilon) -{ - int i; - - for (i = 0; i < 3; i++) - { - if (fabs(p1[i] - p2[i]) > epsilon) return false; - } - return true; -} - - -/* -================= -Winding_BaseForPlane -================= -*/ -//#define DBG_WNDG -winding_t *Winding_BaseForPlane (plane_t *p) -{ - int i, x; - vec_t max, v; - vec3_t org, vright, vup; - winding_t *w; - - // find the major axis -#ifdef DBG_WNDG - Sys_Printf("Winding_BaseForPlane %p\n",p); -#endif - - max = -BOGUS_RANGE; - x = -1; - for (i=0 ; i<3; i++) - { - v = fabs(p->normal[i]); - if (v > max) - { - x = i; - max = v; - } - } - if (x==-1) - Error ("Winding_BaseForPlane: no axis found"); - - VectorCopy (vec3_origin, vup); - switch (x) - { - case 0: - case 1: - vup[2] = 1; - break; - case 2: - vup[0] = 1; - break; - } - - - v = DotProduct (vup, p->normal); - VectorMA (vup, -v, p->normal, vup); - VectorNormalize (vup, vup); - - VectorScale (p->normal, p->dist, org); - - CrossProduct (vup, p->normal, vright); - - VectorScale (vup, BOGUS_RANGE, vup); - VectorScale (vright, BOGUS_RANGE, vright); - - // project a really big axis aligned box onto the plane - w = Winding_Alloc (4); - - VectorSubtract (org, vright, w->points[0]); - VectorAdd (w->points[0], vup, w->points[0]); - - VectorAdd (org, vright, w->points[1]); - VectorAdd (w->points[1], vup, w->points[1]); - - VectorAdd (org, vright, w->points[2]); - VectorSubtract (w->points[2], vup, w->points[2]); - - VectorSubtract (org, vright, w->points[3]); - VectorSubtract (w->points[3], vup, w->points[3]); - - w->numpoints = 4; - - return w; -} - -// macro to compute winding size -#define WINDING_SIZE(pt) (sizeof(int)*2+sizeof(float)*5*(pt)) - -/* -================== -Winding_Alloc -================== -*/ -winding_t *Winding_Alloc (int points) -{ - winding_t *w; - int size; - - if (points > MAX_POINTS_ON_WINDING) - Error ("Winding_Alloc: %i points", points); - -// size = (int)((winding_t *)0)->points[points]; - size = WINDING_SIZE(points); - w = (winding_t*) malloc (size); - memset (w, 0, size); - w->maxpoints = points; - - return w; -} - -void Winding_Free (winding_t *w) -{ - free(w); -} - -/* -================== -Winding_Clone -================== -*/ -winding_t *Winding_Clone(winding_t *w) -{ - int size; - winding_t *c; - -// size = (int)((winding_t *)0)->points[w->numpoints]; - size = WINDING_SIZE(w->numpoints); - c = (winding_t*)qmalloc (size); - memcpy (c, w, size); - return c; -} - -/* -================== -ReverseWinding -================== -*/ -winding_t *Winding_Reverse(winding_t *w) -{ - int i; - winding_t *c; - - c = Winding_Alloc(w->numpoints); - for (i = 0; i < w->numpoints; i++) - { - VectorCopy (w->points[w->numpoints-1-i], c->points[i]); - } - c->numpoints = w->numpoints; - return c; -} - -/* -============== -Winding_RemovePoint -============== -*/ -void Winding_RemovePoint(winding_t *w, int point) -{ - if (point < 0 || point >= w->numpoints) - Error("Winding_RemovePoint: point out of range"); - - if (point < w->numpoints-1) - { - memmove(&w->points[point], &w->points[point+1], (int)((winding_t *)0)->points[w->numpoints - point - 1]); - } - w->numpoints--; -} - -/* -============= -Winding_InsertPoint -============= -*/ -winding_t *Winding_InsertPoint(winding_t *w, vec3_t point, int spot) -{ - int i, j; - winding_t *neww; - - if (spot > w->numpoints) - { - Error("Winding_InsertPoint: spot > w->numpoints"); - } //end if - if (spot < 0) - { - Error("Winding_InsertPoint: spot < 0"); - } //end if - neww = Winding_Alloc(w->numpoints + 1); - neww->numpoints = w->numpoints + 1; - for (i = 0, j = 0; i < neww->numpoints; i++) - { - if (i == spot) - { - VectorCopy(point, neww->points[i]); - } - else - { - VectorCopy(w->points[j], neww->points[i]); - j++; - } - } - return neww; -} - -/* -============== -Winding_IsTiny -============== -*/ -#define EDGE_LENGTH 0.2 - -int Winding_IsTiny (winding_t *w) -{ - int i, j; - vec_t len; - vec3_t delta; - int edges; - - edges = 0; - for (i=0 ; inumpoints ; i++) - { - j = i == w->numpoints - 1 ? 0 : i+1; - VectorSubtract (w->points[j], w->points[i], delta); - len = VectorLength (delta); - if (len > EDGE_LENGTH) - { - if (++edges == 3) - return false; - } - } - return true; -} - -/* -============== -Winding_IsHuge -============== -*/ -int Winding_IsHuge(winding_t *w) -{ - int i, j; - - for (i=0 ; inumpoints ; i++) - { - for (j=0 ; j<3 ; j++) - if (w->points[i][j] < -BOGUS_RANGE+1 || w->points[i][j] > BOGUS_RANGE-1) - return true; - } - return false; -} - -/* -============= -Winding_PlanesConcave -============= -*/ -#define WCONVEX_EPSILON 0.2 - -int Winding_PlanesConcave(winding_t *w1, winding_t *w2, - vec3_t normal1, vec3_t normal2, - float dist1, float dist2) -{ - int i; - - if (!w1 || !w2) return false; - - // check if one of the points of winding 1 is at the back of the plane of winding 2 - for (i = 0; i < w1->numpoints; i++) - { - if (DotProduct(normal2, w1->points[i]) - dist2 > WCONVEX_EPSILON) return true; - } - // check if one of the points of winding 2 is at the back of the plane of winding 1 - for (i = 0; i < w2->numpoints; i++) - { - if (DotProduct(normal1, w2->points[i]) - dist1 > WCONVEX_EPSILON) return true; - } - - return false; -} - -/* -================== -Winding_Clip - -Clips the winding to the plane, returning the new winding on the positive side -Frees the input winding. -If keepon is true, an exactly on-plane winding will be saved, otherwise -it will be clipped away. -================== -*/ -winding_t *Winding_Clip (winding_t *in, plane_t *split, qboolean keepon) -{ - vec_t dists[MAX_POINTS_ON_WINDING]; - int sides[MAX_POINTS_ON_WINDING]; - int counts[3]; - vec_t dot; - int i, j; - vec_t *p1, *p2; - vec3_t mid; - winding_t *neww; - int maxpts; - - counts[0] = counts[1] = counts[2] = 0; - - // determine sides for each point - for (i=0 ; inumpoints ; i++) - { - dot = DotProduct (in->points[i], split->normal); - dot -= split->dist; - dists[i] = dot; - if (dot > ON_EPSILON) - sides[i] = SIDE_FRONT; - else if (dot < -ON_EPSILON) - sides[i] = SIDE_BACK; - else - { - sides[i] = SIDE_ON; - } - counts[sides[i]]++; - } - sides[i] = sides[0]; - dists[i] = dists[0]; - - if (keepon && !counts[0] && !counts[1]) - return in; - - if (!counts[0]) - { - Winding_Free (in); - return NULL; - } - if (!counts[1]) - return in; - - maxpts = in->numpoints+4; // can't use counts[0]+2 because - // of fp grouping errors - neww = Winding_Alloc (maxpts); - - for (i=0 ; inumpoints ; i++) - { - p1 = in->points[i]; - - if (sides[i] == SIDE_ON) - { - VectorCopy (p1, neww->points[neww->numpoints]); - neww->numpoints++; - continue; - } - - if (sides[i] == SIDE_FRONT) - { - VectorCopy (p1, neww->points[neww->numpoints]); - neww->numpoints++; - } - - if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) - continue; - - // generate a split point - p2 = in->points[(i+1)%in->numpoints]; - - dot = dists[i] / (dists[i]-dists[i+1]); - for (j=0 ; j<3 ; j++) - { // avoid round off error when possible - if (split->normal[j] == 1) - mid[j] = split->dist; - else if (split->normal[j] == -1) - mid[j] = -split->dist; - else - mid[j] = p1[j] + dot*(p2[j]-p1[j]); - } - - VectorCopy (mid, neww->points[neww->numpoints]); - neww->numpoints++; - } - - if (neww->numpoints > maxpts) - Error ("Winding_Clip: points exceeded estimate"); - - // free the original winding - Winding_Free (in); - - return neww; -} - -/* -============= -Winding_SplitEpsilon - - split the input winding with the plane - the input winding stays untouched -============= -*/ -void Winding_SplitEpsilon (winding_t *in, vec3_t normal, double dist, - vec_t epsilon, winding_t **front, winding_t **back) -{ - vec_t dists[MAX_POINTS_ON_WINDING+4]; - int sides[MAX_POINTS_ON_WINDING+4]; - int counts[3]; - vec_t dot; - int i, j; - vec_t *p1, *p2; - vec3_t mid; - winding_t *f, *b; - int maxpts; - - counts[0] = counts[1] = counts[2] = 0; - - // determine sides for each point - for (i = 0; i < in->numpoints; i++) - { - dot = DotProduct (in->points[i], normal); - dot -= dist; - dists[i] = dot; - if (dot > epsilon) - sides[i] = SIDE_FRONT; - else if (dot < -epsilon) - sides[i] = SIDE_BACK; - else - { - sides[i] = SIDE_ON; - } - counts[sides[i]]++; - } - sides[i] = sides[0]; - dists[i] = dists[0]; - - *front = *back = NULL; - - if (!counts[0]) - { - *back = Winding_Clone(in); - return; - } - if (!counts[1]) - { - *front = Winding_Clone(in); - return; - } - - maxpts = in->numpoints+4; // cant use counts[0]+2 because - // of fp grouping errors - - *front = f = Winding_Alloc (maxpts); - *back = b = Winding_Alloc (maxpts); - - for (i = 0; i < in->numpoints; i++) - { - p1 = in->points[i]; - - if (sides[i] == SIDE_ON) - { - VectorCopy (p1, f->points[f->numpoints]); - f->numpoints++; - VectorCopy (p1, b->points[b->numpoints]); - b->numpoints++; - continue; - } - - if (sides[i] == SIDE_FRONT) - { - VectorCopy (p1, f->points[f->numpoints]); - f->numpoints++; - } - if (sides[i] == SIDE_BACK) - { - VectorCopy (p1, b->points[b->numpoints]); - b->numpoints++; - } - - if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) - continue; - - // generate a split point - p2 = in->points[(i+1)%in->numpoints]; - - dot = dists[i] / (dists[i]-dists[i+1]); - for (j = 0; j < 3; j++) - { - // avoid round off error when possible - if (normal[j] == 1) - mid[j] = dist; - else if (normal[j] == -1) - mid[j] = -dist; - else - mid[j] = p1[j] + dot*(p2[j]-p1[j]); - } - - VectorCopy (mid, f->points[f->numpoints]); - f->numpoints++; - VectorCopy (mid, b->points[b->numpoints]); - b->numpoints++; - } - - if (f->numpoints > maxpts || b->numpoints > maxpts) - Error ("Winding_Clip: points exceeded estimate"); - if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING) - Error ("Winding_Clip: MAX_POINTS_ON_WINDING"); -} - -/* -============= -Winding_TryMerge - -If two windings share a common edge and the edges that meet at the -common points are both inside the other polygons, merge them - -Returns NULL if the windings couldn't be merged, or the new winding. -The originals will NOT be freed. - -if keep is true no points are ever removed -============= -*/ -#define CONTINUOUS_EPSILON 0.005 - -winding_t *Winding_TryMerge(winding_t *f1, winding_t *f2, vec3_t planenormal, int keep) -{ - vec_t *p1, *p2, *p3, *p4, *back; - winding_t *newf; - int i, j, k, l; - vec3_t normal, delta; - vec_t dot; - qboolean keep1, keep2; - - - // - // find a common edge - // - p1 = p2 = NULL; // stop compiler warning - j = 0; // - - for (i = 0; i < f1->numpoints; i++) - { - p1 = f1->points[i]; - p2 = f1->points[(i+1) % f1->numpoints]; - for (j = 0; j < f2->numpoints; j++) - { - p3 = f2->points[j]; - p4 = f2->points[(j+1) % f2->numpoints]; - for (k = 0; k < 3; k++) - { - if (fabs(p1[k] - p4[k]) > 0.1)//EQUAL_EPSILON) //ME - break; - if (fabs(p2[k] - p3[k]) > 0.1)//EQUAL_EPSILON) //ME - break; - } //end for - if (k==3) - break; - } //end for - if (j < f2->numpoints) - break; - } //end for - - if (i == f1->numpoints) - return NULL; // no matching edges - - // - // check slope of connected lines - // if the slopes are colinear, the point can be removed - // - back = f1->points[(i+f1->numpoints-1)%f1->numpoints]; - VectorSubtract (p1, back, delta); - CrossProduct (planenormal, delta, normal); - VectorNormalize (normal, normal); - - back = f2->points[(j+2)%f2->numpoints]; - VectorSubtract (back, p1, delta); - dot = DotProduct (delta, normal); - if (dot > CONTINUOUS_EPSILON) - return NULL; // not a convex polygon - keep1 = (qboolean)(dot < -CONTINUOUS_EPSILON); - - back = f1->points[(i+2)%f1->numpoints]; - VectorSubtract (back, p2, delta); - CrossProduct (planenormal, delta, normal); - VectorNormalize (normal, normal); - - back = f2->points[(j+f2->numpoints-1)%f2->numpoints]; - VectorSubtract (back, p2, delta); - dot = DotProduct (delta, normal); - if (dot > CONTINUOUS_EPSILON) - return NULL; // not a convex polygon - keep2 = (qboolean)(dot < -CONTINUOUS_EPSILON); - - // - // build the new polygon - // - newf = Winding_Alloc (f1->numpoints + f2->numpoints); - - // copy first polygon - for (k=(i+1)%f1->numpoints ; k != i ; k=(k+1)%f1->numpoints) - { - if (!keep && k==(i+1)%f1->numpoints && !keep2) - continue; - - VectorCopy (f1->points[k], newf->points[newf->numpoints]); - newf->numpoints++; - } - - // copy second polygon - for (l= (j+1)%f2->numpoints ; l != j ; l=(l+1)%f2->numpoints) - { - if (!keep && l==(j+1)%f2->numpoints && !keep1) - continue; - VectorCopy (f2->points[l], newf->points[newf->numpoints]); - newf->numpoints++; - } - - return newf; -} - -/* -============ -Winding_Plane -============ -*/ -void Winding_Plane (winding_t *w, vec3_t normal, double *dist) -{ - vec3_t v1, v2; - int i; - - //find two vectors each longer than 0.5 units - for (i = 0; i < w->numpoints; i++) - { - VectorSubtract(w->points[(i+1) % w->numpoints], w->points[i], v1); - VectorSubtract(w->points[(i+2) % w->numpoints], w->points[i], v2); - if (VectorLength(v1) > 0.5 && VectorLength(v2) > 0.5) break; - } - CrossProduct(v2, v1, normal); - VectorNormalize(normal, normal); - *dist = DotProduct(w->points[0], normal); -} - -/* -============= -Winding_Area -============= -*/ -float Winding_Area (winding_t *w) -{ - int i; - vec3_t d1, d2, cross; - float total; - - total = 0; - for (i=2 ; inumpoints ; i++) - { - VectorSubtract (w->points[i-1], w->points[0], d1); - VectorSubtract (w->points[i], w->points[0], d2); - CrossProduct (d1, d2, cross); - total += 0.5 * VectorLength ( cross ); - } - return total; -} - -/* -============= -Winding_Bounds -============= -*/ -void Winding_Bounds (winding_t *w, vec3_t mins, vec3_t maxs) -{ - vec_t v; - int i,j; - - mins[0] = mins[1] = mins[2] = 99999; - maxs[0] = maxs[1] = maxs[2] = -99999; - - for (i=0 ; inumpoints ; i++) - { - for (j=0 ; j<3 ; j++) - { - v = w->points[i][j]; - if (v < mins[j]) - mins[j] = v; - if (v > maxs[j]) - maxs[j] = v; - } - } -} - - -/* -================= -Winding_PointInside -================= -*/ -int Winding_PointInside(winding_t *w, plane_t *plane, vec3_t point, float epsilon) -{ - int i; - vec3_t dir, normal, pointvec; - - for (i = 0; i < w->numpoints; i++) - { - VectorSubtract(w->points[(i+1) % w->numpoints], w->points[i], dir); - VectorSubtract(point, w->points[i], pointvec); - // - CrossProduct(dir, plane->normal, normal); - // - if (DotProduct(pointvec, normal) < -epsilon) return false; - } - return true; -} - -/* -================= -Winding_VectorIntersect -================= -*/ -int Winding_VectorIntersect(winding_t *w, plane_t *plane, vec3_t p1, vec3_t p2, float epsilon) -{ - float front, back, frac; - vec3_t mid; - - front = DotProduct(p1, plane->normal) - plane->dist; - back = DotProduct(p2, plane->normal) - plane->dist; - //if both points at the same side of the plane - if (front < -epsilon && back < -epsilon) return false; - if (front > epsilon && back > epsilon) return false; - //get point of intersection with winding plane - if (fabs(front-back) < 0.001) - { - VectorCopy(p2, mid); - } - else - { - frac = front/(front-back); - mid[0] = p1[0] + (p2[0] - p1[0]) * frac; - mid[1] = p1[1] + (p2[1] - p1[1]) * frac; - mid[2] = p1[2] + (p2[2] - p1[2]) * frac; - } - return Winding_PointInside(w, plane, mid, epsilon); -} - +/* +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 +*/ + + + +#include "stdafx.h" +#include +#include "winding.h" + +#define BOGUS_RANGE (g_MaxWorldCoord+1) + +/* +============= +Plane_Equal +============= +*/ +#define NORMAL_EPSILON 0.0001 +#define DIST_EPSILON 0.02 + +int Plane_Equal(plane_t *a, plane_t *b, int flip) +{ + vec3_t normal; + float dist; + + if (flip) { + normal[0] = - b->normal[0]; + normal[1] = - b->normal[1]; + normal[2] = - b->normal[2]; + dist = - b->dist; + } + else { + normal[0] = b->normal[0]; + normal[1] = b->normal[1]; + normal[2] = b->normal[2]; + dist = b->dist; + } + if ( + fabs(a->normal[0] - normal[0]) < NORMAL_EPSILON + && fabs(a->normal[1] - normal[1]) < NORMAL_EPSILON + && fabs(a->normal[2] - normal[2]) < NORMAL_EPSILON + && fabs(a->dist - dist) < DIST_EPSILON ) + return true; + return false; +} + +/* +============ +Plane_FromPoints +============ +*/ +int Plane_FromPoints(vec3_t p1, vec3_t p2, vec3_t p3, plane_t *plane) +{ + vec3_t v1, v2; + + VectorSubtract(p2, p1, v1); + VectorSubtract(p3, p1, v2); + //CrossProduct(v2, v1, plane->normal); + CrossProduct(v1, v2, plane->normal); + if (VectorNormalize(plane->normal, plane->normal) < 0.1) return false; + plane->dist = DotProduct(p1, plane->normal); + return true; +} + +/* +================= +Point_Equal +================= +*/ +int Point_Equal(vec3_t p1, vec3_t p2, float epsilon) +{ + int i; + + for (i = 0; i < 3; i++) + { + if (fabs(p1[i] - p2[i]) > epsilon) return false; + } + return true; +} + + +/* +================= +Winding_BaseForPlane +================= +*/ +//#define DBG_WNDG +winding_t *Winding_BaseForPlane (plane_t *p) +{ + int i, x; + vec_t max, v; + vec3_t org, vright, vup; + winding_t *w; + + // find the major axis +#ifdef DBG_WNDG + Sys_Printf("Winding_BaseForPlane %p\n",p); +#endif + + max = -BOGUS_RANGE; + x = -1; + for (i=0 ; i<3; i++) + { + v = fabs(p->normal[i]); + if (v > max) + { + x = i; + max = v; + } + } + if (x==-1) + Error ("Winding_BaseForPlane: no axis found"); + + VectorCopy (vec3_origin, vup); + switch (x) + { + case 0: + case 1: + vup[2] = 1; + break; + case 2: + vup[0] = 1; + break; + } + + + v = DotProduct (vup, p->normal); + VectorMA (vup, -v, p->normal, vup); + VectorNormalize (vup, vup); + + VectorScale (p->normal, p->dist, org); + + CrossProduct (vup, p->normal, vright); + + VectorScale (vup, BOGUS_RANGE, vup); + VectorScale (vright, BOGUS_RANGE, vright); + + // project a really big axis aligned box onto the plane + w = Winding_Alloc (4); + + VectorSubtract (org, vright, w->points[0]); + VectorAdd (w->points[0], vup, w->points[0]); + + VectorAdd (org, vright, w->points[1]); + VectorAdd (w->points[1], vup, w->points[1]); + + VectorAdd (org, vright, w->points[2]); + VectorSubtract (w->points[2], vup, w->points[2]); + + VectorSubtract (org, vright, w->points[3]); + VectorSubtract (w->points[3], vup, w->points[3]); + + w->numpoints = 4; + + return w; +} + +// macro to compute winding size +#define WINDING_SIZE(pt) (sizeof(int)*2+sizeof(float)*5*(pt)) + +/* +================== +Winding_Alloc +================== +*/ +winding_t *Winding_Alloc (int points) +{ + winding_t *w; + int size; + + if (points > MAX_POINTS_ON_WINDING) + Error ("Winding_Alloc: %i points", points); + +// size = (int)((winding_t *)0)->points[points]; + size = WINDING_SIZE(points); + w = (winding_t*) malloc (size); + memset (w, 0, size); + w->maxpoints = points; + + return w; +} + +void Winding_Free (winding_t *w) +{ + free(w); +} + +/* +================== +Winding_Clone +================== +*/ +winding_t *Winding_Clone(winding_t *w) +{ + int size; + winding_t *c; + +// size = (int)((winding_t *)0)->points[w->numpoints]; + size = WINDING_SIZE(w->numpoints); + c = (winding_t*)qmalloc (size); + memcpy (c, w, size); + return c; +} + +/* +================== +ReverseWinding +================== +*/ +winding_t *Winding_Reverse(winding_t *w) +{ + int i; + winding_t *c; + + c = Winding_Alloc(w->numpoints); + for (i = 0; i < w->numpoints; i++) + { + VectorCopy (w->points[w->numpoints-1-i], c->points[i]); + } + c->numpoints = w->numpoints; + return c; +} + +/* +============== +Winding_RemovePoint +============== +*/ +void Winding_RemovePoint(winding_t *w, int point) +{ + if (point < 0 || point >= w->numpoints) + Error("Winding_RemovePoint: point out of range"); + + if (point < w->numpoints-1) + { + memmove(&w->points[point], &w->points[point+1], (int)((winding_t *)0)->points[w->numpoints - point - 1]); + } + w->numpoints--; +} + +/* +============= +Winding_InsertPoint +============= +*/ +winding_t *Winding_InsertPoint(winding_t *w, vec3_t point, int spot) +{ + int i, j; + winding_t *neww; + + if (spot > w->numpoints) + { + Error("Winding_InsertPoint: spot > w->numpoints"); + } //end if + if (spot < 0) + { + Error("Winding_InsertPoint: spot < 0"); + } //end if + neww = Winding_Alloc(w->numpoints + 1); + neww->numpoints = w->numpoints + 1; + for (i = 0, j = 0; i < neww->numpoints; i++) + { + if (i == spot) + { + VectorCopy(point, neww->points[i]); + } + else + { + VectorCopy(w->points[j], neww->points[i]); + j++; + } + } + return neww; +} + +/* +============== +Winding_IsTiny +============== +*/ +#define EDGE_LENGTH 0.2 + +int Winding_IsTiny (winding_t *w) +{ + int i, j; + vec_t len; + vec3_t delta; + int edges; + + edges = 0; + for (i=0 ; inumpoints ; i++) + { + j = i == w->numpoints - 1 ? 0 : i+1; + VectorSubtract (w->points[j], w->points[i], delta); + len = VectorLength (delta); + if (len > EDGE_LENGTH) + { + if (++edges == 3) + return false; + } + } + return true; +} + +/* +============== +Winding_IsHuge +============== +*/ +int Winding_IsHuge(winding_t *w) +{ + int i, j; + + for (i=0 ; inumpoints ; i++) + { + for (j=0 ; j<3 ; j++) + if (w->points[i][j] < -BOGUS_RANGE+1 || w->points[i][j] > BOGUS_RANGE-1) + return true; + } + return false; +} + +/* +============= +Winding_PlanesConcave +============= +*/ +#define WCONVEX_EPSILON 0.2 + +int Winding_PlanesConcave(winding_t *w1, winding_t *w2, + vec3_t normal1, vec3_t normal2, + float dist1, float dist2) +{ + int i; + + if (!w1 || !w2) return false; + + // check if one of the points of winding 1 is at the back of the plane of winding 2 + for (i = 0; i < w1->numpoints; i++) + { + if (DotProduct(normal2, w1->points[i]) - dist2 > WCONVEX_EPSILON) return true; + } + // check if one of the points of winding 2 is at the back of the plane of winding 1 + for (i = 0; i < w2->numpoints; i++) + { + if (DotProduct(normal1, w2->points[i]) - dist1 > WCONVEX_EPSILON) return true; + } + + return false; +} + +/* +================== +Winding_Clip + +Clips the winding to the plane, returning the new winding on the positive side +Frees the input winding. +If keepon is true, an exactly on-plane winding will be saved, otherwise +it will be clipped away. +================== +*/ +winding_t *Winding_Clip (winding_t *in, plane_t *split, qboolean keepon) +{ + vec_t dists[MAX_POINTS_ON_WINDING]; + int sides[MAX_POINTS_ON_WINDING]; + int counts[3]; + vec_t dot; + int i, j; + vec_t *p1, *p2; + vec3_t mid; + winding_t *neww; + int maxpts; + + counts[0] = counts[1] = counts[2] = 0; + + // determine sides for each point + for (i=0 ; inumpoints ; i++) + { + dot = DotProduct (in->points[i], split->normal); + dot -= split->dist; + dists[i] = dot; + if (dot > ON_EPSILON) + sides[i] = SIDE_FRONT; + else if (dot < -ON_EPSILON) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + if (keepon && !counts[0] && !counts[1]) + return in; + + if (!counts[0]) + { + Winding_Free (in); + return NULL; + } + if (!counts[1]) + return in; + + maxpts = in->numpoints+4; // can't use counts[0]+2 because + // of fp grouping errors + neww = Winding_Alloc (maxpts); + + for (i=0 ; inumpoints ; i++) + { + p1 = in->points[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, neww->points[neww->numpoints]); + neww->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, neww->points[neww->numpoints]); + neww->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = in->points[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible + if (split->normal[j] == 1) + mid[j] = split->dist; + else if (split->normal[j] == -1) + mid[j] = -split->dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, neww->points[neww->numpoints]); + neww->numpoints++; + } + + if (neww->numpoints > maxpts) + Error ("Winding_Clip: points exceeded estimate"); + + // free the original winding + Winding_Free (in); + + return neww; +} + +/* +============= +Winding_SplitEpsilon + + split the input winding with the plane + the input winding stays untouched +============= +*/ +void Winding_SplitEpsilon (winding_t *in, vec3_t normal, double dist, + vec_t epsilon, winding_t **front, winding_t **back) +{ + vec_t dists[MAX_POINTS_ON_WINDING+4]; + int sides[MAX_POINTS_ON_WINDING+4]; + int counts[3]; + vec_t dot; + int i, j; + vec_t *p1, *p2; + vec3_t mid; + winding_t *f, *b; + int maxpts; + + counts[0] = counts[1] = counts[2] = 0; + + // determine sides for each point + for (i = 0; i < in->numpoints; i++) + { + dot = DotProduct (in->points[i], normal); + dot -= dist; + dists[i] = dot; + if (dot > epsilon) + sides[i] = SIDE_FRONT; + else if (dot < -epsilon) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + *front = *back = NULL; + + if (!counts[0]) + { + *back = Winding_Clone(in); + return; + } + if (!counts[1]) + { + *front = Winding_Clone(in); + return; + } + + maxpts = in->numpoints+4; // cant use counts[0]+2 because + // of fp grouping errors + + *front = f = Winding_Alloc (maxpts); + *back = b = Winding_Alloc (maxpts); + + for (i = 0; i < in->numpoints; i++) + { + p1 = in->points[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, f->points[f->numpoints]); + f->numpoints++; + VectorCopy (p1, b->points[b->numpoints]); + b->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, f->points[f->numpoints]); + f->numpoints++; + } + if (sides[i] == SIDE_BACK) + { + VectorCopy (p1, b->points[b->numpoints]); + b->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = in->points[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j = 0; j < 3; j++) + { + // avoid round off error when possible + if (normal[j] == 1) + mid[j] = dist; + else if (normal[j] == -1) + mid[j] = -dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, f->points[f->numpoints]); + f->numpoints++; + VectorCopy (mid, b->points[b->numpoints]); + b->numpoints++; + } + + if (f->numpoints > maxpts || b->numpoints > maxpts) + Error ("Winding_Clip: points exceeded estimate"); + if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING) + Error ("Winding_Clip: MAX_POINTS_ON_WINDING"); +} + +/* +============= +Winding_TryMerge + +If two windings share a common edge and the edges that meet at the +common points are both inside the other polygons, merge them + +Returns NULL if the windings couldn't be merged, or the new winding. +The originals will NOT be freed. + +if keep is true no points are ever removed +============= +*/ +#define CONTINUOUS_EPSILON 0.005 + +winding_t *Winding_TryMerge(winding_t *f1, winding_t *f2, vec3_t planenormal, int keep) +{ + vec_t *p1, *p2, *p3, *p4, *back; + winding_t *newf; + int i, j, k, l; + vec3_t normal, delta; + vec_t dot; + qboolean keep1, keep2; + + + // + // find a common edge + // + p1 = p2 = NULL; // stop compiler warning + j = 0; // + + for (i = 0; i < f1->numpoints; i++) + { + p1 = f1->points[i]; + p2 = f1->points[(i+1) % f1->numpoints]; + for (j = 0; j < f2->numpoints; j++) + { + p3 = f2->points[j]; + p4 = f2->points[(j+1) % f2->numpoints]; + for (k = 0; k < 3; k++) + { + if (fabs(p1[k] - p4[k]) > 0.1)//EQUAL_EPSILON) //ME + break; + if (fabs(p2[k] - p3[k]) > 0.1)//EQUAL_EPSILON) //ME + break; + } //end for + if (k==3) + break; + } //end for + if (j < f2->numpoints) + break; + } //end for + + if (i == f1->numpoints) + return NULL; // no matching edges + + // + // check slope of connected lines + // if the slopes are colinear, the point can be removed + // + back = f1->points[(i+f1->numpoints-1)%f1->numpoints]; + VectorSubtract (p1, back, delta); + CrossProduct (planenormal, delta, normal); + VectorNormalize (normal, normal); + + back = f2->points[(j+2)%f2->numpoints]; + VectorSubtract (back, p1, delta); + dot = DotProduct (delta, normal); + if (dot > CONTINUOUS_EPSILON) + return NULL; // not a convex polygon + keep1 = (qboolean)(dot < -CONTINUOUS_EPSILON); + + back = f1->points[(i+2)%f1->numpoints]; + VectorSubtract (back, p2, delta); + CrossProduct (planenormal, delta, normal); + VectorNormalize (normal, normal); + + back = f2->points[(j+f2->numpoints-1)%f2->numpoints]; + VectorSubtract (back, p2, delta); + dot = DotProduct (delta, normal); + if (dot > CONTINUOUS_EPSILON) + return NULL; // not a convex polygon + keep2 = (qboolean)(dot < -CONTINUOUS_EPSILON); + + // + // build the new polygon + // + newf = Winding_Alloc (f1->numpoints + f2->numpoints); + + // copy first polygon + for (k=(i+1)%f1->numpoints ; k != i ; k=(k+1)%f1->numpoints) + { + if (!keep && k==(i+1)%f1->numpoints && !keep2) + continue; + + VectorCopy (f1->points[k], newf->points[newf->numpoints]); + newf->numpoints++; + } + + // copy second polygon + for (l= (j+1)%f2->numpoints ; l != j ; l=(l+1)%f2->numpoints) + { + if (!keep && l==(j+1)%f2->numpoints && !keep1) + continue; + VectorCopy (f2->points[l], newf->points[newf->numpoints]); + newf->numpoints++; + } + + return newf; +} + +/* +============ +Winding_Plane +============ +*/ +void Winding_Plane (winding_t *w, vec3_t normal, double *dist) +{ + vec3_t v1, v2; + int i; + + //find two vectors each longer than 0.5 units + for (i = 0; i < w->numpoints; i++) + { + VectorSubtract(w->points[(i+1) % w->numpoints], w->points[i], v1); + VectorSubtract(w->points[(i+2) % w->numpoints], w->points[i], v2); + if (VectorLength(v1) > 0.5 && VectorLength(v2) > 0.5) break; + } + CrossProduct(v2, v1, normal); + VectorNormalize(normal, normal); + *dist = DotProduct(w->points[0], normal); +} + +/* +============= +Winding_Area +============= +*/ +float Winding_Area (winding_t *w) +{ + int i; + vec3_t d1, d2, cross; + float total; + + total = 0; + for (i=2 ; inumpoints ; i++) + { + VectorSubtract (w->points[i-1], w->points[0], d1); + VectorSubtract (w->points[i], w->points[0], d2); + CrossProduct (d1, d2, cross); + total += 0.5 * VectorLength ( cross ); + } + return total; +} + +/* +============= +Winding_Bounds +============= +*/ +void Winding_Bounds (winding_t *w, vec3_t mins, vec3_t maxs) +{ + vec_t v; + int i,j; + + mins[0] = mins[1] = mins[2] = 99999; + maxs[0] = maxs[1] = maxs[2] = -99999; + + for (i=0 ; inumpoints ; i++) + { + for (j=0 ; j<3 ; j++) + { + v = w->points[i][j]; + if (v < mins[j]) + mins[j] = v; + if (v > maxs[j]) + maxs[j] = v; + } + } +} + + +/* +================= +Winding_PointInside +================= +*/ +int Winding_PointInside(winding_t *w, plane_t *plane, vec3_t point, float epsilon) +{ + int i; + vec3_t dir, normal, pointvec; + + for (i = 0; i < w->numpoints; i++) + { + VectorSubtract(w->points[(i+1) % w->numpoints], w->points[i], dir); + VectorSubtract(point, w->points[i], pointvec); + // + CrossProduct(dir, plane->normal, normal); + // + if (DotProduct(pointvec, normal) < -epsilon) return false; + } + return true; +} + +/* +================= +Winding_VectorIntersect +================= +*/ +int Winding_VectorIntersect(winding_t *w, plane_t *plane, vec3_t p1, vec3_t p2, float epsilon) +{ + float front, back, frac; + vec3_t mid; + + front = DotProduct(p1, plane->normal) - plane->dist; + back = DotProduct(p2, plane->normal) - plane->dist; + //if both points at the same side of the plane + if (front < -epsilon && back < -epsilon) return false; + if (front > epsilon && back > epsilon) return false; + //get point of intersection with winding plane + if (fabs(front-back) < 0.001) + { + VectorCopy(p2, mid); + } + else + { + frac = front/(front-back); + mid[0] = p1[0] + (p2[0] - p1[0]) * frac; + mid[1] = p1[1] + (p2[1] - p1[1]) * frac; + mid[2] = p1[2] + (p2[2] - p1[2]) * frac; + } + return Winding_PointInside(w, plane, mid, epsilon); +} + diff --git a/radiant/xywindow.cpp b/radiant/xywindow.cpp index fabc809f..b24cdc80 100644 --- a/radiant/xywindow.cpp +++ b/radiant/xywindow.cpp @@ -1,3462 +1,3462 @@ -/* -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 -*/ - -// -// XY Window -// -// Leonardo Zide (leo@lokigames.com) -// - -#include "stdafx.h" -#include -#include -#include - -#ifdef _WIN32 -#include -#endif - -// ============================================================================= -// variables - -#define PAGEFLIPS 2 - -CString g_strStatus; -bool g_bCrossHairs = false; -bool g_bScaleMode; -int g_nScaleHow; -bool g_bRotateMode; -bool g_bClipMode; -bool g_bRogueClipMode; -bool g_bSwitch; -ClipPoint g_Clip1; -ClipPoint g_Clip2; -ClipPoint g_Clip3; -ClipPoint* g_pMovingClip; -brush_t g_brFrontSplits; -brush_t g_brBackSplits; - -brush_t g_brClipboard; -brush_t g_brUndo; -entity_t g_enClipboard; - -vec3_t g_vRotateOrigin; -vec3_t g_vRotation; - -bool g_bPathMode; -ClipPoint g_PathPoints[256]; // this limit isn't enforced? -ClipPoint* g_pMovingPath; -int g_nPathCount; -int g_nPathLimit; - -bool g_bSmartGo; - -bool g_bPointMode; -ClipPoint g_PointPoints[512]; -ClipPoint* g_pMovingPoint; -int g_nPointCount; -int g_nPointLimit; - -const int XY_LEFT = 0x01; -const int XY_RIGHT = 0x02; -const int XY_UP = 0x04; -const int XY_DOWN = 0x08; - -PFNPathCallback* g_pPathFunc = NULL; - -static unsigned s_stipple[32] = -{ - 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, - 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, - 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, - 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, - 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, - 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, - 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, - 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, -}; - -void AcquirePath(int nCount, PFNPathCallback* pFunc) -{ - g_nPathCount = 0; - g_nPathLimit = nCount; - g_pPathFunc = pFunc; - g_bPathMode = true; -} - - -CPtrArray g_ptrMenus; - -MemStream g_Clipboard(4096); -MemStream g_PatchClipboard(4096); - -extern int pressx; -extern int pressy; -extern bool g_bWaitCursor; - -vec3_t tdp; - -GtkWidget* XYWnd::m_mnuDrop = NULL; - -extern int g_nPatchClickedView; - -// ============================================================================= -// global functions - -// this is disabled, and broken -// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=394 -#if 0 -void WXY_Print () -{ - long width, height; - width = g_pParentWnd->ActiveXY()->Width(); - height = g_pParentWnd->ActiveXY()->Height(); - unsigned char* img; - const char* filename; - - filename = file_dialog (g_pParentWnd->m_pWidget, FALSE, "Save Image", NULL, FILTER_BMP); - if (!filename) - return; - - g_pParentWnd->ActiveXY()->MakeCurrent(); - img = (unsigned char*)malloc (width*height*3); - qglReadPixels (0,0,width,height,GL_RGB,GL_UNSIGNED_BYTE,img); - - FILE *fp; - fp = fopen(filename, "wb"); - if (fp) - { - unsigned short bits; - unsigned long cmap, bfSize; - - bits = 24; - cmap = 0; - bfSize = 54 + width*height*3; - - long byteswritten = 0; - long pixoff = 54 + cmap*4; - short res = 0; - char m1 ='B', m2 ='M'; - fwrite(&m1, 1, 1, fp); byteswritten++; // B - fwrite(&m2, 1, 1, fp); byteswritten++; // M - fwrite(&bfSize, 4, 1, fp); byteswritten+=4;// bfSize - fwrite(&res, 2, 1, fp); byteswritten+=2;// bfReserved1 - fwrite(&res, 2, 1, fp); byteswritten+=2;// bfReserved2 - fwrite(&pixoff, 4, 1, fp); byteswritten+=4;// bfOffBits - - unsigned long biSize = 40, compress = 0, size = 0; - long pixels = 0; - unsigned short planes = 1; - fwrite(&biSize, 4, 1, fp); byteswritten+=4;// biSize - fwrite(&width, 4, 1, fp); byteswritten+=4;// biWidth - fwrite(&height, 4, 1, fp); byteswritten+=4;// biHeight - fwrite(&planes, 2, 1, fp); byteswritten+=2;// biPlanes - fwrite(&bits, 2, 1, fp); byteswritten+=2;// biBitCount - fwrite(&compress, 4, 1, fp);byteswritten+=4;// biCompression - fwrite(&size, 4, 1, fp); byteswritten+=4;// biSizeImage - fwrite(&pixels, 4, 1, fp); byteswritten+=4;// biXPelsPerMeter - fwrite(&pixels, 4, 1, fp); byteswritten+=4;// biYPelsPerMeter - fwrite(&cmap, 4, 1, fp); byteswritten+=4;// biClrUsed - fwrite(&cmap, 4, 1, fp); byteswritten+=4;// biClrImportant - - unsigned long widthDW = (((width*24) + 31) / 32 * 4); - long row, row_size = width*3; - for (row = 0; row < height; row++) - { - unsigned char* buf = img+row*row_size; - - // write a row - int col; - for (col = 0; col < row_size; col += 3) - { - putc(buf[col+2], fp); - putc(buf[col+1], fp); - putc(buf[col], fp); - } - byteswritten += row_size; - - unsigned long count; - for (count = row_size; count < widthDW; count++) - { - putc(0, fp); // dummy - byteswritten++; - } - } - - fclose(fp); - } - - free (img); -} -#endif - -float ptSum(vec3_t pt) -{ - return pt[0] + pt[1] + pt[2]; -} - -float Betwixt(float f1, float f2) -{ - if (f1 > f2) - return f2 + ((f1 - f2) / 2); - else - return f1 + ((f2 - f1) / 2); -} - -void CleanList(brush_t* pList) -{ - brush_t* pBrush = pList->next; - while (pBrush != NULL && pBrush != pList) - { - brush_t* pNext = pBrush->next; - Brush_Free(pBrush); - pBrush = pNext; - } -} - -void Brush_CopyList (brush_t* pFrom, brush_t* pTo) -{ - brush_t* pBrush = pFrom->next; - while (pBrush != NULL && pBrush != pFrom) - { - brush_t* pNext = pBrush->next; - Brush_RemoveFromList(pBrush); - Brush_AddToList(pBrush, pTo); - pBrush = pNext; - } -} - -float fDiff(float f1, float f2) -{ - if (f1 > f2) - return f1 - f2; - else - return f2 - f1; -} - -/* -============================================================= - - PATH LINES - -============================================================= -*/ - -/* -================== -DrawPathLines - -Draws connections between entities. -Needs to consider all entities, not just ones on screen, -because the lines can be visible when neither end is. -Called for both camera view and xy view. -================== -*/ -void DrawPathLines (void) -{ - int i, j, k; - vec3_t mid, mid1; - entity_t *se, *te; - brush_t *sb, *tb; - const char *psz; - vec3_t dir, s1, s2; - vec_t len, f; - int arrows; - int num_entities; - const char *ent_target[MAX_MAP_ENTITIES]; - entity_t *ent_entity[MAX_MAP_ENTITIES]; - - if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS) - { - return; - } - - num_entities = 0; - for (te = entities.next ; te != &entities && num_entities != MAX_MAP_ENTITIES ; te = te->next) - { - ent_target[num_entities] = ValueForKey (te, "target"); - if (ent_target[num_entities][0]) - { - ent_entity[num_entities] = te; - num_entities++; - } - } - - for (se = entities.next ; se != &entities ; se = se->next) - { - psz = ValueForKey(se, "targetname"); - - if (psz == NULL || psz[0] == '\0') - continue; - - sb = se->brushes.onext; - if (sb == &se->brushes) - continue; - - for (k=0 ; kbrushes.onext; - if (tb == &te->brushes) - continue; - - for (i=0 ; i<3 ; i++) - mid[i] = (sb->mins[i] + sb->maxs[i])*0.5; - - for (i=0 ; i<3 ; i++) - mid1[i] = (tb->mins[i] + tb->maxs[i])*0.5; - - VectorSubtract (mid1, mid, dir); - len = VectorNormalize (dir, dir); - s1[0] = -dir[1]*8 + dir[0]*8; - s2[0] = dir[1]*8 + dir[0]*8; - s1[1] = dir[0]*8 + dir[1]*8; - s2[1] = -dir[0]*8 + dir[1]*8; - - qglColor3f (se->eclass->color[0], se->eclass->color[1], se->eclass->color[2]); - - qglBegin(GL_LINES); - qglVertex3fv(mid); - qglVertex3fv(mid1); - - arrows = (int)(len / 256) + 1; - - for (i=0 ; im_pWidget, "Can't create an entity with worldspawn.", "info", 0); - return; - } - - e = Entity_Alloc(); - SetKeyValue(e, "classname", name); - - if(e->eclass->fixedsize) - { - Select_Delete(); - b = Brush_Create(e->eclass->mins, e->eclass->maxs, &e->eclass->texdef); - Entity_LinkBrush(e, b); - Brush_AddToList(b, &active_brushes); - Select_Brush(b); - Brush_Move(b, origin, true); - } - else - { - Select_GroupEntity(e); - if(e->brushes.onext == &e->brushes) - { - Sys_FPrintf(SYS_ERR, "CreateEntityFromName: selection could not be grouped\n"); - Entity_Free(e); - return; - } - } - - Entity_AddToList(e, &entities); - Undo_EndEntity(e); - - Select_Deselect (); - - // tweaking: when right clic dropping a light entity, ask for light value in a custom dialog box - // see SF bug 105383 - - if (g_pGameDescription->mGameFile == "hl.game") - { - // FIXME - Hydra: really we need a combined light AND color dialog for halflife. - if ((stricmp(name, "light") == 0) || - (stricmp(name, "light_environment") == 0) || - (stricmp(name, "light_spot") == 0) ) - { - int intensity = g_PrefsDlg.m_iLastLightIntensity; - - // Create and show the dialog box - // CWnd *pWnd; - // pWnd = prompt.GetDlgItem( IDC_EDIT1 ); - // prompt.GotoDlgCtrl( pWnd ); - if (DoLightIntensityDlg (&intensity) == IDOK) - { - g_PrefsDlg.m_iLastLightIntensity = intensity; - char buf[30]; - sprintf( buf, "255 255 255 %d", intensity ); - SetKeyValue(e, "_light", buf); - } - } - } - else - { - if (stricmp(name, "light") == 0) - { - int intensity = g_PrefsDlg.m_iLastLightIntensity; - - // Create and show the dialog box - // CWnd *pWnd; - // pWnd = prompt.GetDlgItem( IDC_EDIT1 ); - // prompt.GotoDlgCtrl( pWnd ); - if (DoLightIntensityDlg (&intensity) == IDOK) - { - g_PrefsDlg.m_iLastLightIntensity = intensity; - char buf[10]; - sprintf( buf, "%d", intensity ); - SetKeyValue(e, "light", buf); - } - } - } - Select_Brush (e->brushes.onext); - - if ( (stricmp(name, "misc_model") == 0) || (stricmp(name, "misc_gamemodel") == 0) || (strcmpi(name, "model_static") == 0) ) - { - SetInspectorMode(W_ENTITY); - AssignModel(); - } -} - -void CreateRightClickEntity(XYWnd* pWnd, int x, int y, char* pName) -{ - int height = pWnd->GetWidget()->allocation.height; - vec3_t point; - pWnd->SnapToPoint (x, height - 1 - y, point); - - int nDim = (pWnd->GetViewType() == XY) ? 2 : (pWnd->GetViewType() == YZ) ? 0 : 1; - float fWorkMid = (g_qeglobals.d_work_min[nDim] + g_qeglobals.d_work_max[nDim]) * 0.5; - point[nDim] = g_qeglobals.d_gridsize * ((int)(fWorkMid/g_qeglobals.d_gridsize)); - - CreateEntityFromName(pName, point); -} - - -brush_t* CreateSmartBrush(vec3_t v) -{ - vec3_t mins, maxs; - int i; - brush_t *n; - - for (i=0 ; i<3 ; i++) - { - mins[i] = v[i] - 16; - maxs[i] = v[i] + 16; - } - - n = Brush_Create (mins, maxs, &g_qeglobals.d_texturewin.texdef); - if (!n) - return NULL; - - Brush_AddToList(n, &selected_brushes); - //Entity_LinkBrush(world_entity, n); - Brush_Build(n); - return n; -} - -CString g_strSmartEntity; -int g_nSmartX; -int g_nSmartY; -bool g_bSmartWaiting; -void _SmartPointDone(bool b, int n) -{ - g_bSmartWaiting = false; -} - -void CreateSmartEntity(XYWnd* pWnd, int x, int y, const char* pName) -{ - g_nSmartX = x; - g_nSmartY = y; - g_strSmartEntity = pName; - if (g_strSmartEntity.Find("Smart_Train") >= 0) - { - ShowInfoDialog("Select the path of the train by left clicking in XY, YZ and/or XZ views. You can move an already dropped point by grabbing and moving it. When you are finished, press ENTER to accept and create the entity and path(s), press ESC to abandon the creation"); - g_bPathMode = true; - g_nPathLimit = 0; - g_nPathCount = 0; - g_bSmartGo = true; - } - else - if (g_strSmartEntity.Find("Smart_Monster...") >= 0) - { - g_bPathMode = true; - g_nPathLimit = 0; - g_nPathCount = 0; - } - else - if (g_strSmartEntity.Find("Smart_Rotating") >= 0) - { - g_bSmartWaiting = true; - ShowInfoDialog("Left click to specify the rotation origin"); - AcquirePath(1, &_SmartPointDone); - while (g_bSmartWaiting) - gtk_main_iteration (); - HideInfoDialog(); - CPtrArray array; - g_bScreenUpdates = false; - CreateRightClickEntity(g_pParentWnd->ActiveXY(), g_nSmartX, g_nSmartY, "func_rotating"); - array.Add(reinterpret_cast(selected_brushes.next)); - Select_Deselect(); - brush_t* pBrush = CreateSmartBrush(g_PathPoints[0]); - array.Add(pBrush); - Select_Deselect(); - Select_Brush(reinterpret_cast(array.GetAt(0))); - Select_Brush(reinterpret_cast(array.GetAt(1))); - ConnectEntities(); - g_bScreenUpdates = true; - } -} - -void FinishSmartCreation() -{ - CPtrArray array; - HideInfoDialog(); - // brush_t* pEntities = NULL; - int n; - - if (g_strSmartEntity.Find("Smart_Train") >= 0) - { - g_bScreenUpdates = false; - CreateRightClickEntity(g_pParentWnd->ActiveXY(), g_nSmartX, g_nSmartY, "func_train"); - array.Add(reinterpret_cast(selected_brushes.next)); - for (n = 0; n < g_nPathCount; n++) - { - Select_Deselect(); - CreateRightClickEntity(g_pParentWnd->ActiveXY(), g_PathPoints[n].m_ptScreenX, - g_PathPoints[n].m_ptScreenY, "path_corner"); - array.Add(reinterpret_cast(selected_brushes.next)); - } - - for (n = 0; n < g_nPathCount; n++) - { - Select_Deselect(); - Select_Brush(reinterpret_cast(array.GetAt(n))); - Select_Brush(reinterpret_cast(array.GetAt(n+1))); - ConnectEntities(); - } - g_bScreenUpdates = true; - - } - g_nPathCount = 0; - g_bPathMode = false; - Sys_UpdateWindows(W_ALL); -} - -void CleanCopyEntities() -{ - entity_t* pe = g_enClipboard.next; - while (pe != NULL && pe != &g_enClipboard) - { - entity_t* next = pe->next; - epair_t* enext = NULL; - for (epair_t* ep = pe->epairs ; ep ; ep=enext) - { - enext = ep->next; - free (ep->key); - free (ep->value); - free (ep); - } - free (pe); - pe = next; - } - g_enClipboard.next = g_enClipboard.prev = &g_enClipboard; -} - -entity_t *Entity_CopyClone (entity_t *e) -{ - entity_t *n; - epair_t *ep, *np; - - n = (entity_t*)qmalloc(sizeof(*n)); - n->brushes.onext = n->brushes.oprev = &n->brushes; - n->eclass = e->eclass; - - // add the entity to the entity list - n->next = g_enClipboard.next; - g_enClipboard.next = n; - n->next->prev = n; - n->prev = &g_enClipboard; - - for (ep = e->epairs ; ep ; ep=ep->next) - { - np = (epair_t*)qmalloc(sizeof(*np)); - np->key = copystring(ep->key); - np->value = copystring(ep->value); - np->next = n->epairs; - n->epairs = np; - } - return n; -} - -bool OnList(entity_t* pFind, CPtrArray* pList) -{ - int nSize = pList->GetSize(); - while (nSize-- > 0) - { - entity_t* pEntity = reinterpret_cast(pList->GetAt(nSize)); - if (pEntity == pFind) - return true; - } - return false; -} - -// ============================================================================= -// XYWnd class - -XYWnd::XYWnd () - : GLWindow (FALSE), m_XORRectangle(m_pWidget) -{ - g_brClipboard.next = &g_brClipboard; - g_brUndo.next = &g_brUndo; - g_nScaleHow = 0; - g_bRotateMode = false; - g_bClipMode = false; - g_bRogueClipMode = false; - g_bSwitch = true; - g_pMovingClip = (ClipPoint*)NULL; - g_pMovingPath = (ClipPoint*)NULL; - g_brFrontSplits.next = &g_brFrontSplits; - g_brBackSplits.next = &g_brBackSplits; - m_bActive = false; - //m_bTiming = true; - m_bTiming = false; - m_bRButtonDown = false; - m_nUpdateBits = W_XY; - g_bPathMode = false; - g_nPathCount = 0; - g_nPathLimit = 0; - m_nButtonstate = 0; -// m_mnuDrop = (GtkWidget*)NULL; - XY_Init(); -} - -vec3_t& XYWnd::Rotation() -{ - return g_vRotation; -} - -vec3_t& XYWnd::RotateOrigin() -{ - return g_vRotateOrigin; -} - -/* -============== -XY_Overlay -============== -*/ -void XYWnd::XY_Overlay() -{ - int w, h; - int r[4]; - static vec3_t lastz; - static vec3_t lastcamera; - - qglViewport(0, 0, m_nWidth, m_nHeight); - - // - // set up viewpoint - // - qglMatrixMode(GL_PROJECTION); - qglLoadIdentity (); - - w = (int)(m_nWidth / 2 / m_fScale); - h = (int)(m_nHeight / 2 / m_fScale); - - qglOrtho (m_vOrigin[0] - w, m_vOrigin[0] + w , m_vOrigin[1] - h, m_vOrigin[1] + h, g_MinWorldCoord, g_MaxWorldCoord); - // - // erase the old camera and z checker positions - // if the entire xy hasn't been redrawn - // - if (m_bDirty) - { - qglReadBuffer (GL_BACK); - qglDrawBuffer (GL_FRONT); - - qglRasterPos2f (lastz[0]-9, lastz[1]-9); - qglGetIntegerv (GL_CURRENT_RASTER_POSITION,r); - qglCopyPixels(r[0], r[1], 18,18, GL_COLOR); - - qglRasterPos2f (lastcamera[0]-50, lastcamera[1]-50); - qglGetIntegerv (GL_CURRENT_RASTER_POSITION,r); - qglCopyPixels(r[0], r[1], 100,100, GL_COLOR); - } - m_bDirty = true; - - // - // save off underneath where we are about to draw - // - VectorCopy (z.origin, lastz); - VectorCopy (g_pParentWnd->GetCamWnd()->Camera()->origin, lastcamera); - - qglReadBuffer (GL_FRONT); - qglDrawBuffer (GL_BACK); - - qglRasterPos2f (lastz[0]-9, lastz[1]-9); - qglGetIntegerv (GL_CURRENT_RASTER_POSITION,r); - qglCopyPixels(r[0], r[1], 18,18, GL_COLOR); - - qglRasterPos2f (lastcamera[0]-50, lastcamera[1]-50); - qglGetIntegerv (GL_CURRENT_RASTER_POSITION,r); - qglCopyPixels(r[0], r[1], 100,100, GL_COLOR); - - // - // draw the new icons - // - qglDrawBuffer (GL_FRONT); - - qglShadeModel (GL_FLAT); - qglDisable(GL_TEXTURE_2D); - qglDisable(GL_TEXTURE_1D); - qglDisable(GL_DEPTH_TEST); - qglDisable(GL_BLEND); - qglColor3f(0, 0, 0); - - DrawCameraIcon (); - DrawZIcon (); - - qglDrawBuffer (GL_BACK); - qglFinish(); -} - -vec3_t& XYWnd::GetOrigin() -{ - return m_vOrigin; -} - -void XYWnd::SetOrigin(vec3_t org) -{ - m_vOrigin[0] = org[0]; - m_vOrigin[1] = org[1]; - m_vOrigin[2] = org[2]; -} - -void XYWnd::OnSize(int cx, int cy) -{ - m_nWidth = cx; - m_nHeight = cy; -} - -brush_t hold_brushes; - -void XYWnd::Clip() -{ - if (ClipMode()) - { - hold_brushes.next = &hold_brushes; - ProduceSplitLists(); - brush_t* pList; - if (g_PrefsDlg.m_bSwitchClip) - pList = (!g_bSwitch) ? &g_brFrontSplits : &g_brBackSplits; - else - pList = (g_bSwitch) ? &g_brFrontSplits : &g_brBackSplits; - - if (pList->next != pList) - { - Brush_CopyList(pList, &hold_brushes); - CleanList(&g_brFrontSplits); - CleanList(&g_brBackSplits); - Select_Delete(); - Brush_CopyList(&hold_brushes, &selected_brushes); - if (RogueClipMode()) - RetainClipMode(false); - else - RetainClipMode(true); - Sys_UpdateWindows(W_ALL); - } - } - else if (PathMode()) - { - FinishSmartCreation(); - if (g_pPathFunc) - g_pPathFunc(true, g_nPathCount); - g_pPathFunc = NULL; - g_nPathCount = 0; - g_bPathMode = false; - } -} - -void XYWnd::SplitClip() -{ - ProduceSplitLists(); - if ((g_brFrontSplits.next != &g_brFrontSplits) && - (g_brBackSplits.next != &g_brBackSplits)) - { - Select_Delete(); - Brush_CopyList(&g_brFrontSplits, &selected_brushes); - Brush_CopyList(&g_brBackSplits, &selected_brushes); - CleanList(&g_brFrontSplits); - CleanList(&g_brBackSplits); - if (RogueClipMode()) - RetainClipMode(false); - else - RetainClipMode(true); - } -} - -void XYWnd::FlipClip() -{ - g_bSwitch = !g_bSwitch; - Sys_UpdateWindows(XY | W_CAMERA_IFON); -} - -// makes sure the selected brush or camera is in view -void XYWnd::PositionView() -{ - int nDim1 = (m_nViewType == YZ) ? 1 : 0; - int nDim2 = (m_nViewType == XY) ? 1 : 2; - brush_t* b = selected_brushes.next; - if (b && b->next != b) - { - Select_GetMid (m_vOrigin); - } - else - { - m_vOrigin[nDim1] = g_pParentWnd->GetCamWnd()->Camera()->origin[nDim1]; - m_vOrigin[nDim2] = g_pParentWnd->GetCamWnd()->Camera()->origin[nDim2]; - } -} - -void XYWnd::VectorCopyXY(vec3_t in, vec3_t out) -{ - if (m_nViewType == XY) - { - out[0] = in[0]; - out[1] = in[1]; - } - else if (m_nViewType == XZ) - { - out[0] = in[0]; - out[2] = in[2]; - } - else - { - out[1] = in[1]; - out[2] = in[2]; - } -} - -void XYWnd::RetainClipMode(bool bMode) -{ - bool bSave = g_bRogueClipMode; - SetClipMode(bMode); - if (bMode == true) - g_bRogueClipMode = bSave; - else - g_bRogueClipMode = false; -} - -void XYWnd::SetClipMode(bool bMode) -{ - g_bClipMode = bMode; - g_bRogueClipMode = false; - if (bMode) - { - g_Clip1.Reset(); - g_Clip2.Reset(); - g_Clip3.Reset(); - CleanList(&g_brFrontSplits); - CleanList(&g_brBackSplits); - g_brFrontSplits.next = &g_brFrontSplits; - g_brBackSplits.next = &g_brBackSplits; - - // ydnar: set clipper points based on first selected patch mesh - if( selected_brushes.next != &selected_brushes ) - { - bool found = false; - for( brush_t *pb = selected_brushes.next; pb != &selected_brushes; pb = pb->next ) - { - if( pb->patchBrush ) - { - found = true; - VectorCopy( pb->pPatch->ctrl[ 0 ][ 0 ].xyz, g_Clip1.m_ptClip ); - VectorCopy( pb->pPatch->ctrl[ pb->pPatch->width - 1 ][ pb->pPatch->height - 1 ].xyz, g_Clip2.m_ptClip ); - VectorCopy( pb->pPatch->ctrl[ pb->pPatch->width - 1 ][ 0 ].xyz, g_Clip3.m_ptClip ); - g_Clip1.Set( true ); - g_Clip2.Set( true ); - g_Clip3.Set( true ); - break; - } - } - - if( found ) - { - // SetClipMode( true ); - Sys_UpdateWindows( XY | W_CAMERA_IFON ); - } - } - } - else - { - if (g_pMovingClip) - { - ReleaseCapture(); - g_pMovingClip = NULL; - } - CleanList(&g_brFrontSplits); - CleanList(&g_brBackSplits); - g_brFrontSplits.next = &g_brFrontSplits; - g_brBackSplits.next = &g_brBackSplits; - Sys_UpdateWindows(XY | W_CAMERA_IFON); - } -} - -bool XYWnd::ClipMode() -{ - return g_bClipMode; -} - -bool XYWnd::RogueClipMode() -{ - return g_bRogueClipMode; -} - -bool XYWnd::PathMode() -{ - return g_bPathMode; -} - -bool XYWnd::PointMode() -{ - return g_bPointMode; -} - -void XYWnd::SetPointMode(bool b) -{ - g_bPointMode = b; - if (!b) - g_nPointCount = 0; -} - -void XYWnd::SetViewType(int n) -{ - m_nViewType = n; - if (g_pParentWnd->CurrentStyle() == MainFrame::eFloating) - { - char* str = "YZ Side"; - if (m_nViewType == XY) - str = "XY Top"; - else if (m_nViewType == XZ) - str = "XZ Front"; - - if (m_pParent != NULL) - gtk_window_set_title (GTK_WINDOW (m_pParent), str); - } -} - -void XYWnd::Redraw(unsigned int nBits) -{ - m_nUpdateBits = nBits; - gtk_widget_queue_draw(m_pWidget); - m_nUpdateBits = W_XY; -} - -bool XYWnd::RotateMode() -{ - return g_bRotateMode; -} - -bool XYWnd::ScaleMode() -{ - return g_bScaleMode; -} - -bool XYWnd::SetRotateMode(bool bMode) -{ - if (bMode && selected_brushes.next != &selected_brushes) - { - g_bRotateMode = true; - Select_GetTrueMid(g_vRotateOrigin); - g_vRotation[0] = g_vRotation[1] = g_vRotation[2] = 0.0; - } - else - { - if (bMode) - Sys_Printf("Need a brush selected to turn on Mouse Rotation mode\n"); - g_bRotateMode = false; - } - RedrawWindow(); - return g_bRotateMode; -} - -void XYWnd::SetScaleMode(bool bMode) -{ - g_bScaleMode = bMode; - RedrawWindow(); -} - -rectangle_t rectangle_from_area_xy() -{ - XYWnd* xy = g_pParentWnd->ActiveXY(); - int nDim1 = (xy->GetViewType() == YZ) ? 1 : 0; - int nDim2 = (xy->GetViewType() == XY) ? 1 : 2; - float origin_left = xy->GetOrigin()[nDim1] - (xy->Width() / 2) / xy->Scale(); - float origin_bottom = xy->GetOrigin()[nDim2] - (xy->Height() / 2) / xy->Scale(); - float left = MIN(g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1]) - origin_left; - float top = MAX(g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2]) - origin_bottom; - float right = MAX(g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1]) - origin_left; - float bottom = MIN(g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2]) - origin_bottom; - left *= xy->Scale(); - top *= xy->Scale(); - right *= xy->Scale(); - bottom *= xy->Scale(); - return rectangle_t(left, bottom, right - left, top - bottom); -} - -void update_xor_rectangle_xy(XORRectangle& xor_rectangle) -{ - rectangle_t rectangle; - if ((g_qeglobals.d_select_mode == sel_area)) - rectangle = rectangle_from_area_xy(); - xor_rectangle.set(rectangle); -} - -void XYWnd::OnMouseMove(guint32 nFlags, int pointx, int pointy) -{ - // plugin entities - // TODO TTimo handle return code - DispatchOnMouseMove (nFlags, pointx, pointy); - - m_ptDownX = 0; - m_ptDownY = 0; - - if (g_PrefsDlg.m_bChaseMouse == TRUE && - (pointx < 0 || pointy < 0 || pointx > m_nWidth || pointy > m_nHeight) && - HasCapture ()) - { - float fAdjustment = (g_qeglobals.d_gridsize / 8 * 64) / m_fScale; - //m_ptDrag = point; - m_ptDragAdjX = 0; - m_ptDragAdjY = 0; - - if (pointx < 0) - { - m_ptDragAdjX = (int)(-fAdjustment); - } - else if (pointx > m_nWidth) - { - m_ptDragAdjX = (int)(fAdjustment); - } - - if (pointy < 0) - { - m_ptDragAdjY = (int)(-fAdjustment); - } - else if (pointy > m_nHeight) - { - m_ptDragAdjY = (int)(fAdjustment); - } - - if (!HasTimer ()) - { - SetTimer (50); - m_ptDragX = pointx; - m_ptDragY = pointy; - m_ptDragTotalX = 0; - m_ptDragTotalY = 0; - } - return; - } - - if (HasTimer ()) - { - KillTimer (); - pressx -= m_ptDragTotalX; - pressy += m_ptDragTotalY; - } - - bool bCrossHair = false; - if (!m_bRButtonDown) - { - tdp[0] = tdp[1] = tdp[2] = 0.0; - SnapToPoint (pointx, m_nHeight - 1 - pointy , tdp); - - g_strStatus.Format("x:: %.1f y:: %.1f z:: %.1f", tdp[0], tdp[1], tdp[2]); - g_pParentWnd->SetStatusText(1, g_strStatus); - - // i need to generalize the point code.. having 3 flavors pretty much sucks.. - // once the new curve stuff looks like it is going to stick i will - // rationalize this down to a single interface.. - if (PointMode()) - { - if (g_pMovingPoint && HasCapture ()) - { - bCrossHair = true; - SnapToPoint (pointx, m_nHeight - 1 - pointy , g_pMovingPoint->m_ptClip); - g_pMovingPoint->UpdatePointPtr(); - Sys_UpdateWindows(XY | W_CAMERA_IFON); - } - else - { - g_pMovingPoint = NULL; - int nDim1 = (m_nViewType == YZ) ? 1 : 0; - int nDim2 = (m_nViewType == XY) ? 1 : 2; - for (int n = 0; n < g_nPointCount; n++) - { - if ( fDiff(g_PointPoints[n].m_ptClip[nDim1], tdp[nDim1]) < 3 && - fDiff(g_PointPoints[n].m_ptClip[nDim2], tdp[nDim2]) < 3 ) - { - bCrossHair = true; - g_pMovingPoint = &g_PointPoints[n]; - } - } - } - } - else if (ClipMode()) - { - if (g_pMovingClip && HasCapture ()) - { - bCrossHair = true; - SnapToPoint (pointx, m_nHeight - 1 - pointy , g_pMovingClip->m_ptClip); - Sys_UpdateWindows(XY | W_CAMERA_IFON); - } - else - { - g_pMovingClip = NULL; - int nDim1 = (m_nViewType == YZ) ? 1 : 0; - int nDim2 = (m_nViewType == XY) ? 1 : 2; - if (g_Clip1.Set()) - { - if ( fDiff(g_Clip1.m_ptClip[nDim1], tdp[nDim1]) < 3 && - fDiff(g_Clip1.m_ptClip[nDim2], tdp[nDim2]) < 3 ) - { - bCrossHair = true; - g_pMovingClip = &g_Clip1; - } - } - if (g_Clip2.Set()) - { - if ( fDiff(g_Clip2.m_ptClip[nDim1], tdp[nDim1]) < 3 && - fDiff(g_Clip2.m_ptClip[nDim2], tdp[nDim2]) < 3 ) - { - bCrossHair = true; - g_pMovingClip = &g_Clip2; - } - } - if (g_Clip3.Set()) - { - if ( fDiff(g_Clip3.m_ptClip[nDim1], tdp[nDim1]) < 3 && - fDiff(g_Clip3.m_ptClip[nDim2], tdp[nDim2]) < 3 ) - { - bCrossHair = true; - g_pMovingClip = &g_Clip3; - } - } - } - if (bCrossHair == false) - XY_MouseMoved (pointx, m_nHeight - 1 - pointy , nFlags); - } - else if (PathMode()) - { - if (g_pMovingPath && HasCapture ()) - { - bCrossHair = true; - SnapToPoint (pointx, m_nHeight - 1 - pointy , g_pMovingPath->m_ptClip); - Sys_UpdateWindows(XY | W_CAMERA_IFON); - } - else - { - g_pMovingPath = NULL; - int nDim1 = (m_nViewType == YZ) ? 1 : 0; - int nDim2 = (m_nViewType == XY) ? 1 : 2; - for (int n = 0; n < g_nPathCount; n++) - { - if ( fDiff(g_PathPoints[n].m_ptClip[nDim1], tdp[nDim1]) < 3 && - fDiff(g_PathPoints[n].m_ptClip[nDim2], tdp[nDim2]) < 3 ) - { - bCrossHair = true; - g_pMovingPath = &g_PathPoints[n]; - } - } - } - } - else - { - XY_MouseMoved (pointx, m_nHeight - 1 - pointy , nFlags); - } - } - else - { - XY_MouseMoved (pointx, m_nHeight - 1 - pointy , nFlags); - } - - if ((nFlags & MK_RBUTTON) == 0) - { - if (bCrossHair && !g_bWaitCursor) - { - GdkCursor *cursor; - cursor = gdk_cursor_new (GDK_CROSSHAIR); - gdk_window_set_cursor (m_pWidget->window, cursor); - gdk_cursor_unref (cursor); - } - else - { - gdk_window_set_cursor (m_pWidget->window, NULL); - } - } - - update_xor_rectangle_xy(m_XORRectangle); -} - -void XYWnd::OnMouseWheel(bool bUp) -{ - if (bUp) - g_pParentWnd->OnViewZoomin (); - else - g_pParentWnd->OnViewZoomout (); - - int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); - Sys_UpdateWindows (nUpdate); - g_pParentWnd->OnTimer (); -} - -void XYWnd::OnTimer () -{ - int nDim1 = (m_nViewType == YZ) ? 1 : 0; - int nDim2 = (m_nViewType == XY) ? 1 : 2; - m_vOrigin[nDim1] += m_ptDragAdjX / m_fScale; - m_vOrigin[nDim2] -= m_ptDragAdjY / m_fScale; - Sys_UpdateWindows(W_XY | W_CAMERA); - m_ptDragX += m_ptDragAdjX; - m_ptDragY += m_ptDragAdjY; - m_ptDragTotalX += m_ptDragAdjX; - m_ptDragTotalY += m_ptDragAdjY; - XY_MouseMoved (m_ptDragX, m_nHeight - 1 - m_ptDragY , m_nScrollFlags); -} - -void XYWnd::OnLButtonDown(guint32 flags, int pointx, int pointy) -{ - g_pParentWnd->SetActiveXY(this); - UndoCopy(); - - // plugin entities - if (DispatchOnLButtonDown(flags, pointx, pointy)) - return; - - if (ClipMode() && !RogueClipMode()) - { - DropClipPoint(flags, pointx, pointy); - } - else if (PathMode()) - { - DropPathPoint(flags, pointx, pointy); - } - else OriginalButtonDown(flags, pointx, pointy); -} - -void XYWnd::OnMButtonDown(guint32 flags, int pointx, int pointy) -{ - OriginalButtonDown(flags, pointx, pointy); -} - -void XYWnd::OnRButtonDown(guint32 flags, int pointx, int pointy) -{ - g_pParentWnd->SetActiveXY(this); - m_ptDownX = pointx; - m_ptDownY = pointy; - m_bRButtonDown = true; - - if (g_PrefsDlg.m_nMouseButtons == 3) // 3 button mouse - { - if (flags & MK_CONTROL) - { - if (ClipMode()) // already there? - DropClipPoint(flags, pointx, pointy); - else - { - SetClipMode(true); - g_bRogueClipMode = true; - DropClipPoint(flags, pointx, pointy); - } - return; - } - } - OriginalButtonDown(flags, pointx, pointy); -} - -void XYWnd::OnLButtonUp(guint32 flags, int pointx, int pointy) -{ - // plugin entities - if (DispatchOnLButtonUp(flags, pointx, pointy)) - return; - - if (ClipMode()) - { - if (g_pMovingClip) - { - ReleaseCapture(); - g_pMovingClip = NULL; - } - } - OriginalButtonUp(flags, pointx, pointy); -} - -void XYWnd::OnMButtonUp(guint32 flags, int pointx, int pointy) -{ - OriginalButtonUp(flags, pointx, pointy); -} - -void XYWnd::OnRButtonUp(guint32 flags, int pointx, int pointy) -{ - m_bRButtonDown = false; - if ((pointx == m_ptDownX) && (pointy == m_ptDownY)) // mouse didn't move - { - bool bGo = true; - if (Sys_AltDown ()) - bGo = false; - if (flags & MK_CONTROL) - bGo = false; - if (flags & MK_SHIFT) - bGo = false; - if (bGo) - HandleDrop(); - } - OriginalButtonUp(flags, pointx, pointy); -} - -void XYWnd::XY_MouseDown (int x, int y, int buttons) -{ - vec3_t point; - vec3_t origin, dir, right, up; - - m_nButtonstate = buttons; - m_nPressx = x; - m_nPressy = y; - VectorCopy (vec3_origin, m_vPressdelta); - - VectorClear(point); - XY_ToPoint (x, y, point); - - VectorCopy (point, origin); - - VectorClear (dir); - if (m_nViewType == XY) // view facing dir = negative Z - { - origin[2] = g_MaxWorldCoord; - dir[2] = -1; - right[0] = 1 / m_fScale; - right[1] = 0; - right[2] = 0; - up[0] = 0; - up[1] = 1 / m_fScale; - up[2] = 0; - } - else if (m_nViewType == XZ) - { - origin[1] = g_MinWorldCoord; // view facing dir = positive Y - dir[1] = 1; - right[0] = 1 / m_fScale; - right[1] = 0; - right[2] = 0; - up[0] = 0; - up[1] = 0; - up[2] = 1 / m_fScale; - } - else // if (m_nViewType == YZ) // view facing dir = negative X - { - origin[0] = g_MaxWorldCoord; - dir[0] = -1; - right[0] = 0; - right[1] = 1 / m_fScale; - right[2] = 0; - up[0] = 0; - up[1] = 0; - up[2] = 1 / m_fScale; - } - - m_bPress_selection = (selected_brushes.next != &selected_brushes); - - Sys_GetCursorPos(&m_ptCursorX, &m_ptCursorY); - - // lbutton = manipulate selection - // shift-LBUTTON = select - if ( (buttons == MK_LBUTTON) - || (buttons == (MK_LBUTTON | MK_SHIFT)) - || (buttons == (MK_LBUTTON | MK_CONTROL)) - || (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) ) - { - Patch_SetView( (m_nViewType == XY) ? W_XY : (m_nViewType == YZ) ? W_YZ : W_XZ); - Drag_Begin (x, y, buttons, right, up, origin, dir); - return; - } - - int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON; - - // control mbutton = move camera - if (m_nButtonstate == (MK_CONTROL|nMouseButton) ) - { - VectorCopyXY(point, g_pParentWnd->GetCamWnd()->Camera()->origin); - Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); - } - - // mbutton = angle camera - if ((g_PrefsDlg.m_nMouseButtons == 3 && m_nButtonstate == MK_MBUTTON) || - (g_PrefsDlg.m_nMouseButtons == 2 && m_nButtonstate == (MK_SHIFT|MK_CONTROL|MK_RBUTTON))) - { - VectorSubtract (point, g_pParentWnd->GetCamWnd()->Camera()->origin, point); - - int n1 = (m_nViewType == XY) ? 1 : 2; - int n2 = (m_nViewType == YZ) ? 1 : 0; - int nAngle = (m_nViewType == XY) ? YAW : PITCH; - if (point[n1] || point[n2]) - { - g_pParentWnd->GetCamWnd()->Camera()->angles[nAngle] = 180/Q_PI*atan2 (point[n1], point[n2]); - Sys_UpdateWindows (W_CAMERA_IFON|W_XY_OVERLAY); - } - } - - // shift mbutton = move z checker - if (m_nButtonstate == (MK_SHIFT | nMouseButton)) - { - if (RotateMode() || g_bPatchBendMode) - { - SnapToPoint (x, y, point); - VectorCopyXY(point, g_vRotateOrigin); - if (g_bPatchBendMode) - { - VectorCopy(point, g_vBendOrigin); - } - Sys_UpdateWindows (W_XY); - return; - } - else - { - SnapToPoint (x, y, point); - if (m_nViewType == XY) - { - z.origin[0] = point[0]; - z.origin[1] = point[1]; - } - else if (m_nViewType == YZ) - { - z.origin[0] = point[1]; - z.origin[1] = point[2]; - } - else - { - z.origin[0] = point[0]; - z.origin[1] = point[2]; - } - Sys_UpdateWindows (W_XY_OVERLAY|W_Z); - return; - } - } - - update_xor_rectangle_xy(m_XORRectangle); -} - -void XYWnd::XY_MouseUp(int x, int y, int buttons) -{ - Drag_MouseUp (buttons); - if (!m_bPress_selection) - Sys_UpdateWindows (W_ALL); - m_nButtonstate = 0; - - gdk_window_set_cursor (m_pWidget->window, NULL); - - update_xor_rectangle_xy(m_XORRectangle); -} - -qboolean XYWnd::DragDelta (int x, int y, vec3_t move) -{ - vec3_t xvec, yvec, delta; - int i; - - xvec[0] = 1 / m_fScale; - xvec[1] = xvec[2] = 0; - yvec[1] = 1 / m_fScale; - yvec[0] = yvec[2] = 0; - - for (i=0 ; i<3 ; i++) - { - delta[i] = xvec[i] * (x - m_nPressx) + yvec[i] * (y - m_nPressy); - if (!g_PrefsDlg.m_bNoClamp) - { - delta[i] = floor(delta[i] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; - } - } - VectorSubtract (delta, m_vPressdelta, move); - VectorCopy (delta, m_vPressdelta); - - if (move[0] || move[1] || move[2]) - return true; - return false; -} - -void XYWnd::HandleDrop() -{ - if (g_PrefsDlg.m_bRightClick == false) - return; - - if (m_mnuDrop == NULL) // first time, load it up - { - int nID = ID_ENTITY_START; - GtkWidget *menu, *menu_in_menu, *item, *submenu, *submenu_root; - - menu = m_mnuDrop = gtk_menu_new (); - - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Select"); - create_menu_item_with_mnemonic (menu_in_menu, "Select Complete Tall", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTCOMPLETETALL); - create_menu_item_with_mnemonic (menu_in_menu, "Select Touching", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTTOUCHING); - create_menu_item_with_mnemonic (menu_in_menu, "Select Partial Tall", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTPARTIALTALL); - create_menu_item_with_mnemonic (menu_in_menu, "Select Inside", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTINSIDE); - menu_separator (menu); nID++; - // NOTE: temporary commented out until we put it back in for good (that is with actual features) - /* - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Group",); - create_menu_item_with_mnemonic (menu_in_menu, "Add to...", - GTK_SIGNAL_FUNC (HandleCommand), ID_DROP_GROUP_ADDTO); - create_menu_item_with_mnemonic (menu_in_menu, "Remove", - GTK_SIGNAL_FUNC (HandleCommand), ID_DROP_GROUP_REMOVE); - create_menu_item_with_mnemonic (menu_in_menu, "Name...", - GTK_SIGNAL_FUNC (HandleCommand), ID_DROP_GROUP_NAME); - menu_separator (menu_in_menu); nID++; - create_menu_item_with_mnemonic (menu_in_menu, "New Group...", - GTK_SIGNAL_FUNC (HandleCommand), ID_DROP_GROUP_NEWGROUP); - */ - create_menu_item_with_mnemonic (menu, "Ungroup Entity", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_UNGROUPENTITY); - - create_menu_item_with_mnemonic (menu, "Move into entity", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MERGE); - create_menu_item_with_mnemonic (menu, "Move into worldspawn", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SEPERATE); - - create_menu_item_with_mnemonic (menu, "Make Detail", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MAKE_DETAIL); - create_menu_item_with_mnemonic (menu, "Make Structural", - GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MAKE_STRUCTURAL); - menu_separator (menu); nID++; - - menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Smart Entities"); - create_menu_item_with_mnemonic (menu_in_menu, "Smart__Train", - GTK_SIGNAL_FUNC (HandleCommand), nID++); - menu_separator (menu); nID++; - - submenu = NULL; - submenu_root = NULL; - eclass_t *e; - CString strActive; - CString strLast; - CString strName; - for (e=eclass ; e ; e=e->next) - { - strLast = strName; - strName = e->name; - int n_ = strName.Find("_"); - if (n_ > 0) - { - CString strLeft = strName.Left(n_); - CString strRight = strName.Right(strName.GetLength() - n_ - 1); - if (strLeft == strActive) // this is a child - { - assert (submenu); - item = gtk_menu_item_new_with_label (strName); - gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (nID++)); - gtk_widget_show (item); - CheckMenuSplitting(submenu); - gtk_menu_append (GTK_MENU (submenu), item); - } - else - { - if (submenu) - { - // this is submenu from previous main_item, hook it back - // we use submenu_root cause we may have been cascading submenu - item = gtk_menu_item_new_with_label (strActive); - gtk_widget_show (item); - gtk_menu_append (GTK_MENU (menu), item); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu_root); - g_ptrMenus.Add(submenu_root); - submenu = NULL; - submenu_root = NULL; - } - strActive = strLeft; - - submenu = gtk_menu_new (); - submenu_root = submenu; - item = gtk_menu_item_new_with_label (strName); - gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (nID++)); - gtk_widget_show (item); - gtk_menu_append (GTK_MENU (submenu), item); - } - } - else - { - if (submenu) - { - // this is submenu from previous main_item, hook it back - // we use submenu_root cause we may have been cascading submenu - item = gtk_menu_item_new_with_label (strActive); - gtk_widget_show (item); - gtk_menu_append (GTK_MENU (menu), item); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu_root); - g_ptrMenus.Add(submenu_root); - submenu = NULL; - submenu_root = NULL; - } - strActive = ""; - - item = gtk_menu_item_new_with_label (strName); - gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (HandleCommand), - GINT_TO_POINTER (nID++)); - gtk_widget_show (item); - gtk_menu_append (GTK_MENU (menu), item); - } - } - } - - gtk_menu_popup (GTK_MENU (m_mnuDrop), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME); -} - -/* -============== -NewBrushDrag -============== -*/ -void XYWnd::NewBrushDrag (int x, int y) -{ - vec3_t mins, maxs, junk; - int i; - float temp; - brush_t *n; - - if (!DragDelta (x,y, junk)) - return; - - // delete the current selection - if (selected_brushes.next != &selected_brushes) - Brush_Free (selected_brushes.next); - - SnapToPoint (m_nPressx, m_nPressy, mins); - - int nDim = (m_nViewType == XY) ? 2 : (m_nViewType == YZ) ? 0 : 1; - - //++timo clean -// mins[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_bottom_z / g_qeglobals.d_gridsize)); - mins[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_work_min[nDim]/g_qeglobals.d_gridsize)); - - SnapToPoint (x, y, maxs); -// maxs[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_top_z / g_qeglobals.d_gridsize)); - maxs[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_work_max[nDim]/g_qeglobals.d_gridsize)); - if (maxs[nDim] <= mins[nDim]) - maxs[nDim] = mins[nDim] + g_qeglobals.d_gridsize; - - for (i=0 ; i<3 ; i++) - { - if (mins[i] == maxs[i]) - return; // don't create a degenerate brush - if (mins[i] > maxs[i]) - { - temp = mins[i]; - mins[i] = maxs[i]; - maxs[i] = temp; - } - } - - n = Brush_Create (mins, maxs, &g_qeglobals.d_texturewin.texdef); - if (!n) - return; - - vec3_t vSize; - VectorSubtract(maxs, mins, vSize); - g_strStatus.Format("Size X:: %.1f Y:: %.1f Z:: %.1f", vSize[0], vSize[1], vSize[2]); - g_pParentWnd->SetStatusText(2, g_strStatus); - - Brush_AddToList (n, &selected_brushes); - - Entity_LinkBrush (world_entity, n); - - Brush_Build( n ); - - // Sys_UpdateWindows (W_ALL); - Sys_UpdateWindows (W_XY| W_CAMERA); - -} - -/* -============== -XY_MouseMoved -============== -*/ -void XYWnd::XY_MouseMoved (int x, int y, int buttons) -{ - vec3_t point; - - if (!m_nButtonstate) - { - if (g_bCrossHairs) - { - Sys_UpdateWindows (W_XY | W_XY_OVERLAY); - } - return; - } - - // lbutton without selection = drag new brush - if (m_nButtonstate == MK_LBUTTON && !m_bPress_selection && g_qeglobals.d_select_mode != sel_curvepoint && g_qeglobals.d_select_mode != sel_areatall) - { - NewBrushDrag (x, y); - return; - } - - // lbutton (possibly with control and or shift) - // with selection = drag selection - if (m_nButtonstate & MK_LBUTTON) - { - Drag_MouseMoved (x, y, buttons); - if(g_qeglobals.d_select_mode != sel_area) - Sys_UpdateWindows (W_XY_OVERLAY | W_CAMERA_IFON | W_Z); - return; - } - - int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON; - // control mbutton = move camera - if (m_nButtonstate == (MK_CONTROL|nMouseButton) ) - { - SnapToPoint (x, y, point); - VectorCopyXY(point, g_pParentWnd->GetCamWnd()->Camera()->origin); - Sys_UpdateWindows (W_XY_OVERLAY | W_CAMERA); - return; - } - - // shift mbutton = move z checker - if (m_nButtonstate == (MK_SHIFT|nMouseButton) ) - { - if (RotateMode() || g_bPatchBendMode) - { - SnapToPoint (x, y, point); - VectorCopyXY(point, g_vRotateOrigin); - if (g_bPatchBendMode) - { - VectorCopy(point, g_vBendOrigin); - } - Sys_UpdateWindows (W_XY); - return; - } - else - { - SnapToPoint (x, y, point); - if (m_nViewType == XY) - { - z.origin[0] = point[0]; - z.origin[1] = point[1]; - } - else if (m_nViewType == YZ) - { - z.origin[0] = point[1]; - z.origin[1] = point[2]; - } - else - { - z.origin[0] = point[0]; - z.origin[1] = point[2]; - } - } - Sys_UpdateWindows (W_XY_OVERLAY|W_Z); - return; - } - - // mbutton = angle camera - if ((g_PrefsDlg.m_nMouseButtons == 3 && m_nButtonstate == MK_MBUTTON) || - (g_PrefsDlg.m_nMouseButtons == 2 && m_nButtonstate == (MK_SHIFT|MK_CONTROL|MK_RBUTTON))) - { - SnapToPoint (x, y, point); - VectorSubtract (point, g_pParentWnd->GetCamWnd()->Camera()->origin, point); - - int n1 = (m_nViewType == XY) ? 1 : 2; - int n2 = (m_nViewType == YZ) ? 1 : 0; - int nAngle = (m_nViewType == XY) ? YAW : PITCH; - if (point[n1] || point[n2]) - { - g_pParentWnd->GetCamWnd()->Camera()->angles[nAngle] = 180/Q_PI*atan2 (point[n1], point[n2]); - Sys_UpdateWindows (W_CAMERA_IFON|W_XY_OVERLAY); - } - return; - } - - // rbutton = drag xy origin - if (m_nButtonstate == MK_RBUTTON) - { - Sys_GetCursorPos (&x, &y); - if (x != m_ptCursorX || y != m_ptCursorY) - { - int nDim1 = (m_nViewType == YZ) ? 1 : 0; - int nDim2 = (m_nViewType == XY) ? 1 : 2; - m_vOrigin[nDim1] -= (x - m_ptCursorX) / m_fScale; - m_vOrigin[nDim2] += (y - m_ptCursorY) / m_fScale; - Sys_SetCursorPos (m_ptCursorX, m_ptCursorY); - - // create an empty cursor - if (!g_bWaitCursor) - { - GdkPixmap *pixmap; - GdkBitmap *mask; - char buffer [(32 * 32)/8]; - memset (buffer, 0, (32 * 32)/8); - GdkColor white = {0, 0xffff, 0xffff, 0xffff}; - GdkColor black = {0, 0x0000, 0x0000, 0x0000}; - pixmap = gdk_bitmap_create_from_data (NULL, buffer, 32, 32); - mask = gdk_bitmap_create_from_data (NULL, buffer, 32, 32); - GdkCursor *cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &white, &black, 1, 1); - gdk_window_set_cursor (m_pWidget->window, cursor); - gdk_cursor_unref (cursor); - gdk_drawable_unref (pixmap); - gdk_drawable_unref (mask); - } - - Sys_UpdateWindows (W_XY | W_XY_OVERLAY); - } - return; - } - - // zoom in/out - if (m_nButtonstate == (MK_SHIFT | MK_RBUTTON)) - { - Sys_GetCursorPos (&x, &y); - if (y != m_ptCursorY) - { - if (abs (m_ptCursorY - y) > 10) - { - if (m_ptCursorY < y) - g_pParentWnd->OnViewZoomout (); - else - g_pParentWnd->OnViewZoomin (); - - Sys_SetCursorPos (m_ptCursorX, m_ptCursorY); - } - } - return; - } -} - -void XYWnd::OriginalButtonDown(guint32 nFlags, int pointx, int pointy) -{ - SetFocus(); - SetCapture(); - XY_MouseDown (pointx, m_pWidget->allocation.height - 1 - pointy , nFlags); - m_nScrollFlags = nFlags; -} - -void XYWnd::OriginalButtonUp(guint32 nFlags, int pointx, int pointy) -{ - XY_MouseUp (pointx, m_pWidget->allocation.height - 1 - pointy , nFlags); - ReleaseCapture (); -} - -void XYWnd::DropClipPoint(guint32 nFlags, int pointx, int pointy) -{ - if (g_pMovingClip) - { - SetCapture(); - SnapToPoint (pointx, m_pWidget->allocation.height - 1 - pointy , *g_pMovingClip); - } - else - { - vec3_t* pPt = NULL; - if (g_Clip1.Set() == false) - { - pPt = g_Clip1; - g_Clip1.Set(true); - g_Clip1.m_ptScreenX = pointx; - g_Clip1.m_ptScreenY = pointy; - } - else - if (g_Clip2.Set() == false) - { - pPt = g_Clip2; - g_Clip2.Set(true); - g_Clip2.m_ptScreenX = pointx; - g_Clip2.m_ptScreenY = pointy; - } - else - if (g_Clip3.Set() == false) - { - pPt = g_Clip3; - g_Clip3.Set(true); - g_Clip3.m_ptScreenX = pointx; - g_Clip3.m_ptScreenY = pointy; - } - else - { - RetainClipMode(true); - pPt = g_Clip1; - g_Clip1.Set(true); - g_Clip1.m_ptScreenX = pointx; - g_Clip1.m_ptScreenY = pointy; - } - SnapToPoint (pointx, m_pWidget->allocation.height - 1 - pointy , *pPt); - // third coordinates for clip point: use d_work_max - // Arnout: changed to use center of selection for clipping, saves level designers moving points all over the map - // g_pParentWnd->ActiveXY()->GetViewType() - // cf VIEWTYPE defintion: enum VIEWTYPE {YZ, XZ, XY}; - int nViewType = g_pParentWnd->ActiveXY()->GetViewType(); - int nDim = (nViewType == YZ ) ? nDim = 0 : ( (nViewType == XZ) ? nDim = 1 : nDim = 2 ); - //(*pPt)[nDim] = g_qeglobals.d_work_max[nDim]; - vec3_t mid; - Select_GetMid( mid ); - (*pPt)[nDim] = mid[nDim]; - } - Sys_UpdateWindows(XY | W_CAMERA_IFON); -} - -void XYWnd::DropPathPoint(guint32 nFlags, int pointx, int pointy) -{ - if (g_pMovingPath) - { - SetCapture(); - SnapToPoint (pointx, m_pWidget->allocation.height - 1 - pointy , *g_pMovingPath); - } - else - { - g_PathPoints[g_nPathCount].Set(true); - g_PathPoints[g_nPathCount].m_ptScreenX = pointx; - g_PathPoints[g_nPathCount].m_ptScreenY = pointy; - SnapToPoint(pointx, m_pWidget->allocation.height - 1 - pointy, g_PathPoints[g_nPathCount]); - // third coordinates for dropped point: use d_work_max - // g_pParentWnd->ActiveXY()->GetViewType() - // cf VIEWTYPE definition: enum VIEWTYPE {YZ, XZ, XY}; - int nViewType = g_pParentWnd->ActiveXY()->GetViewType(); - int nDim = (nViewType == YZ ) ? nDim = 0 : ( (nViewType == XZ) ? nDim = 1 : nDim = 2 ); - g_PathPoints[g_nPathCount].m_ptClip[nDim] = g_qeglobals.d_work_max[nDim]; - - g_nPathCount++; - if (g_nPathCount == g_nPathLimit) - { - if (g_pPathFunc) - g_pPathFunc(true, g_nPathCount); - g_nPathCount = 0; - g_bPathMode = false; - g_pPathFunc = NULL; - } - } - Sys_UpdateWindows(XY | W_CAMERA_IFON); -} - -// FIXME: AddPointPoint() redundant function never called -#if 0 -void XYWnd::AddPointPoint(guint32 nFlags, vec3_t* pVec) -{ - g_PointPoints[g_nPointCount].Set(true); - //g_PointPoints[g_nPointCount].m_ptScreen = point; - _VectorCopy(*pVec, g_PointPoints[g_nPointCount]); - g_PointPoints[g_nPointCount].SetPointPtr(pVec); - g_nPointCount++; - Sys_UpdateWindows(XY | W_CAMERA_IFON); -} - -// FIXME: ProduceSplits() redundant function never called -void XYWnd::ProduceSplits(brush_t** pFront, brush_t** pBack) -{ - *pFront = NULL; - *pBack = NULL; - if (ClipMode()) - { - if (g_Clip1.Set() && g_Clip2.Set()) - { - face_t face; - VectorCopy(g_Clip1.m_ptClip,face.planepts[0]); - VectorCopy(g_Clip2.m_ptClip,face.planepts[1]); - VectorCopy(g_Clip3.m_ptClip,face.planepts[2]); - if (selected_brushes.next && (selected_brushes.next->next == &selected_brushes)) - { - if (g_Clip3.Set() == false) - { - if (m_nViewType == XY) - { - face.planepts[0][2] = selected_brushes.next->mins[2]; - face.planepts[1][2] = selected_brushes.next->mins[2]; - face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]); - face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]); - face.planepts[2][2] = selected_brushes.next->maxs[2]; - } - else if (m_nViewType == YZ) - { - face.planepts[0][0] = selected_brushes.next->mins[0]; - face.planepts[1][0] = selected_brushes.next->mins[0]; - face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]); - face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]); - face.planepts[2][0] = selected_brushes.next->maxs[0]; - } - else - { - face.planepts[0][1] = selected_brushes.next->mins[1]; - face.planepts[1][1] = selected_brushes.next->mins[1]; - face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]); - face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]); - face.planepts[2][1] = selected_brushes.next->maxs[1]; - } - } - - Brush_SplitBrushByFace (selected_brushes.next, &face, pFront, pBack); - } - - } - } -} -#endif - -void XYWnd::PlanePointsFromClipPoints(vec3_t planepts[3], brush_t *pBrush) -{ - VectorCopy(g_Clip1.m_ptClip,planepts[0]); - VectorCopy(g_Clip2.m_ptClip,planepts[1]); - VectorCopy(g_Clip3.m_ptClip,planepts[2]); - if (g_Clip3.Set() == false) - { - int n = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 2 : (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 0 : 1; - int x = (n == 0) ? 1 : 0; - int y = (n == 2) ? 1 : 2; - - if (n == 1) // on viewtype XZ, flip clip points - { - planepts[0][n] = pBrush->maxs[n]; - planepts[1][n] = pBrush->maxs[n]; - planepts[2][x] = g_Clip1.m_ptClip[x]; - planepts[2][y] = g_Clip1.m_ptClip[y]; - planepts[2][n] = pBrush->mins[n]; - } - else - { - planepts[0][n] = pBrush->mins[n]; - planepts[1][n] = pBrush->mins[n]; - planepts[2][x] = g_Clip1.m_ptClip[x]; - planepts[2][y] = g_Clip1.m_ptClip[y]; - planepts[2][n] = pBrush->maxs[n]; - } - } -} - -void XYWnd::ProduceSplitLists() -{ - bool bCaulk = false; - int nFlags; - - if (AnyPatchesSelected()) - { - Sys_Printf("Deselecting patches for clip operation.\n"); - brush_t *next; - for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = next) - { - next = pb->next; - if (pb->patchBrush) - { - Brush_RemoveFromList (pb); - Brush_AddToList (pb, &active_brushes); - UpdatePatchInspector(); - } - } - // ydnar: update the window if any patches are selected - Sys_UpdateWindows( XY | W_CAMERA_IFON ); - } - - CleanList(&g_brFrontSplits); - CleanList(&g_brBackSplits); - g_brFrontSplits.next = &g_brFrontSplits; - g_brBackSplits.next = &g_brBackSplits; - if (ClipMode() && (g_Clip1.Set() && g_Clip2.Set())) - { - brush_t* pBrush; - for (pBrush = selected_brushes.next ; pBrush != NULL && pBrush != &selected_brushes ; pBrush=pBrush->next) - { - brush_t* pFront = NULL; - brush_t* pBack = NULL; - - face_t face; - memset(&face,0,sizeof(face_t)); - PlanePointsFromClipPoints(face.planepts, pBrush); - - // decide wether caulking should be applied on the splits - // FIXME: hack - // this should take the first brush face, check shader for NODRAW, if it isn't nodraw then find the appropriate - // common/ shader to use, out of solid+nodraw, nonsolid+nodraw, water+nodraw, lava+nodraw, nonsolid+nodraw+trans, water+nodraw+trans, lava+nodraw+trans.. and fog.. etc - // or if none of those apply (unlikely), construct a new shader (shadername_nodraw) based on the shader of the first face, but with surfaceparm nodraw - if (g_PrefsDlg.m_bClipCaulk) - { - nFlags = pBrush->brush_faces->pShader->getFlags(); - if ((nFlags & QER_NODRAW) || (nFlags & QER_NONSOLID) || (nFlags & QER_WATER) || (nFlags & QER_LAVA) || (nFlags & QER_FOG)) // first face shader is anything other than solid AND opaque like caulk - bCaulk = false; // use first face's shader for the splitting face - else - bCaulk = true; // use caulk - } - - Brush_SplitBrushByFace (pBrush, &face, &pFront, &pBack, bCaulk); - if (pBack) - Brush_AddToList(pBack, &g_brBackSplits); - if (pFront) - Brush_AddToList(pFront, &g_brFrontSplits); - - } - } -} - -void XYWnd::XY_Init() -{ - m_vOrigin[0] = 0; - m_vOrigin[1] = 20; - m_vOrigin[2] = 46; - m_fScale = 1; -} - -void XYWnd::SnapToPoint (int x, int y, vec3_t point) -{ - if (g_PrefsDlg.m_bNoClamp) - { - XY_ToPoint(x, y, point); - } - else - { - XY_ToGridPoint(x, y, point); - } -} - -// TTimo: watch it, this doesn't init one of the 3 coords -void XYWnd::XY_ToPoint (int x, int y, vec3_t point) -{ - float fx = x; - float fy = y; - float fw = m_nWidth; - float fh = m_nHeight; - if (m_nViewType == XY) - { - point[0] = m_vOrigin[0] + (fx - fw / 2) / m_fScale; - point[1] = m_vOrigin[1] + (fy - fh / 2) / m_fScale; - } - else if (m_nViewType == YZ) - { - point[1] = m_vOrigin[1] + (fx - fw / 2) / m_fScale; - point[2] = m_vOrigin[2] + (fy - fh / 2 ) / m_fScale; - } - else - { - point[0] = m_vOrigin[0] + (fx - fw / 2) / m_fScale; - point[2] = m_vOrigin[2] + (fy - fh / 2) / m_fScale; - } -} - -void XYWnd::XY_ToGridPoint (int x, int y, vec3_t point) -{ - if (m_nViewType == XY) - { - point[0] = m_vOrigin[0] + (x - m_nWidth / 2) / m_fScale; - point[1] = m_vOrigin[1] + (y - m_nHeight / 2) / m_fScale; - point[0] = floor(point[0] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; - point[1] = floor(point[1] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; - } - else if (m_nViewType == YZ) - { - point[1] = m_vOrigin[1] + (x - m_nWidth / 2) / m_fScale; - point[2] = m_vOrigin[2] + (y - m_nHeight / 2) / m_fScale; - point[1] = floor(point[1] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; - point[2] = floor(point[2] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; - } - else - { - point[0] = m_vOrigin[0] + (x - m_nWidth / 2) / m_fScale; - point[2] = m_vOrigin[2] + (y - m_nHeight / 2) / m_fScale; - point[0] = floor(point[0] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; - point[2] = floor(point[2] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; - } -} - -/* -============================================================================ - -DRAWING - -============================================================================ -*/ - -/* -============== -XY_DrawGrid -============== -*/ -void XYWnd::XY_DrawGrid() -{ - float x, y, xb, xe, yb, ye; - float w, h; - char text[32]; - int step, stepx, stepy, colour; - step = stepx = stepy = MAX (64, (int)g_qeglobals.d_gridsize); - - /* - int stepSize = (int)(8 / m_fScale); - if (stepSize > step) - { - int i; - for (i = 1; i < stepSize; i <<= 1) - ; - step = i; - } - */ - - //Sys_Printf("scale: %f\n", m_fScale); - //Sys_Printf("step before: %i\n", step); - //Sys_Printf("scaled step: %f\n", step * m_fScale); - while ((step * m_fScale) < 4.0f) // make sure major grid spacing is at least 4 pixels on the screen - step *= 8; - //Sys_Printf("step after: %i\n", step); - while ((stepx * m_fScale) < 32.0f) // text step x must be at least 32 - stepx *= 2; - while ((stepy * m_fScale) < 32.0f) // text step y must be at least 32 - stepy *= 2; - - qglDisable(GL_TEXTURE_2D); - qglDisable(GL_TEXTURE_1D); - qglDisable(GL_DEPTH_TEST); - qglDisable(GL_BLEND); - - w = (m_nWidth / 2 / m_fScale); - h = (m_nHeight / 2 / m_fScale); - - int nDim1 = (m_nViewType == YZ) ? 1 : 0; - int nDim2 = (m_nViewType == XY) ? 1 : 2; - - xb = m_vOrigin[nDim1] - w; - if (xb < region_mins[nDim1]) - xb = region_mins[nDim1]; - xb = step * floor (xb/step); - - xe = m_vOrigin[nDim1] + w; - if (xe > region_maxs[nDim1]) - xe = region_maxs[nDim1]; - xe = step * ceil (xe/step); - - yb = m_vOrigin[nDim2] - h; - if (yb < region_mins[nDim2]) - yb = region_mins[nDim2]; - yb = step * floor (yb/step); - - ye = m_vOrigin[nDim2] + h; - if (ye > region_maxs[nDim2]) - ye = region_maxs[nDim2]; - ye = step * ceil (ye/step); - -#define COLORS_DIFFER(a,b) \ - (g_qeglobals.d_savedinfo.colors[a][0] != g_qeglobals.d_savedinfo.colors[b][0] || \ - g_qeglobals.d_savedinfo.colors[a][1] != g_qeglobals.d_savedinfo.colors[b][1] || \ - g_qeglobals.d_savedinfo.colors[a][2] != g_qeglobals.d_savedinfo.colors[b][2]) - - // djbob - // draw minor blocks - if (m_fScale > .1 && g_qeglobals.d_showgrid && g_qeglobals.d_gridsize * m_fScale >= 4) - { - if (g_qeglobals.d_gridsize < 1) - colour = COLOR_GRIDMINOR_ALT; - else - colour = COLOR_GRIDMINOR; - - if (COLORS_DIFFER(colour, COLOR_GRIDBACK)) - { - qglColor3fv(g_qeglobals.d_savedinfo.colors[colour]); - - qglBegin (GL_LINES); - for (x=xb ; x 65536 || g_qeglobals.blockSize < 1024) - // don't use custom blocksize if it is less than the default, or greater than the maximum world coordinate - g_qeglobals.blockSize = 1024; - - float x, y, xb, xe, yb, ye; - float w, h; - char text[32]; - - qglDisable(GL_TEXTURE_2D); - qglDisable(GL_TEXTURE_1D); - qglDisable(GL_DEPTH_TEST); - qglDisable(GL_BLEND); - - w = (m_nWidth / 2 / m_fScale); - h = (m_nHeight / 2 / m_fScale); - - int nDim1 = (m_nViewType == YZ) ? 1 : 0; - int nDim2 = (m_nViewType == XY) ? 1 : 2; - - xb = m_vOrigin[nDim1] - w; - if (xb < region_mins[nDim1]) - xb = region_mins[nDim1]; - xb = g_qeglobals.blockSize * floor (xb/g_qeglobals.blockSize); - - xe = m_vOrigin[nDim1] + w; - if (xe > region_maxs[nDim1]) - xe = region_maxs[nDim1]; - xe = g_qeglobals.blockSize * ceil (xe/g_qeglobals.blockSize); - - yb = m_vOrigin[nDim2] - h; - if (yb < region_mins[nDim2]) - yb = region_mins[nDim2]; - yb = g_qeglobals.blockSize * floor (yb/g_qeglobals.blockSize); - - ye = m_vOrigin[nDim2] + h; - if (ye > region_maxs[nDim2]) - ye = region_maxs[nDim2]; - ye = g_qeglobals.blockSize * ceil (ye/g_qeglobals.blockSize); - - // draw major blocks - - qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK]); - qglLineWidth (2); - - qglBegin (GL_LINES); - - for (x=xb ; x<=xe ; x+=g_qeglobals.blockSize) - { - qglVertex2f (x, yb); - qglVertex2f (x, ye); - } - - if (m_nViewType == XY) - { - for (y=yb ; y<=ye ; y+=g_qeglobals.blockSize) - { - qglVertex2f (xb, y); - qglVertex2f (xe, y); - } - } - - qglEnd (); - qglLineWidth (1); - - // draw coordinate text if needed - - if (m_nViewType == XY && m_fScale > .1) - { - for (x=xb ; xGetCamWnd()->Camera()->origin[0]; - y = g_pParentWnd->GetCamWnd()->Camera()->origin[1]; - a = g_pParentWnd->GetCamWnd()->Camera()->angles[YAW]/180*Q_PI; - } - else if (m_nViewType == YZ) - { - x = g_pParentWnd->GetCamWnd()->Camera()->origin[1]; - y = g_pParentWnd->GetCamWnd()->Camera()->origin[2]; - a = g_pParentWnd->GetCamWnd()->Camera()->angles[PITCH]/180*Q_PI; - } - else - { - x = g_pParentWnd->GetCamWnd()->Camera()->origin[0]; - y = g_pParentWnd->GetCamWnd()->Camera()->origin[2]; - a = g_pParentWnd->GetCamWnd()->Camera()->angles[PITCH]/180*Q_PI; - } - - qglColor3f (0.0, 0.0, 1.0); - qglBegin(GL_LINE_STRIP); - qglVertex3f (x-box,y,0); - qglVertex3f (x,y+(box/2),0); - qglVertex3f (x+box,y,0); - qglVertex3f (x,y-(box/2),0); - qglVertex3f (x-box,y,0); - qglVertex3f (x+box,y,0); - qglEnd (); - - qglBegin(GL_LINE_STRIP); - qglVertex3f (x+fov*cos(a+Q_PI/4), y+fov*sin(a+Q_PI/4), 0); - qglVertex3f (x, y, 0); - qglVertex3f (x+fov*cos(a-Q_PI/4), y+fov*sin(a-Q_PI/4), 0); - qglEnd (); - -} - -void XYWnd::DrawZIcon (void) -{ - if (m_nViewType == XY) - { - float x = z.origin[0]; - float y = z.origin[1]; - float zdim = 8 / m_fScale; - qglEnable (GL_BLEND); - qglDisable (GL_TEXTURE_2D); - qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); - qglDisable (GL_CULL_FACE); - qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - qglColor4f (0.0, 0.0, 1.0, 0.25); - qglBegin(GL_QUADS); - qglVertex3f (x-zdim,y-zdim,0); - qglVertex3f (x+zdim,y-zdim,0); - qglVertex3f (x+zdim,y+zdim,0); - qglVertex3f (x-zdim,y+zdim,0); - qglEnd (); - qglDisable (GL_BLEND); - - qglColor4f (0.0, 0.0, 1.0, 1); - - qglBegin(GL_LINE_LOOP); - qglVertex3f (x-zdim,y-zdim,0); - qglVertex3f (x+zdim,y-zdim,0); - qglVertex3f (x+zdim,y+zdim,0); - qglVertex3f (x-zdim,y+zdim,0); - qglEnd (); - - qglBegin(GL_LINE_STRIP); - qglVertex3f (x-(zdim/2),y+(zdim/2),0); - qglVertex3f (x+(zdim/2),y+(zdim/2),0); - qglVertex3f (x-(zdim/2),y-(zdim/2),0); - qglVertex3f (x+(zdim/2),y-(zdim/2),0); - qglEnd (); - } -} - -// can be greatly simplified but per usual i am in a hurry -// which is not an excuse, just a fact -void XYWnd::PaintSizeInfo(int nDim1, int nDim2, vec3_t vMinBounds, vec3_t vMaxBounds) -{ - const char* g_pDimStrings[] = {"x:%.f", "y:%.f", "z:%.f"}; - const char* g_pOrgStrings[] = {"(x:%.f y:%.f)", "(x:%.f z:%.f)", "(y:%.f z:%.f)"}; - - CString g_strDim; - - vec3_t vSize; - VectorSubtract(vMaxBounds, vMinBounds, vSize); - - qglColor3f(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0] * .65, - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1] * .65, - g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2] * .65); - - if (m_nViewType == XY) - { - qglBegin (GL_LINES); - - qglVertex3f(vMinBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale, 0.0f); - qglVertex3f(vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f); - - qglVertex3f(vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f); - qglVertex3f(vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f); - - qglVertex3f(vMaxBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale, 0.0f); - qglVertex3f(vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f); - - - qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, vMinBounds[nDim2], 0.0f); - qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2], 0.0f); - - qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2], 0.0f); - qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2], 0.0f); - - qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, vMaxBounds[nDim2], 0.0f); - qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2], 0.0f); - - qglEnd(); - - qglRasterPos3f (Betwixt(vMinBounds[nDim1], vMaxBounds[nDim1]), vMinBounds[nDim2] - 20.0 / m_fScale, 0.0f); - g_strDim.Format(g_pDimStrings[nDim1], vSize[nDim1]); - gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); - - qglRasterPos3f (vMaxBounds[nDim1] + 16.0 / m_fScale, Betwixt(vMinBounds[nDim2], vMaxBounds[nDim2]), 0.0f); - g_strDim.Format(g_pDimStrings[nDim2], vSize[nDim2]); - gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); - - qglRasterPos3f (vMinBounds[nDim1] + 4, vMaxBounds[nDim2] + 8 / m_fScale, 0.0f); - g_strDim.Format(g_pOrgStrings[0], vMinBounds[nDim1], vMaxBounds[nDim2]); - gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); - } - else if (m_nViewType == XZ) - { - qglBegin (GL_LINES); - - qglVertex3f(vMinBounds[nDim1], 0, vMinBounds[nDim2] - 6.0f / m_fScale); - qglVertex3f(vMinBounds[nDim1], 0, vMinBounds[nDim2] - 10.0f / m_fScale); - - qglVertex3f(vMinBounds[nDim1], 0,vMinBounds[nDim2] - 10.0f / m_fScale); - qglVertex3f(vMaxBounds[nDim1], 0,vMinBounds[nDim2] - 10.0f / m_fScale); - - qglVertex3f(vMaxBounds[nDim1], 0,vMinBounds[nDim2] - 6.0f / m_fScale); - qglVertex3f(vMaxBounds[nDim1], 0,vMinBounds[nDim2] - 10.0f / m_fScale); - - - qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, 0,vMinBounds[nDim2]); - qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0,vMinBounds[nDim2]); - - qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0,vMinBounds[nDim2]); - qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0,vMaxBounds[nDim2]); - - qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, 0,vMaxBounds[nDim2]); - qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0,vMaxBounds[nDim2]); - - qglEnd(); - - qglRasterPos3f (Betwixt(vMinBounds[nDim1], vMaxBounds[nDim1]), 0, vMinBounds[nDim2] - 20.0 / m_fScale); - g_strDim.Format(g_pDimStrings[nDim1], vSize[nDim1]); - gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); - - qglRasterPos3f (vMaxBounds[nDim1] + 16.0 / m_fScale, 0, Betwixt(vMinBounds[nDim2], vMaxBounds[nDim2])); - g_strDim.Format(g_pDimStrings[nDim2], vSize[nDim2]); - gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); - - qglRasterPos3f (vMinBounds[nDim1] + 4, 0, vMaxBounds[nDim2] + 8 / m_fScale); - g_strDim.Format(g_pOrgStrings[1], vMinBounds[nDim1], vMaxBounds[nDim2]); - gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); - } - else - { - qglBegin (GL_LINES); - - qglVertex3f(0, vMinBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale); - qglVertex3f(0, vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale); - - qglVertex3f(0, vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale); - qglVertex3f(0, vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale); - - qglVertex3f(0, vMaxBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale); - qglVertex3f(0, vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale); - - - qglVertex3f(0, vMaxBounds[nDim1] + 6.0f / m_fScale, vMinBounds[nDim2]); - qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2]); - - qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2]); - qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2]); - - qglVertex3f(0, vMaxBounds[nDim1] + 6.0f / m_fScale, vMaxBounds[nDim2]); - qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2]); - - qglEnd(); - - qglRasterPos3f (0, Betwixt(vMinBounds[nDim1], vMaxBounds[nDim1]), vMinBounds[nDim2] - 20.0 / m_fScale); - g_strDim.Format(g_pDimStrings[nDim1], vSize[nDim1]); - gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); - - qglRasterPos3f (0, vMaxBounds[nDim1] + 16.0 / m_fScale, Betwixt(vMinBounds[nDim2], vMaxBounds[nDim2])); - g_strDim.Format(g_pDimStrings[nDim2], vSize[nDim2]); - gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); - - qglRasterPos3f (0, vMinBounds[nDim1] + 4.0, vMaxBounds[nDim2] + 8 / m_fScale); - g_strDim.Format(g_pOrgStrings[2], vMinBounds[nDim1], vMaxBounds[nDim2]); - gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); - } -} - -/* -============== -XY_Draw -============== -*/ -#define ALT_POINT_SIZE 4 -// Alternative to GL_POINTS (for; vertex handles, patch handles, clip points, path points) -void DrawAlternatePoint(vec3_t v, float scale) -{ - if(scale == 0) - { - scale = g_pParentWnd->GetXYWnd()->Scale(); - //scale = g_qeglobals.d_xyOld.scale; - } - - // ugly gl_line cross - qglVertex3f ( v[0]+(ALT_POINT_SIZE/scale), v[1], v[2] ); - qglVertex3f ( v[0]-(ALT_POINT_SIZE/scale), v[1], v[2] ); - qglVertex3f ( v[0], v[1]+(ALT_POINT_SIZE/scale), v[2] ); - qglVertex3f ( v[0], v[1]-(ALT_POINT_SIZE/scale), v[2] ); - qglVertex3f ( v[0], v[1], v[2]+(ALT_POINT_SIZE/scale) ); - qglVertex3f ( v[0], v[1], v[2]-(ALT_POINT_SIZE/scale) ); -} - - -long g_lCount = 0; -long g_lTotal = 0; -extern void DrawBrushEntityName (brush_t *b); - -//#define DBG_SCENEDUMP - -void XYWnd::XY_Draw() -{ -#ifdef DBG_SCENEDUMP - static time_t s_start = 0; // we use that to dump the selected stuff every 2 seconds - time_t now; - time (&now); - bool bDump; - - if ((now - s_start) > 3) - { - bDump = true; - s_start = now; - Sys_FPrintf(SYS_WRN, "Starting scene dump\n"); - } - else bDump = false; -#endif - - brush_t *brush; - float w, h; - entity_t *e; - double start, end; - double start2, end2; - vec3_t mins, maxs; - int drawn, culled; - int i; - - if (!active_brushes.next) - return; // not valid yet - - Patch_LODMatchAll(); // spog - - if (m_bTiming) - start = Sys_DoubleTime(); - // - // clear - // - m_bDirty = false; - - qglViewport(0, 0, m_nWidth, m_nHeight); - qglClearColor (g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][0], - g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][1], - g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][2],0); - - qglClear(GL_COLOR_BUFFER_BIT); - - // - // set up viewpoint - // - qglMatrixMode(GL_PROJECTION); - qglLoadIdentity (); - - w = m_nWidth / 2 / m_fScale; - h = m_nHeight / 2/ m_fScale; - - // fix GL_INVALID_VALUE error on first time the window is updated (win32) - if (w == 0) - w = 1; - - int nDim1 = (m_nViewType == YZ) ? 1 : 0; - int nDim2 = (m_nViewType == XY) ? 1 : 2; - mins[0] = m_vOrigin[nDim1] - w; - maxs[0] = m_vOrigin[nDim1] + w; - mins[1] = m_vOrigin[nDim2] - h; - maxs[1] = m_vOrigin[nDim2] + h; - - qglOrtho (mins[0], maxs[0], mins[1], maxs[1], g_MinWorldCoord, g_MaxWorldCoord); - - qglMatrixMode(GL_MODELVIEW); - qglLoadIdentity (); - - // - // now draw the grid - // - XY_DrawGrid (); - - // - // draw block grid - // - if ( g_qeglobals.show_blocks) - XY_DrawBlockGrid (); - - if (m_nViewType != XY) - { - qglPushMatrix(); - if (m_nViewType == YZ) - qglRotatef (-90, 0, 1, 0); // put Z going up - qglRotatef (-90, 1, 0, 0); // put Z going up - } - - // - // draw stuff - // - qglShadeModel (GL_FLAT); - qglDisable(GL_TEXTURE_2D); - qglDisable(GL_TEXTURE_1D); - qglDisable(GL_DEPTH_TEST); - qglDisable(GL_BLEND); - qglDisable(GL_CULL_FACE); - qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); - qglColor3f(0, 0, 0); - qglEnableClientState(GL_VERTEX_ARRAY); - - // Fishman - Add antialiazed points and lines support. 09/15/00 - if (g_PrefsDlg.m_bAntialiasedPointsAndLines) - { - qglEnable(GL_BLEND); - qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - qglEnable(GL_POINT_SMOOTH); - qglEnable(GL_LINE_SMOOTH); - } - - drawn = culled = 0; - - e = world_entity; - - if (m_bTiming) - start2 = Sys_DoubleTime(); - - for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next) - { - if (brush->bFiltered) - continue; - - if (brush->mins[nDim1] > maxs[0] || - brush->mins[nDim2] > maxs[1] || - brush->maxs[nDim1] < mins[0] || - brush->maxs[nDim2] < mins[1]) - { - culled++; - continue; // off screen - } - - drawn++; - - if (brush->owner != e && brush->owner) - { - qglColor3fv(brush->owner->eclass->color); - } - else - { - qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES]); - } - -#ifdef DBG_SCENEDUMP - if (bDump) - { - Sys_FPrintf(SYS_WRN, "Active brush: %p ", brush); - Sys_FPrintf(SYS_WRN, "owner->eclass: %s\n", brush->owner->eclass->name); - } -#endif - - Brush_DrawXY(brush, m_nViewType); - } - - if (m_bTiming) - end2 = Sys_DoubleTime(); - - DrawPathLines (); - - // - // draw pointfile - // - //++timo why is the display list broken? - if ( g_qeglobals.d_pointfile_display_list) - Pointfile_Draw(); - - // - // now draw selected brushes - // - - if (RotateMode()) - qglColor3f(0.8f, 0.1f, 0.9f); - else - if (ScaleMode()) - qglColor3f(0.1f, 0.8f, 0.1f); - else - qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES]); - - - if (g_PrefsDlg.m_bNoStipple == FALSE) - { - qglEnable (GL_LINE_STIPPLE); - qglLineStipple (3, 0xaaaa); - } - qglLineWidth (2); - - vec3_t vMinBounds; - vec3_t vMaxBounds; - vMinBounds[0] = vMinBounds[1] = vMinBounds[2] = g_MaxWorldCoord; - vMaxBounds[0] = vMaxBounds[1] = vMaxBounds[2] = g_MinWorldCoord; - - int nSaveDrawn = drawn; - bool bFixedSize = false; - for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next) - { - // spog - added culling of selected brushes in XY window - if (brush->mins[nDim1] > maxs[0] || - brush->mins[nDim2] > maxs[1] || - brush->maxs[nDim1] < mins[0] || - brush->maxs[nDim2] < mins[1]) - { - culled++; - continue; // off screen - } - drawn++; -#ifdef DBG_SCENEDUMP - if (bDump) - { - Sys_FPrintf(SYS_WRN, "Selected brush: %p ", brush); - Sys_FPrintf(SYS_WRN, "owner->eclass: %s\n", brush->owner->eclass->name); - } -#endif - Brush_DrawXY(brush, m_nViewType); - - if (!bFixedSize) - { - if (brush->owner->eclass->fixedsize) - bFixedSize = true; - if (g_PrefsDlg.m_bSizePaint) - { - for (i = 0; i < 3; i ++) - { - if (brush->mins[i] < vMinBounds[i]) - vMinBounds[i] = brush->mins[i]; - if (brush->maxs[i] > vMaxBounds[i]) - vMaxBounds[i] = brush->maxs[i]; - } - } - } - } - - if (g_PrefsDlg.m_bNoStipple == FALSE) - { - qglDisable (GL_LINE_STIPPLE); - } - qglLineWidth (1); - - if (!bFixedSize && !RotateMode() && !ScaleMode() && drawn - nSaveDrawn > 0 && g_PrefsDlg.m_bSizePaint) - PaintSizeInfo(nDim1, nDim2, vMinBounds, vMaxBounds); - - // edge / vertex flags - if (g_qeglobals.d_select_mode == sel_vertex) - { - if(!g_PrefsDlg.m_bGlPtWorkaround) - { - // brush verts - qglPointSize (4); - qglColor3f (0,1,0); - qglBegin (GL_POINTS); - for (i=0 ; iCurrentStyle() == MainFrame::eSplit) - qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME]); - else - qglColor3fv( g_qeglobals.d_savedinfo.AxisColors[m_nViewType]); - qglBegin (GL_LINE_LOOP); - qglVertex2i (0, 0); - qglVertex2i (m_nWidth-1, 0); - qglVertex2i (m_nWidth-1, m_nHeight-1); - qglVertex2i (0, m_nHeight-1); - qglEnd (); - - qglMatrixMode (GL_PROJECTION); - qglPopMatrix (); - qglMatrixMode (GL_MODELVIEW); - qglPopMatrix (); - } - } - - qglFinish(); - - if (m_bTiming) - { - end = Sys_DoubleTime (); - i = (int)(1000*(end-start)); - int i3 = (int)(1000*(end2-start2)); - g_lCount++; - g_lTotal += i; - int i2 = g_lTotal / g_lCount; - Sys_Printf ("xy: %i ab: %i avg: %i\n", i, i3, i2); - } - - // Fishman - Add antialiazed points and lines support. 09/03/00 - if (g_PrefsDlg.m_bAntialiasedPointsAndLines) - { - qglDisable(GL_POINT_SMOOTH); - qglDisable(GL_LINE_SMOOTH); - qglDisable(GL_BLEND); - } -} - -void XYWnd::Copy() -{ -} - -void XYWnd::Undo() -{ -} - -void XYWnd::UndoClear() -{ -} - -void XYWnd::UndoCopy() -{ -} - -bool XYWnd::UndoAvailable() -{ - return (g_brUndo.next != &g_brUndo); -} - -void XYWnd::Paste() -{ -} - -// should be static as should be the rotate scale stuff -bool XYWnd::AreaSelectOK() -{ - return RotateMode() ? false : ScaleMode() ? false : true; -} - -void XYWnd::OnCreate () -{ - if (!MakeCurrent ()) - Error ("glXMakeCurrent failed"); - - qglPolygonStipple ((unsigned char *)s_stipple); - qglLineStipple (3, 0xaaaa); -} - -void XYWnd::OnExpose () -{ - bool bPaint = true; - if (!MakeCurrent ()) - { - Sys_Printf("ERROR: glXMakeCurrent failed.. Error:%i\n",qglGetError()); - Sys_Printf("Please restart Radiant if the Map view is not working\n"); - bPaint = false; - } - if (bPaint) - { - QE_CheckOpenGLForErrors(); - XY_Draw (); - QE_CheckOpenGLForErrors(); - - if (m_nViewType != XY) - { - qglPushMatrix(); - if (m_nViewType == YZ) - qglRotatef (-90, 0, 1, 0); // put Z going up - qglRotatef (-90, 1, 0, 0); // put Z going up - } - - if (g_bCrossHairs) - { - qglColor4f(0.2f, 0.9f, 0.2f, 0.8f); - qglBegin (GL_LINES); - if (m_nViewType == XY) - { - qglVertex2f(2*g_MinWorldCoord, tdp[1]); - qglVertex2f(2*g_MaxWorldCoord, tdp[1]); - qglVertex2f(tdp[0], 2*g_MinWorldCoord); - qglVertex2f(tdp[0], 2*g_MaxWorldCoord); - } - else if (m_nViewType == YZ) - { - qglVertex3f(tdp[0], 2*g_MinWorldCoord, tdp[2]); - qglVertex3f(tdp[0], 2*g_MaxWorldCoord, tdp[2]); - qglVertex3f(tdp[0], tdp[1], 2*g_MinWorldCoord); - qglVertex3f(tdp[0], tdp[1], 2*g_MaxWorldCoord); - } - else - { - qglVertex3f (2*g_MinWorldCoord, tdp[1], tdp[2]); - qglVertex3f (2*g_MaxWorldCoord, tdp[1], tdp[2]); - qglVertex3f(tdp[0], tdp[1], 2*g_MinWorldCoord); - qglVertex3f(tdp[0], tdp[1], 2*g_MaxWorldCoord); - } - qglEnd(); - } - - if (ClipMode()) - { - // Draw clip points - if (g_Clip1.Set()) - g_Clip1.Draw(m_fScale, 1); // qglVertex3fv (g_Clip1); - if (g_Clip2.Set()) - g_Clip2.Draw(m_fScale, 2); // qglVertex3fv (g_Clip2); - if (g_Clip3.Set()) - g_Clip3.Draw(m_fScale, 3); // qglVertex3fv (g_Clip3); - if (g_Clip1.Set() && g_Clip2.Set()) - { - ProduceSplitLists(); - brush_t* pBrush; - brush_t* pList = (g_bSwitch) ? &g_brBackSplits : &g_brFrontSplits; - for (pBrush = pList->next ; pBrush != NULL && pBrush != pList ; pBrush=pBrush->next) - { - qglColor3f (1,1,0); - face_t *face; - int order; - for (face = pBrush->brush_faces,order = 0 ; face ; face=face->next, order++) - { - winding_t* w = face->face_winding; - if (!w) - continue; - // draw the polygon - qglBegin(GL_LINE_LOOP); - for (int i=0 ; inumpoints ; i++) - qglVertex3fv(w->points[i]); - qglEnd(); - } - } - } - } - - if (PathMode()) - { - int n; - for (n = 0; n < g_nPathCount; n++) - g_PathPoints[n].Draw(m_fScale, n+1); // qglVertex3fv(g_PathPoints[n]); - } - if (m_nViewType != XY) - qglPopMatrix(); - - m_XORRectangle.set(rectangle_t()); - SwapBuffers (); - } -} - -void XYWnd::KillPathMode() -{ - g_bSmartGo = false; - g_bPathMode = false; - if (g_pPathFunc) - g_pPathFunc(false, g_nPathCount); - g_nPathCount = 0; - g_pPathFunc = NULL; - Sys_UpdateWindows(W_ALL); -} - -// gets called for drop down menu messages -// TIP: it's not always about EntityCreate -void XYWnd::OnEntityCreate (const char* item) -{ - Undo_Start("create entity"); - Undo_AddBrushList(&selected_brushes); - - if (m_mnuDrop != NULL) - { - CString strItem; - strItem = item; - - if (strItem.CompareNoCase("Add to...") == 0) - { - //++timo TODO: fill the menu with current groups? - // this one is for adding to existing groups only - Sys_Printf("TODO: Add to... in XYWnd::OnEntityCreate\n"); - } - else if (strItem.CompareNoCase("Remove") == 0) - { - // remove selected brushes from their current group - brush_t *b; - for( b = selected_brushes.next; b != &selected_brushes; b = b->next ) - { - - } - } - - //++timo FIXME: remove when all hooks are in - if (strItem.CompareNoCase("Add to...") == 0 - || strItem.CompareNoCase("Remove") == 0 - || strItem.CompareNoCase("Name...") == 0 - || strItem.CompareNoCase("New group...") == 0) - { - Sys_Printf("TODO: hook drop down group menu\n"); - return; - } - - if (strItem.Find("Smart_") >= 0) - { - CreateSmartEntity(this, m_ptDownX, m_ptDownY, strItem); - } - else - { - CreateRightClickEntity(this, m_ptDownX, m_ptDownY, (char*)strItem.GetBuffer()); - } - - Sys_UpdateWindows(W_ALL); - //OnLButtonDown((MK_LBUTTON | MK_SHIFT), CPoint(m_ptDown.x+2, m_ptDown.y+2)); - } - Undo_EndBrushList(&selected_brushes); - Undo_End(); -} - -/* Drawing clip points */ -void ClipPoint::Draw(float fScale, int num) -{ - CString strLabel; - strLabel.Format("%d", num); - Draw(fScale, strLabel.GetBuffer()); -} - -#define ALT_POINT_VERTS 6 - -void ClipPoint::Draw(float fScale, const char *label) -{ - // draw point - if(!g_PrefsDlg.m_bGlPtWorkaround) - { - qglPointSize (4); - qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER]); - qglBegin (GL_POINTS); - qglVertex3fv (m_ptClip); - qglEnd(); - qglPointSize (1); - } - else - { - qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER]); - qglLineWidth(2.0); - qglBegin (GL_LINES); - DrawAlternatePoint(m_ptClip, fScale); - qglEnd(); - qglLineWidth(1.0); - } - - // draw label - qglRasterPos3f (m_ptClip[0]+2, m_ptClip[1]+2, m_ptClip[2]+2); - qglCallLists (strlen(label), GL_UNSIGNED_BYTE, label); -} - +/* +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 +*/ + +// +// XY Window +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" +#include +#include +#include + +#ifdef _WIN32 +#include +#endif + +// ============================================================================= +// variables + +#define PAGEFLIPS 2 + +CString g_strStatus; +bool g_bCrossHairs = false; +bool g_bScaleMode; +int g_nScaleHow; +bool g_bRotateMode; +bool g_bClipMode; +bool g_bRogueClipMode; +bool g_bSwitch; +ClipPoint g_Clip1; +ClipPoint g_Clip2; +ClipPoint g_Clip3; +ClipPoint* g_pMovingClip; +brush_t g_brFrontSplits; +brush_t g_brBackSplits; + +brush_t g_brClipboard; +brush_t g_brUndo; +entity_t g_enClipboard; + +vec3_t g_vRotateOrigin; +vec3_t g_vRotation; + +bool g_bPathMode; +ClipPoint g_PathPoints[256]; // this limit isn't enforced? +ClipPoint* g_pMovingPath; +int g_nPathCount; +int g_nPathLimit; + +bool g_bSmartGo; + +bool g_bPointMode; +ClipPoint g_PointPoints[512]; +ClipPoint* g_pMovingPoint; +int g_nPointCount; +int g_nPointLimit; + +const int XY_LEFT = 0x01; +const int XY_RIGHT = 0x02; +const int XY_UP = 0x04; +const int XY_DOWN = 0x08; + +PFNPathCallback* g_pPathFunc = NULL; + +static unsigned s_stipple[32] = +{ + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, +}; + +void AcquirePath(int nCount, PFNPathCallback* pFunc) +{ + g_nPathCount = 0; + g_nPathLimit = nCount; + g_pPathFunc = pFunc; + g_bPathMode = true; +} + + +CPtrArray g_ptrMenus; + +MemStream g_Clipboard(4096); +MemStream g_PatchClipboard(4096); + +extern int pressx; +extern int pressy; +extern bool g_bWaitCursor; + +vec3_t tdp; + +GtkWidget* XYWnd::m_mnuDrop = NULL; + +extern int g_nPatchClickedView; + +// ============================================================================= +// global functions + +// this is disabled, and broken +// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=394 +#if 0 +void WXY_Print () +{ + long width, height; + width = g_pParentWnd->ActiveXY()->Width(); + height = g_pParentWnd->ActiveXY()->Height(); + unsigned char* img; + const char* filename; + + filename = file_dialog (g_pParentWnd->m_pWidget, FALSE, "Save Image", NULL, FILTER_BMP); + if (!filename) + return; + + g_pParentWnd->ActiveXY()->MakeCurrent(); + img = (unsigned char*)malloc (width*height*3); + qglReadPixels (0,0,width,height,GL_RGB,GL_UNSIGNED_BYTE,img); + + FILE *fp; + fp = fopen(filename, "wb"); + if (fp) + { + unsigned short bits; + unsigned long cmap, bfSize; + + bits = 24; + cmap = 0; + bfSize = 54 + width*height*3; + + long byteswritten = 0; + long pixoff = 54 + cmap*4; + short res = 0; + char m1 ='B', m2 ='M'; + fwrite(&m1, 1, 1, fp); byteswritten++; // B + fwrite(&m2, 1, 1, fp); byteswritten++; // M + fwrite(&bfSize, 4, 1, fp); byteswritten+=4;// bfSize + fwrite(&res, 2, 1, fp); byteswritten+=2;// bfReserved1 + fwrite(&res, 2, 1, fp); byteswritten+=2;// bfReserved2 + fwrite(&pixoff, 4, 1, fp); byteswritten+=4;// bfOffBits + + unsigned long biSize = 40, compress = 0, size = 0; + long pixels = 0; + unsigned short planes = 1; + fwrite(&biSize, 4, 1, fp); byteswritten+=4;// biSize + fwrite(&width, 4, 1, fp); byteswritten+=4;// biWidth + fwrite(&height, 4, 1, fp); byteswritten+=4;// biHeight + fwrite(&planes, 2, 1, fp); byteswritten+=2;// biPlanes + fwrite(&bits, 2, 1, fp); byteswritten+=2;// biBitCount + fwrite(&compress, 4, 1, fp);byteswritten+=4;// biCompression + fwrite(&size, 4, 1, fp); byteswritten+=4;// biSizeImage + fwrite(&pixels, 4, 1, fp); byteswritten+=4;// biXPelsPerMeter + fwrite(&pixels, 4, 1, fp); byteswritten+=4;// biYPelsPerMeter + fwrite(&cmap, 4, 1, fp); byteswritten+=4;// biClrUsed + fwrite(&cmap, 4, 1, fp); byteswritten+=4;// biClrImportant + + unsigned long widthDW = (((width*24) + 31) / 32 * 4); + long row, row_size = width*3; + for (row = 0; row < height; row++) + { + unsigned char* buf = img+row*row_size; + + // write a row + int col; + for (col = 0; col < row_size; col += 3) + { + putc(buf[col+2], fp); + putc(buf[col+1], fp); + putc(buf[col], fp); + } + byteswritten += row_size; + + unsigned long count; + for (count = row_size; count < widthDW; count++) + { + putc(0, fp); // dummy + byteswritten++; + } + } + + fclose(fp); + } + + free (img); +} +#endif + +float ptSum(vec3_t pt) +{ + return pt[0] + pt[1] + pt[2]; +} + +float Betwixt(float f1, float f2) +{ + if (f1 > f2) + return f2 + ((f1 - f2) / 2); + else + return f1 + ((f2 - f1) / 2); +} + +void CleanList(brush_t* pList) +{ + brush_t* pBrush = pList->next; + while (pBrush != NULL && pBrush != pList) + { + brush_t* pNext = pBrush->next; + Brush_Free(pBrush); + pBrush = pNext; + } +} + +void Brush_CopyList (brush_t* pFrom, brush_t* pTo) +{ + brush_t* pBrush = pFrom->next; + while (pBrush != NULL && pBrush != pFrom) + { + brush_t* pNext = pBrush->next; + Brush_RemoveFromList(pBrush); + Brush_AddToList(pBrush, pTo); + pBrush = pNext; + } +} + +float fDiff(float f1, float f2) +{ + if (f1 > f2) + return f1 - f2; + else + return f2 - f1; +} + +/* +============================================================= + + PATH LINES + +============================================================= +*/ + +/* +================== +DrawPathLines + +Draws connections between entities. +Needs to consider all entities, not just ones on screen, +because the lines can be visible when neither end is. +Called for both camera view and xy view. +================== +*/ +void DrawPathLines (void) +{ + int i, j, k; + vec3_t mid, mid1; + entity_t *se, *te; + brush_t *sb, *tb; + const char *psz; + vec3_t dir, s1, s2; + vec_t len, f; + int arrows; + int num_entities; + const char *ent_target[MAX_MAP_ENTITIES]; + entity_t *ent_entity[MAX_MAP_ENTITIES]; + + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS) + { + return; + } + + num_entities = 0; + for (te = entities.next ; te != &entities && num_entities != MAX_MAP_ENTITIES ; te = te->next) + { + ent_target[num_entities] = ValueForKey (te, "target"); + if (ent_target[num_entities][0]) + { + ent_entity[num_entities] = te; + num_entities++; + } + } + + for (se = entities.next ; se != &entities ; se = se->next) + { + psz = ValueForKey(se, "targetname"); + + if (psz == NULL || psz[0] == '\0') + continue; + + sb = se->brushes.onext; + if (sb == &se->brushes) + continue; + + for (k=0 ; kbrushes.onext; + if (tb == &te->brushes) + continue; + + for (i=0 ; i<3 ; i++) + mid[i] = (sb->mins[i] + sb->maxs[i])*0.5; + + for (i=0 ; i<3 ; i++) + mid1[i] = (tb->mins[i] + tb->maxs[i])*0.5; + + VectorSubtract (mid1, mid, dir); + len = VectorNormalize (dir, dir); + s1[0] = -dir[1]*8 + dir[0]*8; + s2[0] = dir[1]*8 + dir[0]*8; + s1[1] = dir[0]*8 + dir[1]*8; + s2[1] = -dir[0]*8 + dir[1]*8; + + qglColor3f (se->eclass->color[0], se->eclass->color[1], se->eclass->color[2]); + + qglBegin(GL_LINES); + qglVertex3fv(mid); + qglVertex3fv(mid1); + + arrows = (int)(len / 256) + 1; + + for (i=0 ; im_pWidget, "Can't create an entity with worldspawn.", "info", 0); + return; + } + + e = Entity_Alloc(); + SetKeyValue(e, "classname", name); + + if(e->eclass->fixedsize) + { + Select_Delete(); + b = Brush_Create(e->eclass->mins, e->eclass->maxs, &e->eclass->texdef); + Entity_LinkBrush(e, b); + Brush_AddToList(b, &active_brushes); + Select_Brush(b); + Brush_Move(b, origin, true); + } + else + { + Select_GroupEntity(e); + if(e->brushes.onext == &e->brushes) + { + Sys_FPrintf(SYS_ERR, "CreateEntityFromName: selection could not be grouped\n"); + Entity_Free(e); + return; + } + } + + Entity_AddToList(e, &entities); + Undo_EndEntity(e); + + Select_Deselect (); + + // tweaking: when right clic dropping a light entity, ask for light value in a custom dialog box + // see SF bug 105383 + + if (g_pGameDescription->mGameFile == "hl.game") + { + // FIXME - Hydra: really we need a combined light AND color dialog for halflife. + if ((stricmp(name, "light") == 0) || + (stricmp(name, "light_environment") == 0) || + (stricmp(name, "light_spot") == 0) ) + { + int intensity = g_PrefsDlg.m_iLastLightIntensity; + + // Create and show the dialog box + // CWnd *pWnd; + // pWnd = prompt.GetDlgItem( IDC_EDIT1 ); + // prompt.GotoDlgCtrl( pWnd ); + if (DoLightIntensityDlg (&intensity) == IDOK) + { + g_PrefsDlg.m_iLastLightIntensity = intensity; + char buf[30]; + sprintf( buf, "255 255 255 %d", intensity ); + SetKeyValue(e, "_light", buf); + } + } + } + else + { + if (stricmp(name, "light") == 0) + { + int intensity = g_PrefsDlg.m_iLastLightIntensity; + + // Create and show the dialog box + // CWnd *pWnd; + // pWnd = prompt.GetDlgItem( IDC_EDIT1 ); + // prompt.GotoDlgCtrl( pWnd ); + if (DoLightIntensityDlg (&intensity) == IDOK) + { + g_PrefsDlg.m_iLastLightIntensity = intensity; + char buf[10]; + sprintf( buf, "%d", intensity ); + SetKeyValue(e, "light", buf); + } + } + } + Select_Brush (e->brushes.onext); + + if ( (stricmp(name, "misc_model") == 0) || (stricmp(name, "misc_gamemodel") == 0) || (strcmpi(name, "model_static") == 0) ) + { + SetInspectorMode(W_ENTITY); + AssignModel(); + } +} + +void CreateRightClickEntity(XYWnd* pWnd, int x, int y, char* pName) +{ + int height = pWnd->GetWidget()->allocation.height; + vec3_t point; + pWnd->SnapToPoint (x, height - 1 - y, point); + + int nDim = (pWnd->GetViewType() == XY) ? 2 : (pWnd->GetViewType() == YZ) ? 0 : 1; + float fWorkMid = (g_qeglobals.d_work_min[nDim] + g_qeglobals.d_work_max[nDim]) * 0.5; + point[nDim] = g_qeglobals.d_gridsize * ((int)(fWorkMid/g_qeglobals.d_gridsize)); + + CreateEntityFromName(pName, point); +} + + +brush_t* CreateSmartBrush(vec3_t v) +{ + vec3_t mins, maxs; + int i; + brush_t *n; + + for (i=0 ; i<3 ; i++) + { + mins[i] = v[i] - 16; + maxs[i] = v[i] + 16; + } + + n = Brush_Create (mins, maxs, &g_qeglobals.d_texturewin.texdef); + if (!n) + return NULL; + + Brush_AddToList(n, &selected_brushes); + //Entity_LinkBrush(world_entity, n); + Brush_Build(n); + return n; +} + +CString g_strSmartEntity; +int g_nSmartX; +int g_nSmartY; +bool g_bSmartWaiting; +void _SmartPointDone(bool b, int n) +{ + g_bSmartWaiting = false; +} + +void CreateSmartEntity(XYWnd* pWnd, int x, int y, const char* pName) +{ + g_nSmartX = x; + g_nSmartY = y; + g_strSmartEntity = pName; + if (g_strSmartEntity.Find("Smart_Train") >= 0) + { + ShowInfoDialog("Select the path of the train by left clicking in XY, YZ and/or XZ views. You can move an already dropped point by grabbing and moving it. When you are finished, press ENTER to accept and create the entity and path(s), press ESC to abandon the creation"); + g_bPathMode = true; + g_nPathLimit = 0; + g_nPathCount = 0; + g_bSmartGo = true; + } + else + if (g_strSmartEntity.Find("Smart_Monster...") >= 0) + { + g_bPathMode = true; + g_nPathLimit = 0; + g_nPathCount = 0; + } + else + if (g_strSmartEntity.Find("Smart_Rotating") >= 0) + { + g_bSmartWaiting = true; + ShowInfoDialog("Left click to specify the rotation origin"); + AcquirePath(1, &_SmartPointDone); + while (g_bSmartWaiting) + gtk_main_iteration (); + HideInfoDialog(); + CPtrArray array; + g_bScreenUpdates = false; + CreateRightClickEntity(g_pParentWnd->ActiveXY(), g_nSmartX, g_nSmartY, "func_rotating"); + array.Add(reinterpret_cast(selected_brushes.next)); + Select_Deselect(); + brush_t* pBrush = CreateSmartBrush(g_PathPoints[0]); + array.Add(pBrush); + Select_Deselect(); + Select_Brush(reinterpret_cast(array.GetAt(0))); + Select_Brush(reinterpret_cast(array.GetAt(1))); + ConnectEntities(); + g_bScreenUpdates = true; + } +} + +void FinishSmartCreation() +{ + CPtrArray array; + HideInfoDialog(); + // brush_t* pEntities = NULL; + int n; + + if (g_strSmartEntity.Find("Smart_Train") >= 0) + { + g_bScreenUpdates = false; + CreateRightClickEntity(g_pParentWnd->ActiveXY(), g_nSmartX, g_nSmartY, "func_train"); + array.Add(reinterpret_cast(selected_brushes.next)); + for (n = 0; n < g_nPathCount; n++) + { + Select_Deselect(); + CreateRightClickEntity(g_pParentWnd->ActiveXY(), g_PathPoints[n].m_ptScreenX, + g_PathPoints[n].m_ptScreenY, "path_corner"); + array.Add(reinterpret_cast(selected_brushes.next)); + } + + for (n = 0; n < g_nPathCount; n++) + { + Select_Deselect(); + Select_Brush(reinterpret_cast(array.GetAt(n))); + Select_Brush(reinterpret_cast(array.GetAt(n+1))); + ConnectEntities(); + } + g_bScreenUpdates = true; + + } + g_nPathCount = 0; + g_bPathMode = false; + Sys_UpdateWindows(W_ALL); +} + +void CleanCopyEntities() +{ + entity_t* pe = g_enClipboard.next; + while (pe != NULL && pe != &g_enClipboard) + { + entity_t* next = pe->next; + epair_t* enext = NULL; + for (epair_t* ep = pe->epairs ; ep ; ep=enext) + { + enext = ep->next; + free (ep->key); + free (ep->value); + free (ep); + } + free (pe); + pe = next; + } + g_enClipboard.next = g_enClipboard.prev = &g_enClipboard; +} + +entity_t *Entity_CopyClone (entity_t *e) +{ + entity_t *n; + epair_t *ep, *np; + + n = (entity_t*)qmalloc(sizeof(*n)); + n->brushes.onext = n->brushes.oprev = &n->brushes; + n->eclass = e->eclass; + + // add the entity to the entity list + n->next = g_enClipboard.next; + g_enClipboard.next = n; + n->next->prev = n; + n->prev = &g_enClipboard; + + for (ep = e->epairs ; ep ; ep=ep->next) + { + np = (epair_t*)qmalloc(sizeof(*np)); + np->key = copystring(ep->key); + np->value = copystring(ep->value); + np->next = n->epairs; + n->epairs = np; + } + return n; +} + +bool OnList(entity_t* pFind, CPtrArray* pList) +{ + int nSize = pList->GetSize(); + while (nSize-- > 0) + { + entity_t* pEntity = reinterpret_cast(pList->GetAt(nSize)); + if (pEntity == pFind) + return true; + } + return false; +} + +// ============================================================================= +// XYWnd class + +XYWnd::XYWnd () + : GLWindow (FALSE), m_XORRectangle(m_pWidget) +{ + g_brClipboard.next = &g_brClipboard; + g_brUndo.next = &g_brUndo; + g_nScaleHow = 0; + g_bRotateMode = false; + g_bClipMode = false; + g_bRogueClipMode = false; + g_bSwitch = true; + g_pMovingClip = (ClipPoint*)NULL; + g_pMovingPath = (ClipPoint*)NULL; + g_brFrontSplits.next = &g_brFrontSplits; + g_brBackSplits.next = &g_brBackSplits; + m_bActive = false; + //m_bTiming = true; + m_bTiming = false; + m_bRButtonDown = false; + m_nUpdateBits = W_XY; + g_bPathMode = false; + g_nPathCount = 0; + g_nPathLimit = 0; + m_nButtonstate = 0; +// m_mnuDrop = (GtkWidget*)NULL; + XY_Init(); +} + +vec3_t& XYWnd::Rotation() +{ + return g_vRotation; +} + +vec3_t& XYWnd::RotateOrigin() +{ + return g_vRotateOrigin; +} + +/* +============== +XY_Overlay +============== +*/ +void XYWnd::XY_Overlay() +{ + int w, h; + int r[4]; + static vec3_t lastz; + static vec3_t lastcamera; + + qglViewport(0, 0, m_nWidth, m_nHeight); + + // + // set up viewpoint + // + qglMatrixMode(GL_PROJECTION); + qglLoadIdentity (); + + w = (int)(m_nWidth / 2 / m_fScale); + h = (int)(m_nHeight / 2 / m_fScale); + + qglOrtho (m_vOrigin[0] - w, m_vOrigin[0] + w , m_vOrigin[1] - h, m_vOrigin[1] + h, g_MinWorldCoord, g_MaxWorldCoord); + // + // erase the old camera and z checker positions + // if the entire xy hasn't been redrawn + // + if (m_bDirty) + { + qglReadBuffer (GL_BACK); + qglDrawBuffer (GL_FRONT); + + qglRasterPos2f (lastz[0]-9, lastz[1]-9); + qglGetIntegerv (GL_CURRENT_RASTER_POSITION,r); + qglCopyPixels(r[0], r[1], 18,18, GL_COLOR); + + qglRasterPos2f (lastcamera[0]-50, lastcamera[1]-50); + qglGetIntegerv (GL_CURRENT_RASTER_POSITION,r); + qglCopyPixels(r[0], r[1], 100,100, GL_COLOR); + } + m_bDirty = true; + + // + // save off underneath where we are about to draw + // + VectorCopy (z.origin, lastz); + VectorCopy (g_pParentWnd->GetCamWnd()->Camera()->origin, lastcamera); + + qglReadBuffer (GL_FRONT); + qglDrawBuffer (GL_BACK); + + qglRasterPos2f (lastz[0]-9, lastz[1]-9); + qglGetIntegerv (GL_CURRENT_RASTER_POSITION,r); + qglCopyPixels(r[0], r[1], 18,18, GL_COLOR); + + qglRasterPos2f (lastcamera[0]-50, lastcamera[1]-50); + qglGetIntegerv (GL_CURRENT_RASTER_POSITION,r); + qglCopyPixels(r[0], r[1], 100,100, GL_COLOR); + + // + // draw the new icons + // + qglDrawBuffer (GL_FRONT); + + qglShadeModel (GL_FLAT); + qglDisable(GL_TEXTURE_2D); + qglDisable(GL_TEXTURE_1D); + qglDisable(GL_DEPTH_TEST); + qglDisable(GL_BLEND); + qglColor3f(0, 0, 0); + + DrawCameraIcon (); + DrawZIcon (); + + qglDrawBuffer (GL_BACK); + qglFinish(); +} + +vec3_t& XYWnd::GetOrigin() +{ + return m_vOrigin; +} + +void XYWnd::SetOrigin(vec3_t org) +{ + m_vOrigin[0] = org[0]; + m_vOrigin[1] = org[1]; + m_vOrigin[2] = org[2]; +} + +void XYWnd::OnSize(int cx, int cy) +{ + m_nWidth = cx; + m_nHeight = cy; +} + +brush_t hold_brushes; + +void XYWnd::Clip() +{ + if (ClipMode()) + { + hold_brushes.next = &hold_brushes; + ProduceSplitLists(); + brush_t* pList; + if (g_PrefsDlg.m_bSwitchClip) + pList = (!g_bSwitch) ? &g_brFrontSplits : &g_brBackSplits; + else + pList = (g_bSwitch) ? &g_brFrontSplits : &g_brBackSplits; + + if (pList->next != pList) + { + Brush_CopyList(pList, &hold_brushes); + CleanList(&g_brFrontSplits); + CleanList(&g_brBackSplits); + Select_Delete(); + Brush_CopyList(&hold_brushes, &selected_brushes); + if (RogueClipMode()) + RetainClipMode(false); + else + RetainClipMode(true); + Sys_UpdateWindows(W_ALL); + } + } + else if (PathMode()) + { + FinishSmartCreation(); + if (g_pPathFunc) + g_pPathFunc(true, g_nPathCount); + g_pPathFunc = NULL; + g_nPathCount = 0; + g_bPathMode = false; + } +} + +void XYWnd::SplitClip() +{ + ProduceSplitLists(); + if ((g_brFrontSplits.next != &g_brFrontSplits) && + (g_brBackSplits.next != &g_brBackSplits)) + { + Select_Delete(); + Brush_CopyList(&g_brFrontSplits, &selected_brushes); + Brush_CopyList(&g_brBackSplits, &selected_brushes); + CleanList(&g_brFrontSplits); + CleanList(&g_brBackSplits); + if (RogueClipMode()) + RetainClipMode(false); + else + RetainClipMode(true); + } +} + +void XYWnd::FlipClip() +{ + g_bSwitch = !g_bSwitch; + Sys_UpdateWindows(XY | W_CAMERA_IFON); +} + +// makes sure the selected brush or camera is in view +void XYWnd::PositionView() +{ + int nDim1 = (m_nViewType == YZ) ? 1 : 0; + int nDim2 = (m_nViewType == XY) ? 1 : 2; + brush_t* b = selected_brushes.next; + if (b && b->next != b) + { + Select_GetMid (m_vOrigin); + } + else + { + m_vOrigin[nDim1] = g_pParentWnd->GetCamWnd()->Camera()->origin[nDim1]; + m_vOrigin[nDim2] = g_pParentWnd->GetCamWnd()->Camera()->origin[nDim2]; + } +} + +void XYWnd::VectorCopyXY(vec3_t in, vec3_t out) +{ + if (m_nViewType == XY) + { + out[0] = in[0]; + out[1] = in[1]; + } + else if (m_nViewType == XZ) + { + out[0] = in[0]; + out[2] = in[2]; + } + else + { + out[1] = in[1]; + out[2] = in[2]; + } +} + +void XYWnd::RetainClipMode(bool bMode) +{ + bool bSave = g_bRogueClipMode; + SetClipMode(bMode); + if (bMode == true) + g_bRogueClipMode = bSave; + else + g_bRogueClipMode = false; +} + +void XYWnd::SetClipMode(bool bMode) +{ + g_bClipMode = bMode; + g_bRogueClipMode = false; + if (bMode) + { + g_Clip1.Reset(); + g_Clip2.Reset(); + g_Clip3.Reset(); + CleanList(&g_brFrontSplits); + CleanList(&g_brBackSplits); + g_brFrontSplits.next = &g_brFrontSplits; + g_brBackSplits.next = &g_brBackSplits; + + // ydnar: set clipper points based on first selected patch mesh + if( selected_brushes.next != &selected_brushes ) + { + bool found = false; + for( brush_t *pb = selected_brushes.next; pb != &selected_brushes; pb = pb->next ) + { + if( pb->patchBrush ) + { + found = true; + VectorCopy( pb->pPatch->ctrl[ 0 ][ 0 ].xyz, g_Clip1.m_ptClip ); + VectorCopy( pb->pPatch->ctrl[ pb->pPatch->width - 1 ][ pb->pPatch->height - 1 ].xyz, g_Clip2.m_ptClip ); + VectorCopy( pb->pPatch->ctrl[ pb->pPatch->width - 1 ][ 0 ].xyz, g_Clip3.m_ptClip ); + g_Clip1.Set( true ); + g_Clip2.Set( true ); + g_Clip3.Set( true ); + break; + } + } + + if( found ) + { + // SetClipMode( true ); + Sys_UpdateWindows( XY | W_CAMERA_IFON ); + } + } + } + else + { + if (g_pMovingClip) + { + ReleaseCapture(); + g_pMovingClip = NULL; + } + CleanList(&g_brFrontSplits); + CleanList(&g_brBackSplits); + g_brFrontSplits.next = &g_brFrontSplits; + g_brBackSplits.next = &g_brBackSplits; + Sys_UpdateWindows(XY | W_CAMERA_IFON); + } +} + +bool XYWnd::ClipMode() +{ + return g_bClipMode; +} + +bool XYWnd::RogueClipMode() +{ + return g_bRogueClipMode; +} + +bool XYWnd::PathMode() +{ + return g_bPathMode; +} + +bool XYWnd::PointMode() +{ + return g_bPointMode; +} + +void XYWnd::SetPointMode(bool b) +{ + g_bPointMode = b; + if (!b) + g_nPointCount = 0; +} + +void XYWnd::SetViewType(int n) +{ + m_nViewType = n; + if (g_pParentWnd->CurrentStyle() == MainFrame::eFloating) + { + char* str = "YZ Side"; + if (m_nViewType == XY) + str = "XY Top"; + else if (m_nViewType == XZ) + str = "XZ Front"; + + if (m_pParent != NULL) + gtk_window_set_title (GTK_WINDOW (m_pParent), str); + } +} + +void XYWnd::Redraw(unsigned int nBits) +{ + m_nUpdateBits = nBits; + gtk_widget_queue_draw(m_pWidget); + m_nUpdateBits = W_XY; +} + +bool XYWnd::RotateMode() +{ + return g_bRotateMode; +} + +bool XYWnd::ScaleMode() +{ + return g_bScaleMode; +} + +bool XYWnd::SetRotateMode(bool bMode) +{ + if (bMode && selected_brushes.next != &selected_brushes) + { + g_bRotateMode = true; + Select_GetTrueMid(g_vRotateOrigin); + g_vRotation[0] = g_vRotation[1] = g_vRotation[2] = 0.0; + } + else + { + if (bMode) + Sys_Printf("Need a brush selected to turn on Mouse Rotation mode\n"); + g_bRotateMode = false; + } + RedrawWindow(); + return g_bRotateMode; +} + +void XYWnd::SetScaleMode(bool bMode) +{ + g_bScaleMode = bMode; + RedrawWindow(); +} + +rectangle_t rectangle_from_area_xy() +{ + XYWnd* xy = g_pParentWnd->ActiveXY(); + int nDim1 = (xy->GetViewType() == YZ) ? 1 : 0; + int nDim2 = (xy->GetViewType() == XY) ? 1 : 2; + float origin_left = xy->GetOrigin()[nDim1] - (xy->Width() / 2) / xy->Scale(); + float origin_bottom = xy->GetOrigin()[nDim2] - (xy->Height() / 2) / xy->Scale(); + float left = MIN(g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1]) - origin_left; + float top = MAX(g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2]) - origin_bottom; + float right = MAX(g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1]) - origin_left; + float bottom = MIN(g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2]) - origin_bottom; + left *= xy->Scale(); + top *= xy->Scale(); + right *= xy->Scale(); + bottom *= xy->Scale(); + return rectangle_t(left, bottom, right - left, top - bottom); +} + +void update_xor_rectangle_xy(XORRectangle& xor_rectangle) +{ + rectangle_t rectangle; + if ((g_qeglobals.d_select_mode == sel_area)) + rectangle = rectangle_from_area_xy(); + xor_rectangle.set(rectangle); +} + +void XYWnd::OnMouseMove(guint32 nFlags, int pointx, int pointy) +{ + // plugin entities + // TODO TTimo handle return code + DispatchOnMouseMove (nFlags, pointx, pointy); + + m_ptDownX = 0; + m_ptDownY = 0; + + if (g_PrefsDlg.m_bChaseMouse == TRUE && + (pointx < 0 || pointy < 0 || pointx > m_nWidth || pointy > m_nHeight) && + HasCapture ()) + { + float fAdjustment = (g_qeglobals.d_gridsize / 8 * 64) / m_fScale; + //m_ptDrag = point; + m_ptDragAdjX = 0; + m_ptDragAdjY = 0; + + if (pointx < 0) + { + m_ptDragAdjX = (int)(-fAdjustment); + } + else if (pointx > m_nWidth) + { + m_ptDragAdjX = (int)(fAdjustment); + } + + if (pointy < 0) + { + m_ptDragAdjY = (int)(-fAdjustment); + } + else if (pointy > m_nHeight) + { + m_ptDragAdjY = (int)(fAdjustment); + } + + if (!HasTimer ()) + { + SetTimer (50); + m_ptDragX = pointx; + m_ptDragY = pointy; + m_ptDragTotalX = 0; + m_ptDragTotalY = 0; + } + return; + } + + if (HasTimer ()) + { + KillTimer (); + pressx -= m_ptDragTotalX; + pressy += m_ptDragTotalY; + } + + bool bCrossHair = false; + if (!m_bRButtonDown) + { + tdp[0] = tdp[1] = tdp[2] = 0.0; + SnapToPoint (pointx, m_nHeight - 1 - pointy , tdp); + + g_strStatus.Format("x:: %.1f y:: %.1f z:: %.1f", tdp[0], tdp[1], tdp[2]); + g_pParentWnd->SetStatusText(1, g_strStatus); + + // i need to generalize the point code.. having 3 flavors pretty much sucks.. + // once the new curve stuff looks like it is going to stick i will + // rationalize this down to a single interface.. + if (PointMode()) + { + if (g_pMovingPoint && HasCapture ()) + { + bCrossHair = true; + SnapToPoint (pointx, m_nHeight - 1 - pointy , g_pMovingPoint->m_ptClip); + g_pMovingPoint->UpdatePointPtr(); + Sys_UpdateWindows(XY | W_CAMERA_IFON); + } + else + { + g_pMovingPoint = NULL; + int nDim1 = (m_nViewType == YZ) ? 1 : 0; + int nDim2 = (m_nViewType == XY) ? 1 : 2; + for (int n = 0; n < g_nPointCount; n++) + { + if ( fDiff(g_PointPoints[n].m_ptClip[nDim1], tdp[nDim1]) < 3 && + fDiff(g_PointPoints[n].m_ptClip[nDim2], tdp[nDim2]) < 3 ) + { + bCrossHair = true; + g_pMovingPoint = &g_PointPoints[n]; + } + } + } + } + else if (ClipMode()) + { + if (g_pMovingClip && HasCapture ()) + { + bCrossHair = true; + SnapToPoint (pointx, m_nHeight - 1 - pointy , g_pMovingClip->m_ptClip); + Sys_UpdateWindows(XY | W_CAMERA_IFON); + } + else + { + g_pMovingClip = NULL; + int nDim1 = (m_nViewType == YZ) ? 1 : 0; + int nDim2 = (m_nViewType == XY) ? 1 : 2; + if (g_Clip1.Set()) + { + if ( fDiff(g_Clip1.m_ptClip[nDim1], tdp[nDim1]) < 3 && + fDiff(g_Clip1.m_ptClip[nDim2], tdp[nDim2]) < 3 ) + { + bCrossHair = true; + g_pMovingClip = &g_Clip1; + } + } + if (g_Clip2.Set()) + { + if ( fDiff(g_Clip2.m_ptClip[nDim1], tdp[nDim1]) < 3 && + fDiff(g_Clip2.m_ptClip[nDim2], tdp[nDim2]) < 3 ) + { + bCrossHair = true; + g_pMovingClip = &g_Clip2; + } + } + if (g_Clip3.Set()) + { + if ( fDiff(g_Clip3.m_ptClip[nDim1], tdp[nDim1]) < 3 && + fDiff(g_Clip3.m_ptClip[nDim2], tdp[nDim2]) < 3 ) + { + bCrossHair = true; + g_pMovingClip = &g_Clip3; + } + } + } + if (bCrossHair == false) + XY_MouseMoved (pointx, m_nHeight - 1 - pointy , nFlags); + } + else if (PathMode()) + { + if (g_pMovingPath && HasCapture ()) + { + bCrossHair = true; + SnapToPoint (pointx, m_nHeight - 1 - pointy , g_pMovingPath->m_ptClip); + Sys_UpdateWindows(XY | W_CAMERA_IFON); + } + else + { + g_pMovingPath = NULL; + int nDim1 = (m_nViewType == YZ) ? 1 : 0; + int nDim2 = (m_nViewType == XY) ? 1 : 2; + for (int n = 0; n < g_nPathCount; n++) + { + if ( fDiff(g_PathPoints[n].m_ptClip[nDim1], tdp[nDim1]) < 3 && + fDiff(g_PathPoints[n].m_ptClip[nDim2], tdp[nDim2]) < 3 ) + { + bCrossHair = true; + g_pMovingPath = &g_PathPoints[n]; + } + } + } + } + else + { + XY_MouseMoved (pointx, m_nHeight - 1 - pointy , nFlags); + } + } + else + { + XY_MouseMoved (pointx, m_nHeight - 1 - pointy , nFlags); + } + + if ((nFlags & MK_RBUTTON) == 0) + { + if (bCrossHair && !g_bWaitCursor) + { + GdkCursor *cursor; + cursor = gdk_cursor_new (GDK_CROSSHAIR); + gdk_window_set_cursor (m_pWidget->window, cursor); + gdk_cursor_unref (cursor); + } + else + { + gdk_window_set_cursor (m_pWidget->window, NULL); + } + } + + update_xor_rectangle_xy(m_XORRectangle); +} + +void XYWnd::OnMouseWheel(bool bUp) +{ + if (bUp) + g_pParentWnd->OnViewZoomin (); + else + g_pParentWnd->OnViewZoomout (); + + int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA); + Sys_UpdateWindows (nUpdate); + g_pParentWnd->OnTimer (); +} + +void XYWnd::OnTimer () +{ + int nDim1 = (m_nViewType == YZ) ? 1 : 0; + int nDim2 = (m_nViewType == XY) ? 1 : 2; + m_vOrigin[nDim1] += m_ptDragAdjX / m_fScale; + m_vOrigin[nDim2] -= m_ptDragAdjY / m_fScale; + Sys_UpdateWindows(W_XY | W_CAMERA); + m_ptDragX += m_ptDragAdjX; + m_ptDragY += m_ptDragAdjY; + m_ptDragTotalX += m_ptDragAdjX; + m_ptDragTotalY += m_ptDragAdjY; + XY_MouseMoved (m_ptDragX, m_nHeight - 1 - m_ptDragY , m_nScrollFlags); +} + +void XYWnd::OnLButtonDown(guint32 flags, int pointx, int pointy) +{ + g_pParentWnd->SetActiveXY(this); + UndoCopy(); + + // plugin entities + if (DispatchOnLButtonDown(flags, pointx, pointy)) + return; + + if (ClipMode() && !RogueClipMode()) + { + DropClipPoint(flags, pointx, pointy); + } + else if (PathMode()) + { + DropPathPoint(flags, pointx, pointy); + } + else OriginalButtonDown(flags, pointx, pointy); +} + +void XYWnd::OnMButtonDown(guint32 flags, int pointx, int pointy) +{ + OriginalButtonDown(flags, pointx, pointy); +} + +void XYWnd::OnRButtonDown(guint32 flags, int pointx, int pointy) +{ + g_pParentWnd->SetActiveXY(this); + m_ptDownX = pointx; + m_ptDownY = pointy; + m_bRButtonDown = true; + + if (g_PrefsDlg.m_nMouseButtons == 3) // 3 button mouse + { + if (flags & MK_CONTROL) + { + if (ClipMode()) // already there? + DropClipPoint(flags, pointx, pointy); + else + { + SetClipMode(true); + g_bRogueClipMode = true; + DropClipPoint(flags, pointx, pointy); + } + return; + } + } + OriginalButtonDown(flags, pointx, pointy); +} + +void XYWnd::OnLButtonUp(guint32 flags, int pointx, int pointy) +{ + // plugin entities + if (DispatchOnLButtonUp(flags, pointx, pointy)) + return; + + if (ClipMode()) + { + if (g_pMovingClip) + { + ReleaseCapture(); + g_pMovingClip = NULL; + } + } + OriginalButtonUp(flags, pointx, pointy); +} + +void XYWnd::OnMButtonUp(guint32 flags, int pointx, int pointy) +{ + OriginalButtonUp(flags, pointx, pointy); +} + +void XYWnd::OnRButtonUp(guint32 flags, int pointx, int pointy) +{ + m_bRButtonDown = false; + if ((pointx == m_ptDownX) && (pointy == m_ptDownY)) // mouse didn't move + { + bool bGo = true; + if (Sys_AltDown ()) + bGo = false; + if (flags & MK_CONTROL) + bGo = false; + if (flags & MK_SHIFT) + bGo = false; + if (bGo) + HandleDrop(); + } + OriginalButtonUp(flags, pointx, pointy); +} + +void XYWnd::XY_MouseDown (int x, int y, int buttons) +{ + vec3_t point; + vec3_t origin, dir, right, up; + + m_nButtonstate = buttons; + m_nPressx = x; + m_nPressy = y; + VectorCopy (vec3_origin, m_vPressdelta); + + VectorClear(point); + XY_ToPoint (x, y, point); + + VectorCopy (point, origin); + + VectorClear (dir); + if (m_nViewType == XY) // view facing dir = negative Z + { + origin[2] = g_MaxWorldCoord; + dir[2] = -1; + right[0] = 1 / m_fScale; + right[1] = 0; + right[2] = 0; + up[0] = 0; + up[1] = 1 / m_fScale; + up[2] = 0; + } + else if (m_nViewType == XZ) + { + origin[1] = g_MinWorldCoord; // view facing dir = positive Y + dir[1] = 1; + right[0] = 1 / m_fScale; + right[1] = 0; + right[2] = 0; + up[0] = 0; + up[1] = 0; + up[2] = 1 / m_fScale; + } + else // if (m_nViewType == YZ) // view facing dir = negative X + { + origin[0] = g_MaxWorldCoord; + dir[0] = -1; + right[0] = 0; + right[1] = 1 / m_fScale; + right[2] = 0; + up[0] = 0; + up[1] = 0; + up[2] = 1 / m_fScale; + } + + m_bPress_selection = (selected_brushes.next != &selected_brushes); + + Sys_GetCursorPos(&m_ptCursorX, &m_ptCursorY); + + // lbutton = manipulate selection + // shift-LBUTTON = select + if ( (buttons == MK_LBUTTON) + || (buttons == (MK_LBUTTON | MK_SHIFT)) + || (buttons == (MK_LBUTTON | MK_CONTROL)) + || (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) ) + { + Patch_SetView( (m_nViewType == XY) ? W_XY : (m_nViewType == YZ) ? W_YZ : W_XZ); + Drag_Begin (x, y, buttons, right, up, origin, dir); + return; + } + + int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON; + + // control mbutton = move camera + if (m_nButtonstate == (MK_CONTROL|nMouseButton) ) + { + VectorCopyXY(point, g_pParentWnd->GetCamWnd()->Camera()->origin); + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + } + + // mbutton = angle camera + if ((g_PrefsDlg.m_nMouseButtons == 3 && m_nButtonstate == MK_MBUTTON) || + (g_PrefsDlg.m_nMouseButtons == 2 && m_nButtonstate == (MK_SHIFT|MK_CONTROL|MK_RBUTTON))) + { + VectorSubtract (point, g_pParentWnd->GetCamWnd()->Camera()->origin, point); + + int n1 = (m_nViewType == XY) ? 1 : 2; + int n2 = (m_nViewType == YZ) ? 1 : 0; + int nAngle = (m_nViewType == XY) ? YAW : PITCH; + if (point[n1] || point[n2]) + { + g_pParentWnd->GetCamWnd()->Camera()->angles[nAngle] = 180/Q_PI*atan2 (point[n1], point[n2]); + Sys_UpdateWindows (W_CAMERA_IFON|W_XY_OVERLAY); + } + } + + // shift mbutton = move z checker + if (m_nButtonstate == (MK_SHIFT | nMouseButton)) + { + if (RotateMode() || g_bPatchBendMode) + { + SnapToPoint (x, y, point); + VectorCopyXY(point, g_vRotateOrigin); + if (g_bPatchBendMode) + { + VectorCopy(point, g_vBendOrigin); + } + Sys_UpdateWindows (W_XY); + return; + } + else + { + SnapToPoint (x, y, point); + if (m_nViewType == XY) + { + z.origin[0] = point[0]; + z.origin[1] = point[1]; + } + else if (m_nViewType == YZ) + { + z.origin[0] = point[1]; + z.origin[1] = point[2]; + } + else + { + z.origin[0] = point[0]; + z.origin[1] = point[2]; + } + Sys_UpdateWindows (W_XY_OVERLAY|W_Z); + return; + } + } + + update_xor_rectangle_xy(m_XORRectangle); +} + +void XYWnd::XY_MouseUp(int x, int y, int buttons) +{ + Drag_MouseUp (buttons); + if (!m_bPress_selection) + Sys_UpdateWindows (W_ALL); + m_nButtonstate = 0; + + gdk_window_set_cursor (m_pWidget->window, NULL); + + update_xor_rectangle_xy(m_XORRectangle); +} + +qboolean XYWnd::DragDelta (int x, int y, vec3_t move) +{ + vec3_t xvec, yvec, delta; + int i; + + xvec[0] = 1 / m_fScale; + xvec[1] = xvec[2] = 0; + yvec[1] = 1 / m_fScale; + yvec[0] = yvec[2] = 0; + + for (i=0 ; i<3 ; i++) + { + delta[i] = xvec[i] * (x - m_nPressx) + yvec[i] * (y - m_nPressy); + if (!g_PrefsDlg.m_bNoClamp) + { + delta[i] = floor(delta[i] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + } + } + VectorSubtract (delta, m_vPressdelta, move); + VectorCopy (delta, m_vPressdelta); + + if (move[0] || move[1] || move[2]) + return true; + return false; +} + +void XYWnd::HandleDrop() +{ + if (g_PrefsDlg.m_bRightClick == false) + return; + + if (m_mnuDrop == NULL) // first time, load it up + { + int nID = ID_ENTITY_START; + GtkWidget *menu, *menu_in_menu, *item, *submenu, *submenu_root; + + menu = m_mnuDrop = gtk_menu_new (); + + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Select"); + create_menu_item_with_mnemonic (menu_in_menu, "Select Complete Tall", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTCOMPLETETALL); + create_menu_item_with_mnemonic (menu_in_menu, "Select Touching", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTTOUCHING); + create_menu_item_with_mnemonic (menu_in_menu, "Select Partial Tall", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTPARTIALTALL); + create_menu_item_with_mnemonic (menu_in_menu, "Select Inside", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTINSIDE); + menu_separator (menu); nID++; + // NOTE: temporary commented out until we put it back in for good (that is with actual features) + /* + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Group",); + create_menu_item_with_mnemonic (menu_in_menu, "Add to...", + GTK_SIGNAL_FUNC (HandleCommand), ID_DROP_GROUP_ADDTO); + create_menu_item_with_mnemonic (menu_in_menu, "Remove", + GTK_SIGNAL_FUNC (HandleCommand), ID_DROP_GROUP_REMOVE); + create_menu_item_with_mnemonic (menu_in_menu, "Name...", + GTK_SIGNAL_FUNC (HandleCommand), ID_DROP_GROUP_NAME); + menu_separator (menu_in_menu); nID++; + create_menu_item_with_mnemonic (menu_in_menu, "New Group...", + GTK_SIGNAL_FUNC (HandleCommand), ID_DROP_GROUP_NEWGROUP); + */ + create_menu_item_with_mnemonic (menu, "Ungroup Entity", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_UNGROUPENTITY); + + create_menu_item_with_mnemonic (menu, "Move into entity", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MERGE); + create_menu_item_with_mnemonic (menu, "Move into worldspawn", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SEPERATE); + + create_menu_item_with_mnemonic (menu, "Make Detail", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MAKE_DETAIL); + create_menu_item_with_mnemonic (menu, "Make Structural", + GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MAKE_STRUCTURAL); + menu_separator (menu); nID++; + + menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Smart Entities"); + create_menu_item_with_mnemonic (menu_in_menu, "Smart__Train", + GTK_SIGNAL_FUNC (HandleCommand), nID++); + menu_separator (menu); nID++; + + submenu = NULL; + submenu_root = NULL; + eclass_t *e; + CString strActive; + CString strLast; + CString strName; + for (e=eclass ; e ; e=e->next) + { + strLast = strName; + strName = e->name; + int n_ = strName.Find("_"); + if (n_ > 0) + { + CString strLeft = strName.Left(n_); + CString strRight = strName.Right(strName.GetLength() - n_ - 1); + if (strLeft == strActive) // this is a child + { + assert (submenu); + item = gtk_menu_item_new_with_label (strName); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (nID++)); + gtk_widget_show (item); + CheckMenuSplitting(submenu); + gtk_menu_append (GTK_MENU (submenu), item); + } + else + { + if (submenu) + { + // this is submenu from previous main_item, hook it back + // we use submenu_root cause we may have been cascading submenu + item = gtk_menu_item_new_with_label (strActive); + gtk_widget_show (item); + gtk_menu_append (GTK_MENU (menu), item); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu_root); + g_ptrMenus.Add(submenu_root); + submenu = NULL; + submenu_root = NULL; + } + strActive = strLeft; + + submenu = gtk_menu_new (); + submenu_root = submenu; + item = gtk_menu_item_new_with_label (strName); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (nID++)); + gtk_widget_show (item); + gtk_menu_append (GTK_MENU (submenu), item); + } + } + else + { + if (submenu) + { + // this is submenu from previous main_item, hook it back + // we use submenu_root cause we may have been cascading submenu + item = gtk_menu_item_new_with_label (strActive); + gtk_widget_show (item); + gtk_menu_append (GTK_MENU (menu), item); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu_root); + g_ptrMenus.Add(submenu_root); + submenu = NULL; + submenu_root = NULL; + } + strActive = ""; + + item = gtk_menu_item_new_with_label (strName); + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (HandleCommand), + GINT_TO_POINTER (nID++)); + gtk_widget_show (item); + gtk_menu_append (GTK_MENU (menu), item); + } + } + } + + gtk_menu_popup (GTK_MENU (m_mnuDrop), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME); +} + +/* +============== +NewBrushDrag +============== +*/ +void XYWnd::NewBrushDrag (int x, int y) +{ + vec3_t mins, maxs, junk; + int i; + float temp; + brush_t *n; + + if (!DragDelta (x,y, junk)) + return; + + // delete the current selection + if (selected_brushes.next != &selected_brushes) + Brush_Free (selected_brushes.next); + + SnapToPoint (m_nPressx, m_nPressy, mins); + + int nDim = (m_nViewType == XY) ? 2 : (m_nViewType == YZ) ? 0 : 1; + + //++timo clean +// mins[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_bottom_z / g_qeglobals.d_gridsize)); + mins[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_work_min[nDim]/g_qeglobals.d_gridsize)); + + SnapToPoint (x, y, maxs); +// maxs[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_top_z / g_qeglobals.d_gridsize)); + maxs[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_work_max[nDim]/g_qeglobals.d_gridsize)); + if (maxs[nDim] <= mins[nDim]) + maxs[nDim] = mins[nDim] + g_qeglobals.d_gridsize; + + for (i=0 ; i<3 ; i++) + { + if (mins[i] == maxs[i]) + return; // don't create a degenerate brush + if (mins[i] > maxs[i]) + { + temp = mins[i]; + mins[i] = maxs[i]; + maxs[i] = temp; + } + } + + n = Brush_Create (mins, maxs, &g_qeglobals.d_texturewin.texdef); + if (!n) + return; + + vec3_t vSize; + VectorSubtract(maxs, mins, vSize); + g_strStatus.Format("Size X:: %.1f Y:: %.1f Z:: %.1f", vSize[0], vSize[1], vSize[2]); + g_pParentWnd->SetStatusText(2, g_strStatus); + + Brush_AddToList (n, &selected_brushes); + + Entity_LinkBrush (world_entity, n); + + Brush_Build( n ); + + // Sys_UpdateWindows (W_ALL); + Sys_UpdateWindows (W_XY| W_CAMERA); + +} + +/* +============== +XY_MouseMoved +============== +*/ +void XYWnd::XY_MouseMoved (int x, int y, int buttons) +{ + vec3_t point; + + if (!m_nButtonstate) + { + if (g_bCrossHairs) + { + Sys_UpdateWindows (W_XY | W_XY_OVERLAY); + } + return; + } + + // lbutton without selection = drag new brush + if (m_nButtonstate == MK_LBUTTON && !m_bPress_selection && g_qeglobals.d_select_mode != sel_curvepoint && g_qeglobals.d_select_mode != sel_areatall) + { + NewBrushDrag (x, y); + return; + } + + // lbutton (possibly with control and or shift) + // with selection = drag selection + if (m_nButtonstate & MK_LBUTTON) + { + Drag_MouseMoved (x, y, buttons); + if(g_qeglobals.d_select_mode != sel_area) + Sys_UpdateWindows (W_XY_OVERLAY | W_CAMERA_IFON | W_Z); + return; + } + + int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON; + // control mbutton = move camera + if (m_nButtonstate == (MK_CONTROL|nMouseButton) ) + { + SnapToPoint (x, y, point); + VectorCopyXY(point, g_pParentWnd->GetCamWnd()->Camera()->origin); + Sys_UpdateWindows (W_XY_OVERLAY | W_CAMERA); + return; + } + + // shift mbutton = move z checker + if (m_nButtonstate == (MK_SHIFT|nMouseButton) ) + { + if (RotateMode() || g_bPatchBendMode) + { + SnapToPoint (x, y, point); + VectorCopyXY(point, g_vRotateOrigin); + if (g_bPatchBendMode) + { + VectorCopy(point, g_vBendOrigin); + } + Sys_UpdateWindows (W_XY); + return; + } + else + { + SnapToPoint (x, y, point); + if (m_nViewType == XY) + { + z.origin[0] = point[0]; + z.origin[1] = point[1]; + } + else if (m_nViewType == YZ) + { + z.origin[0] = point[1]; + z.origin[1] = point[2]; + } + else + { + z.origin[0] = point[0]; + z.origin[1] = point[2]; + } + } + Sys_UpdateWindows (W_XY_OVERLAY|W_Z); + return; + } + + // mbutton = angle camera + if ((g_PrefsDlg.m_nMouseButtons == 3 && m_nButtonstate == MK_MBUTTON) || + (g_PrefsDlg.m_nMouseButtons == 2 && m_nButtonstate == (MK_SHIFT|MK_CONTROL|MK_RBUTTON))) + { + SnapToPoint (x, y, point); + VectorSubtract (point, g_pParentWnd->GetCamWnd()->Camera()->origin, point); + + int n1 = (m_nViewType == XY) ? 1 : 2; + int n2 = (m_nViewType == YZ) ? 1 : 0; + int nAngle = (m_nViewType == XY) ? YAW : PITCH; + if (point[n1] || point[n2]) + { + g_pParentWnd->GetCamWnd()->Camera()->angles[nAngle] = 180/Q_PI*atan2 (point[n1], point[n2]); + Sys_UpdateWindows (W_CAMERA_IFON|W_XY_OVERLAY); + } + return; + } + + // rbutton = drag xy origin + if (m_nButtonstate == MK_RBUTTON) + { + Sys_GetCursorPos (&x, &y); + if (x != m_ptCursorX || y != m_ptCursorY) + { + int nDim1 = (m_nViewType == YZ) ? 1 : 0; + int nDim2 = (m_nViewType == XY) ? 1 : 2; + m_vOrigin[nDim1] -= (x - m_ptCursorX) / m_fScale; + m_vOrigin[nDim2] += (y - m_ptCursorY) / m_fScale; + Sys_SetCursorPos (m_ptCursorX, m_ptCursorY); + + // create an empty cursor + if (!g_bWaitCursor) + { + GdkPixmap *pixmap; + GdkBitmap *mask; + char buffer [(32 * 32)/8]; + memset (buffer, 0, (32 * 32)/8); + GdkColor white = {0, 0xffff, 0xffff, 0xffff}; + GdkColor black = {0, 0x0000, 0x0000, 0x0000}; + pixmap = gdk_bitmap_create_from_data (NULL, buffer, 32, 32); + mask = gdk_bitmap_create_from_data (NULL, buffer, 32, 32); + GdkCursor *cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &white, &black, 1, 1); + gdk_window_set_cursor (m_pWidget->window, cursor); + gdk_cursor_unref (cursor); + gdk_drawable_unref (pixmap); + gdk_drawable_unref (mask); + } + + Sys_UpdateWindows (W_XY | W_XY_OVERLAY); + } + return; + } + + // zoom in/out + if (m_nButtonstate == (MK_SHIFT | MK_RBUTTON)) + { + Sys_GetCursorPos (&x, &y); + if (y != m_ptCursorY) + { + if (abs (m_ptCursorY - y) > 10) + { + if (m_ptCursorY < y) + g_pParentWnd->OnViewZoomout (); + else + g_pParentWnd->OnViewZoomin (); + + Sys_SetCursorPos (m_ptCursorX, m_ptCursorY); + } + } + return; + } +} + +void XYWnd::OriginalButtonDown(guint32 nFlags, int pointx, int pointy) +{ + SetFocus(); + SetCapture(); + XY_MouseDown (pointx, m_pWidget->allocation.height - 1 - pointy , nFlags); + m_nScrollFlags = nFlags; +} + +void XYWnd::OriginalButtonUp(guint32 nFlags, int pointx, int pointy) +{ + XY_MouseUp (pointx, m_pWidget->allocation.height - 1 - pointy , nFlags); + ReleaseCapture (); +} + +void XYWnd::DropClipPoint(guint32 nFlags, int pointx, int pointy) +{ + if (g_pMovingClip) + { + SetCapture(); + SnapToPoint (pointx, m_pWidget->allocation.height - 1 - pointy , *g_pMovingClip); + } + else + { + vec3_t* pPt = NULL; + if (g_Clip1.Set() == false) + { + pPt = g_Clip1; + g_Clip1.Set(true); + g_Clip1.m_ptScreenX = pointx; + g_Clip1.m_ptScreenY = pointy; + } + else + if (g_Clip2.Set() == false) + { + pPt = g_Clip2; + g_Clip2.Set(true); + g_Clip2.m_ptScreenX = pointx; + g_Clip2.m_ptScreenY = pointy; + } + else + if (g_Clip3.Set() == false) + { + pPt = g_Clip3; + g_Clip3.Set(true); + g_Clip3.m_ptScreenX = pointx; + g_Clip3.m_ptScreenY = pointy; + } + else + { + RetainClipMode(true); + pPt = g_Clip1; + g_Clip1.Set(true); + g_Clip1.m_ptScreenX = pointx; + g_Clip1.m_ptScreenY = pointy; + } + SnapToPoint (pointx, m_pWidget->allocation.height - 1 - pointy , *pPt); + // third coordinates for clip point: use d_work_max + // Arnout: changed to use center of selection for clipping, saves level designers moving points all over the map + // g_pParentWnd->ActiveXY()->GetViewType() + // cf VIEWTYPE defintion: enum VIEWTYPE {YZ, XZ, XY}; + int nViewType = g_pParentWnd->ActiveXY()->GetViewType(); + int nDim = (nViewType == YZ ) ? nDim = 0 : ( (nViewType == XZ) ? nDim = 1 : nDim = 2 ); + //(*pPt)[nDim] = g_qeglobals.d_work_max[nDim]; + vec3_t mid; + Select_GetMid( mid ); + (*pPt)[nDim] = mid[nDim]; + } + Sys_UpdateWindows(XY | W_CAMERA_IFON); +} + +void XYWnd::DropPathPoint(guint32 nFlags, int pointx, int pointy) +{ + if (g_pMovingPath) + { + SetCapture(); + SnapToPoint (pointx, m_pWidget->allocation.height - 1 - pointy , *g_pMovingPath); + } + else + { + g_PathPoints[g_nPathCount].Set(true); + g_PathPoints[g_nPathCount].m_ptScreenX = pointx; + g_PathPoints[g_nPathCount].m_ptScreenY = pointy; + SnapToPoint(pointx, m_pWidget->allocation.height - 1 - pointy, g_PathPoints[g_nPathCount]); + // third coordinates for dropped point: use d_work_max + // g_pParentWnd->ActiveXY()->GetViewType() + // cf VIEWTYPE definition: enum VIEWTYPE {YZ, XZ, XY}; + int nViewType = g_pParentWnd->ActiveXY()->GetViewType(); + int nDim = (nViewType == YZ ) ? nDim = 0 : ( (nViewType == XZ) ? nDim = 1 : nDim = 2 ); + g_PathPoints[g_nPathCount].m_ptClip[nDim] = g_qeglobals.d_work_max[nDim]; + + g_nPathCount++; + if (g_nPathCount == g_nPathLimit) + { + if (g_pPathFunc) + g_pPathFunc(true, g_nPathCount); + g_nPathCount = 0; + g_bPathMode = false; + g_pPathFunc = NULL; + } + } + Sys_UpdateWindows(XY | W_CAMERA_IFON); +} + +// FIXME: AddPointPoint() redundant function never called +#if 0 +void XYWnd::AddPointPoint(guint32 nFlags, vec3_t* pVec) +{ + g_PointPoints[g_nPointCount].Set(true); + //g_PointPoints[g_nPointCount].m_ptScreen = point; + _VectorCopy(*pVec, g_PointPoints[g_nPointCount]); + g_PointPoints[g_nPointCount].SetPointPtr(pVec); + g_nPointCount++; + Sys_UpdateWindows(XY | W_CAMERA_IFON); +} + +// FIXME: ProduceSplits() redundant function never called +void XYWnd::ProduceSplits(brush_t** pFront, brush_t** pBack) +{ + *pFront = NULL; + *pBack = NULL; + if (ClipMode()) + { + if (g_Clip1.Set() && g_Clip2.Set()) + { + face_t face; + VectorCopy(g_Clip1.m_ptClip,face.planepts[0]); + VectorCopy(g_Clip2.m_ptClip,face.planepts[1]); + VectorCopy(g_Clip3.m_ptClip,face.planepts[2]); + if (selected_brushes.next && (selected_brushes.next->next == &selected_brushes)) + { + if (g_Clip3.Set() == false) + { + if (m_nViewType == XY) + { + face.planepts[0][2] = selected_brushes.next->mins[2]; + face.planepts[1][2] = selected_brushes.next->mins[2]; + face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]); + face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]); + face.planepts[2][2] = selected_brushes.next->maxs[2]; + } + else if (m_nViewType == YZ) + { + face.planepts[0][0] = selected_brushes.next->mins[0]; + face.planepts[1][0] = selected_brushes.next->mins[0]; + face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]); + face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]); + face.planepts[2][0] = selected_brushes.next->maxs[0]; + } + else + { + face.planepts[0][1] = selected_brushes.next->mins[1]; + face.planepts[1][1] = selected_brushes.next->mins[1]; + face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]); + face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]); + face.planepts[2][1] = selected_brushes.next->maxs[1]; + } + } + + Brush_SplitBrushByFace (selected_brushes.next, &face, pFront, pBack); + } + + } + } +} +#endif + +void XYWnd::PlanePointsFromClipPoints(vec3_t planepts[3], brush_t *pBrush) +{ + VectorCopy(g_Clip1.m_ptClip,planepts[0]); + VectorCopy(g_Clip2.m_ptClip,planepts[1]); + VectorCopy(g_Clip3.m_ptClip,planepts[2]); + if (g_Clip3.Set() == false) + { + int n = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 2 : (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 0 : 1; + int x = (n == 0) ? 1 : 0; + int y = (n == 2) ? 1 : 2; + + if (n == 1) // on viewtype XZ, flip clip points + { + planepts[0][n] = pBrush->maxs[n]; + planepts[1][n] = pBrush->maxs[n]; + planepts[2][x] = g_Clip1.m_ptClip[x]; + planepts[2][y] = g_Clip1.m_ptClip[y]; + planepts[2][n] = pBrush->mins[n]; + } + else + { + planepts[0][n] = pBrush->mins[n]; + planepts[1][n] = pBrush->mins[n]; + planepts[2][x] = g_Clip1.m_ptClip[x]; + planepts[2][y] = g_Clip1.m_ptClip[y]; + planepts[2][n] = pBrush->maxs[n]; + } + } +} + +void XYWnd::ProduceSplitLists() +{ + bool bCaulk = false; + int nFlags; + + if (AnyPatchesSelected()) + { + Sys_Printf("Deselecting patches for clip operation.\n"); + brush_t *next; + for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = next) + { + next = pb->next; + if (pb->patchBrush) + { + Brush_RemoveFromList (pb); + Brush_AddToList (pb, &active_brushes); + UpdatePatchInspector(); + } + } + // ydnar: update the window if any patches are selected + Sys_UpdateWindows( XY | W_CAMERA_IFON ); + } + + CleanList(&g_brFrontSplits); + CleanList(&g_brBackSplits); + g_brFrontSplits.next = &g_brFrontSplits; + g_brBackSplits.next = &g_brBackSplits; + if (ClipMode() && (g_Clip1.Set() && g_Clip2.Set())) + { + brush_t* pBrush; + for (pBrush = selected_brushes.next ; pBrush != NULL && pBrush != &selected_brushes ; pBrush=pBrush->next) + { + brush_t* pFront = NULL; + brush_t* pBack = NULL; + + face_t face; + memset(&face,0,sizeof(face_t)); + PlanePointsFromClipPoints(face.planepts, pBrush); + + // decide wether caulking should be applied on the splits + // FIXME: hack + // this should take the first brush face, check shader for NODRAW, if it isn't nodraw then find the appropriate + // common/ shader to use, out of solid+nodraw, nonsolid+nodraw, water+nodraw, lava+nodraw, nonsolid+nodraw+trans, water+nodraw+trans, lava+nodraw+trans.. and fog.. etc + // or if none of those apply (unlikely), construct a new shader (shadername_nodraw) based on the shader of the first face, but with surfaceparm nodraw + if (g_PrefsDlg.m_bClipCaulk) + { + nFlags = pBrush->brush_faces->pShader->getFlags(); + if ((nFlags & QER_NODRAW) || (nFlags & QER_NONSOLID) || (nFlags & QER_WATER) || (nFlags & QER_LAVA) || (nFlags & QER_FOG)) // first face shader is anything other than solid AND opaque like caulk + bCaulk = false; // use first face's shader for the splitting face + else + bCaulk = true; // use caulk + } + + Brush_SplitBrushByFace (pBrush, &face, &pFront, &pBack, bCaulk); + if (pBack) + Brush_AddToList(pBack, &g_brBackSplits); + if (pFront) + Brush_AddToList(pFront, &g_brFrontSplits); + + } + } +} + +void XYWnd::XY_Init() +{ + m_vOrigin[0] = 0; + m_vOrigin[1] = 20; + m_vOrigin[2] = 46; + m_fScale = 1; +} + +void XYWnd::SnapToPoint (int x, int y, vec3_t point) +{ + if (g_PrefsDlg.m_bNoClamp) + { + XY_ToPoint(x, y, point); + } + else + { + XY_ToGridPoint(x, y, point); + } +} + +// TTimo: watch it, this doesn't init one of the 3 coords +void XYWnd::XY_ToPoint (int x, int y, vec3_t point) +{ + float fx = x; + float fy = y; + float fw = m_nWidth; + float fh = m_nHeight; + if (m_nViewType == XY) + { + point[0] = m_vOrigin[0] + (fx - fw / 2) / m_fScale; + point[1] = m_vOrigin[1] + (fy - fh / 2) / m_fScale; + } + else if (m_nViewType == YZ) + { + point[1] = m_vOrigin[1] + (fx - fw / 2) / m_fScale; + point[2] = m_vOrigin[2] + (fy - fh / 2 ) / m_fScale; + } + else + { + point[0] = m_vOrigin[0] + (fx - fw / 2) / m_fScale; + point[2] = m_vOrigin[2] + (fy - fh / 2) / m_fScale; + } +} + +void XYWnd::XY_ToGridPoint (int x, int y, vec3_t point) +{ + if (m_nViewType == XY) + { + point[0] = m_vOrigin[0] + (x - m_nWidth / 2) / m_fScale; + point[1] = m_vOrigin[1] + (y - m_nHeight / 2) / m_fScale; + point[0] = floor(point[0] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + point[1] = floor(point[1] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + } + else if (m_nViewType == YZ) + { + point[1] = m_vOrigin[1] + (x - m_nWidth / 2) / m_fScale; + point[2] = m_vOrigin[2] + (y - m_nHeight / 2) / m_fScale; + point[1] = floor(point[1] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + point[2] = floor(point[2] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + } + else + { + point[0] = m_vOrigin[0] + (x - m_nWidth / 2) / m_fScale; + point[2] = m_vOrigin[2] + (y - m_nHeight / 2) / m_fScale; + point[0] = floor(point[0] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + point[2] = floor(point[2] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + } +} + +/* +============================================================================ + +DRAWING + +============================================================================ +*/ + +/* +============== +XY_DrawGrid +============== +*/ +void XYWnd::XY_DrawGrid() +{ + float x, y, xb, xe, yb, ye; + float w, h; + char text[32]; + int step, stepx, stepy, colour; + step = stepx = stepy = MAX (64, (int)g_qeglobals.d_gridsize); + + /* + int stepSize = (int)(8 / m_fScale); + if (stepSize > step) + { + int i; + for (i = 1; i < stepSize; i <<= 1) + ; + step = i; + } + */ + + //Sys_Printf("scale: %f\n", m_fScale); + //Sys_Printf("step before: %i\n", step); + //Sys_Printf("scaled step: %f\n", step * m_fScale); + while ((step * m_fScale) < 4.0f) // make sure major grid spacing is at least 4 pixels on the screen + step *= 8; + //Sys_Printf("step after: %i\n", step); + while ((stepx * m_fScale) < 32.0f) // text step x must be at least 32 + stepx *= 2; + while ((stepy * m_fScale) < 32.0f) // text step y must be at least 32 + stepy *= 2; + + qglDisable(GL_TEXTURE_2D); + qglDisable(GL_TEXTURE_1D); + qglDisable(GL_DEPTH_TEST); + qglDisable(GL_BLEND); + + w = (m_nWidth / 2 / m_fScale); + h = (m_nHeight / 2 / m_fScale); + + int nDim1 = (m_nViewType == YZ) ? 1 : 0; + int nDim2 = (m_nViewType == XY) ? 1 : 2; + + xb = m_vOrigin[nDim1] - w; + if (xb < region_mins[nDim1]) + xb = region_mins[nDim1]; + xb = step * floor (xb/step); + + xe = m_vOrigin[nDim1] + w; + if (xe > region_maxs[nDim1]) + xe = region_maxs[nDim1]; + xe = step * ceil (xe/step); + + yb = m_vOrigin[nDim2] - h; + if (yb < region_mins[nDim2]) + yb = region_mins[nDim2]; + yb = step * floor (yb/step); + + ye = m_vOrigin[nDim2] + h; + if (ye > region_maxs[nDim2]) + ye = region_maxs[nDim2]; + ye = step * ceil (ye/step); + +#define COLORS_DIFFER(a,b) \ + (g_qeglobals.d_savedinfo.colors[a][0] != g_qeglobals.d_savedinfo.colors[b][0] || \ + g_qeglobals.d_savedinfo.colors[a][1] != g_qeglobals.d_savedinfo.colors[b][1] || \ + g_qeglobals.d_savedinfo.colors[a][2] != g_qeglobals.d_savedinfo.colors[b][2]) + + // djbob + // draw minor blocks + if (m_fScale > .1 && g_qeglobals.d_showgrid && g_qeglobals.d_gridsize * m_fScale >= 4) + { + if (g_qeglobals.d_gridsize < 1) + colour = COLOR_GRIDMINOR_ALT; + else + colour = COLOR_GRIDMINOR; + + if (COLORS_DIFFER(colour, COLOR_GRIDBACK)) + { + qglColor3fv(g_qeglobals.d_savedinfo.colors[colour]); + + qglBegin (GL_LINES); + for (x=xb ; x 65536 || g_qeglobals.blockSize < 1024) + // don't use custom blocksize if it is less than the default, or greater than the maximum world coordinate + g_qeglobals.blockSize = 1024; + + float x, y, xb, xe, yb, ye; + float w, h; + char text[32]; + + qglDisable(GL_TEXTURE_2D); + qglDisable(GL_TEXTURE_1D); + qglDisable(GL_DEPTH_TEST); + qglDisable(GL_BLEND); + + w = (m_nWidth / 2 / m_fScale); + h = (m_nHeight / 2 / m_fScale); + + int nDim1 = (m_nViewType == YZ) ? 1 : 0; + int nDim2 = (m_nViewType == XY) ? 1 : 2; + + xb = m_vOrigin[nDim1] - w; + if (xb < region_mins[nDim1]) + xb = region_mins[nDim1]; + xb = g_qeglobals.blockSize * floor (xb/g_qeglobals.blockSize); + + xe = m_vOrigin[nDim1] + w; + if (xe > region_maxs[nDim1]) + xe = region_maxs[nDim1]; + xe = g_qeglobals.blockSize * ceil (xe/g_qeglobals.blockSize); + + yb = m_vOrigin[nDim2] - h; + if (yb < region_mins[nDim2]) + yb = region_mins[nDim2]; + yb = g_qeglobals.blockSize * floor (yb/g_qeglobals.blockSize); + + ye = m_vOrigin[nDim2] + h; + if (ye > region_maxs[nDim2]) + ye = region_maxs[nDim2]; + ye = g_qeglobals.blockSize * ceil (ye/g_qeglobals.blockSize); + + // draw major blocks + + qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK]); + qglLineWidth (2); + + qglBegin (GL_LINES); + + for (x=xb ; x<=xe ; x+=g_qeglobals.blockSize) + { + qglVertex2f (x, yb); + qglVertex2f (x, ye); + } + + if (m_nViewType == XY) + { + for (y=yb ; y<=ye ; y+=g_qeglobals.blockSize) + { + qglVertex2f (xb, y); + qglVertex2f (xe, y); + } + } + + qglEnd (); + qglLineWidth (1); + + // draw coordinate text if needed + + if (m_nViewType == XY && m_fScale > .1) + { + for (x=xb ; xGetCamWnd()->Camera()->origin[0]; + y = g_pParentWnd->GetCamWnd()->Camera()->origin[1]; + a = g_pParentWnd->GetCamWnd()->Camera()->angles[YAW]/180*Q_PI; + } + else if (m_nViewType == YZ) + { + x = g_pParentWnd->GetCamWnd()->Camera()->origin[1]; + y = g_pParentWnd->GetCamWnd()->Camera()->origin[2]; + a = g_pParentWnd->GetCamWnd()->Camera()->angles[PITCH]/180*Q_PI; + } + else + { + x = g_pParentWnd->GetCamWnd()->Camera()->origin[0]; + y = g_pParentWnd->GetCamWnd()->Camera()->origin[2]; + a = g_pParentWnd->GetCamWnd()->Camera()->angles[PITCH]/180*Q_PI; + } + + qglColor3f (0.0, 0.0, 1.0); + qglBegin(GL_LINE_STRIP); + qglVertex3f (x-box,y,0); + qglVertex3f (x,y+(box/2),0); + qglVertex3f (x+box,y,0); + qglVertex3f (x,y-(box/2),0); + qglVertex3f (x-box,y,0); + qglVertex3f (x+box,y,0); + qglEnd (); + + qglBegin(GL_LINE_STRIP); + qglVertex3f (x+fov*cos(a+Q_PI/4), y+fov*sin(a+Q_PI/4), 0); + qglVertex3f (x, y, 0); + qglVertex3f (x+fov*cos(a-Q_PI/4), y+fov*sin(a-Q_PI/4), 0); + qglEnd (); + +} + +void XYWnd::DrawZIcon (void) +{ + if (m_nViewType == XY) + { + float x = z.origin[0]; + float y = z.origin[1]; + float zdim = 8 / m_fScale; + qglEnable (GL_BLEND); + qglDisable (GL_TEXTURE_2D); + qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + qglDisable (GL_CULL_FACE); + qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + qglColor4f (0.0, 0.0, 1.0, 0.25); + qglBegin(GL_QUADS); + qglVertex3f (x-zdim,y-zdim,0); + qglVertex3f (x+zdim,y-zdim,0); + qglVertex3f (x+zdim,y+zdim,0); + qglVertex3f (x-zdim,y+zdim,0); + qglEnd (); + qglDisable (GL_BLEND); + + qglColor4f (0.0, 0.0, 1.0, 1); + + qglBegin(GL_LINE_LOOP); + qglVertex3f (x-zdim,y-zdim,0); + qglVertex3f (x+zdim,y-zdim,0); + qglVertex3f (x+zdim,y+zdim,0); + qglVertex3f (x-zdim,y+zdim,0); + qglEnd (); + + qglBegin(GL_LINE_STRIP); + qglVertex3f (x-(zdim/2),y+(zdim/2),0); + qglVertex3f (x+(zdim/2),y+(zdim/2),0); + qglVertex3f (x-(zdim/2),y-(zdim/2),0); + qglVertex3f (x+(zdim/2),y-(zdim/2),0); + qglEnd (); + } +} + +// can be greatly simplified but per usual i am in a hurry +// which is not an excuse, just a fact +void XYWnd::PaintSizeInfo(int nDim1, int nDim2, vec3_t vMinBounds, vec3_t vMaxBounds) +{ + const char* g_pDimStrings[] = {"x:%.f", "y:%.f", "z:%.f"}; + const char* g_pOrgStrings[] = {"(x:%.f y:%.f)", "(x:%.f z:%.f)", "(y:%.f z:%.f)"}; + + CString g_strDim; + + vec3_t vSize; + VectorSubtract(vMaxBounds, vMinBounds, vSize); + + qglColor3f(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0] * .65, + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1] * .65, + g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2] * .65); + + if (m_nViewType == XY) + { + qglBegin (GL_LINES); + + qglVertex3f(vMinBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale, 0.0f); + qglVertex3f(vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f); + + qglVertex3f(vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f); + qglVertex3f(vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f); + + qglVertex3f(vMaxBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale, 0.0f); + qglVertex3f(vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f); + + + qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, vMinBounds[nDim2], 0.0f); + qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2], 0.0f); + + qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2], 0.0f); + qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2], 0.0f); + + qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, vMaxBounds[nDim2], 0.0f); + qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2], 0.0f); + + qglEnd(); + + qglRasterPos3f (Betwixt(vMinBounds[nDim1], vMaxBounds[nDim1]), vMinBounds[nDim2] - 20.0 / m_fScale, 0.0f); + g_strDim.Format(g_pDimStrings[nDim1], vSize[nDim1]); + gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); + + qglRasterPos3f (vMaxBounds[nDim1] + 16.0 / m_fScale, Betwixt(vMinBounds[nDim2], vMaxBounds[nDim2]), 0.0f); + g_strDim.Format(g_pDimStrings[nDim2], vSize[nDim2]); + gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); + + qglRasterPos3f (vMinBounds[nDim1] + 4, vMaxBounds[nDim2] + 8 / m_fScale, 0.0f); + g_strDim.Format(g_pOrgStrings[0], vMinBounds[nDim1], vMaxBounds[nDim2]); + gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); + } + else if (m_nViewType == XZ) + { + qglBegin (GL_LINES); + + qglVertex3f(vMinBounds[nDim1], 0, vMinBounds[nDim2] - 6.0f / m_fScale); + qglVertex3f(vMinBounds[nDim1], 0, vMinBounds[nDim2] - 10.0f / m_fScale); + + qglVertex3f(vMinBounds[nDim1], 0,vMinBounds[nDim2] - 10.0f / m_fScale); + qglVertex3f(vMaxBounds[nDim1], 0,vMinBounds[nDim2] - 10.0f / m_fScale); + + qglVertex3f(vMaxBounds[nDim1], 0,vMinBounds[nDim2] - 6.0f / m_fScale); + qglVertex3f(vMaxBounds[nDim1], 0,vMinBounds[nDim2] - 10.0f / m_fScale); + + + qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, 0,vMinBounds[nDim2]); + qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0,vMinBounds[nDim2]); + + qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0,vMinBounds[nDim2]); + qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0,vMaxBounds[nDim2]); + + qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, 0,vMaxBounds[nDim2]); + qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0,vMaxBounds[nDim2]); + + qglEnd(); + + qglRasterPos3f (Betwixt(vMinBounds[nDim1], vMaxBounds[nDim1]), 0, vMinBounds[nDim2] - 20.0 / m_fScale); + g_strDim.Format(g_pDimStrings[nDim1], vSize[nDim1]); + gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); + + qglRasterPos3f (vMaxBounds[nDim1] + 16.0 / m_fScale, 0, Betwixt(vMinBounds[nDim2], vMaxBounds[nDim2])); + g_strDim.Format(g_pDimStrings[nDim2], vSize[nDim2]); + gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); + + qglRasterPos3f (vMinBounds[nDim1] + 4, 0, vMaxBounds[nDim2] + 8 / m_fScale); + g_strDim.Format(g_pOrgStrings[1], vMinBounds[nDim1], vMaxBounds[nDim2]); + gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); + } + else + { + qglBegin (GL_LINES); + + qglVertex3f(0, vMinBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale); + qglVertex3f(0, vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale); + + qglVertex3f(0, vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale); + qglVertex3f(0, vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale); + + qglVertex3f(0, vMaxBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale); + qglVertex3f(0, vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale); + + + qglVertex3f(0, vMaxBounds[nDim1] + 6.0f / m_fScale, vMinBounds[nDim2]); + qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2]); + + qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2]); + qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2]); + + qglVertex3f(0, vMaxBounds[nDim1] + 6.0f / m_fScale, vMaxBounds[nDim2]); + qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2]); + + qglEnd(); + + qglRasterPos3f (0, Betwixt(vMinBounds[nDim1], vMaxBounds[nDim1]), vMinBounds[nDim2] - 20.0 / m_fScale); + g_strDim.Format(g_pDimStrings[nDim1], vSize[nDim1]); + gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); + + qglRasterPos3f (0, vMaxBounds[nDim1] + 16.0 / m_fScale, Betwixt(vMinBounds[nDim2], vMaxBounds[nDim2])); + g_strDim.Format(g_pDimStrings[nDim2], vSize[nDim2]); + gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); + + qglRasterPos3f (0, vMinBounds[nDim1] + 4.0, vMaxBounds[nDim2] + 8 / m_fScale); + g_strDim.Format(g_pOrgStrings[2], vMinBounds[nDim1], vMaxBounds[nDim2]); + gtk_glwidget_print_string((char *) g_strDim.GetBuffer()); + } +} + +/* +============== +XY_Draw +============== +*/ +#define ALT_POINT_SIZE 4 +// Alternative to GL_POINTS (for; vertex handles, patch handles, clip points, path points) +void DrawAlternatePoint(vec3_t v, float scale) +{ + if(scale == 0) + { + scale = g_pParentWnd->GetXYWnd()->Scale(); + //scale = g_qeglobals.d_xyOld.scale; + } + + // ugly gl_line cross + qglVertex3f ( v[0]+(ALT_POINT_SIZE/scale), v[1], v[2] ); + qglVertex3f ( v[0]-(ALT_POINT_SIZE/scale), v[1], v[2] ); + qglVertex3f ( v[0], v[1]+(ALT_POINT_SIZE/scale), v[2] ); + qglVertex3f ( v[0], v[1]-(ALT_POINT_SIZE/scale), v[2] ); + qglVertex3f ( v[0], v[1], v[2]+(ALT_POINT_SIZE/scale) ); + qglVertex3f ( v[0], v[1], v[2]-(ALT_POINT_SIZE/scale) ); +} + + +long g_lCount = 0; +long g_lTotal = 0; +extern void DrawBrushEntityName (brush_t *b); + +//#define DBG_SCENEDUMP + +void XYWnd::XY_Draw() +{ +#ifdef DBG_SCENEDUMP + static time_t s_start = 0; // we use that to dump the selected stuff every 2 seconds + time_t now; + time (&now); + bool bDump; + + if ((now - s_start) > 3) + { + bDump = true; + s_start = now; + Sys_FPrintf(SYS_WRN, "Starting scene dump\n"); + } + else bDump = false; +#endif + + brush_t *brush; + float w, h; + entity_t *e; + double start, end; + double start2, end2; + vec3_t mins, maxs; + int drawn, culled; + int i; + + if (!active_brushes.next) + return; // not valid yet + + Patch_LODMatchAll(); // spog + + if (m_bTiming) + start = Sys_DoubleTime(); + // + // clear + // + m_bDirty = false; + + qglViewport(0, 0, m_nWidth, m_nHeight); + qglClearColor (g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][0], + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][1], + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][2],0); + + qglClear(GL_COLOR_BUFFER_BIT); + + // + // set up viewpoint + // + qglMatrixMode(GL_PROJECTION); + qglLoadIdentity (); + + w = m_nWidth / 2 / m_fScale; + h = m_nHeight / 2/ m_fScale; + + // fix GL_INVALID_VALUE error on first time the window is updated (win32) + if (w == 0) + w = 1; + + int nDim1 = (m_nViewType == YZ) ? 1 : 0; + int nDim2 = (m_nViewType == XY) ? 1 : 2; + mins[0] = m_vOrigin[nDim1] - w; + maxs[0] = m_vOrigin[nDim1] + w; + mins[1] = m_vOrigin[nDim2] - h; + maxs[1] = m_vOrigin[nDim2] + h; + + qglOrtho (mins[0], maxs[0], mins[1], maxs[1], g_MinWorldCoord, g_MaxWorldCoord); + + qglMatrixMode(GL_MODELVIEW); + qglLoadIdentity (); + + // + // now draw the grid + // + XY_DrawGrid (); + + // + // draw block grid + // + if ( g_qeglobals.show_blocks) + XY_DrawBlockGrid (); + + if (m_nViewType != XY) + { + qglPushMatrix(); + if (m_nViewType == YZ) + qglRotatef (-90, 0, 1, 0); // put Z going up + qglRotatef (-90, 1, 0, 0); // put Z going up + } + + // + // draw stuff + // + qglShadeModel (GL_FLAT); + qglDisable(GL_TEXTURE_2D); + qglDisable(GL_TEXTURE_1D); + qglDisable(GL_DEPTH_TEST); + qglDisable(GL_BLEND); + qglDisable(GL_CULL_FACE); + qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + qglColor3f(0, 0, 0); + qglEnableClientState(GL_VERTEX_ARRAY); + + // Fishman - Add antialiazed points and lines support. 09/15/00 + if (g_PrefsDlg.m_bAntialiasedPointsAndLines) + { + qglEnable(GL_BLEND); + qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + qglEnable(GL_POINT_SMOOTH); + qglEnable(GL_LINE_SMOOTH); + } + + drawn = culled = 0; + + e = world_entity; + + if (m_bTiming) + start2 = Sys_DoubleTime(); + + for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next) + { + if (brush->bFiltered) + continue; + + if (brush->mins[nDim1] > maxs[0] || + brush->mins[nDim2] > maxs[1] || + brush->maxs[nDim1] < mins[0] || + brush->maxs[nDim2] < mins[1]) + { + culled++; + continue; // off screen + } + + drawn++; + + if (brush->owner != e && brush->owner) + { + qglColor3fv(brush->owner->eclass->color); + } + else + { + qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES]); + } + +#ifdef DBG_SCENEDUMP + if (bDump) + { + Sys_FPrintf(SYS_WRN, "Active brush: %p ", brush); + Sys_FPrintf(SYS_WRN, "owner->eclass: %s\n", brush->owner->eclass->name); + } +#endif + + Brush_DrawXY(brush, m_nViewType); + } + + if (m_bTiming) + end2 = Sys_DoubleTime(); + + DrawPathLines (); + + // + // draw pointfile + // + //++timo why is the display list broken? + if ( g_qeglobals.d_pointfile_display_list) + Pointfile_Draw(); + + // + // now draw selected brushes + // + + if (RotateMode()) + qglColor3f(0.8f, 0.1f, 0.9f); + else + if (ScaleMode()) + qglColor3f(0.1f, 0.8f, 0.1f); + else + qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES]); + + + if (g_PrefsDlg.m_bNoStipple == FALSE) + { + qglEnable (GL_LINE_STIPPLE); + qglLineStipple (3, 0xaaaa); + } + qglLineWidth (2); + + vec3_t vMinBounds; + vec3_t vMaxBounds; + vMinBounds[0] = vMinBounds[1] = vMinBounds[2] = g_MaxWorldCoord; + vMaxBounds[0] = vMaxBounds[1] = vMaxBounds[2] = g_MinWorldCoord; + + int nSaveDrawn = drawn; + bool bFixedSize = false; + for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next) + { + // spog - added culling of selected brushes in XY window + if (brush->mins[nDim1] > maxs[0] || + brush->mins[nDim2] > maxs[1] || + brush->maxs[nDim1] < mins[0] || + brush->maxs[nDim2] < mins[1]) + { + culled++; + continue; // off screen + } + drawn++; +#ifdef DBG_SCENEDUMP + if (bDump) + { + Sys_FPrintf(SYS_WRN, "Selected brush: %p ", brush); + Sys_FPrintf(SYS_WRN, "owner->eclass: %s\n", brush->owner->eclass->name); + } +#endif + Brush_DrawXY(brush, m_nViewType); + + if (!bFixedSize) + { + if (brush->owner->eclass->fixedsize) + bFixedSize = true; + if (g_PrefsDlg.m_bSizePaint) + { + for (i = 0; i < 3; i ++) + { + if (brush->mins[i] < vMinBounds[i]) + vMinBounds[i] = brush->mins[i]; + if (brush->maxs[i] > vMaxBounds[i]) + vMaxBounds[i] = brush->maxs[i]; + } + } + } + } + + if (g_PrefsDlg.m_bNoStipple == FALSE) + { + qglDisable (GL_LINE_STIPPLE); + } + qglLineWidth (1); + + if (!bFixedSize && !RotateMode() && !ScaleMode() && drawn - nSaveDrawn > 0 && g_PrefsDlg.m_bSizePaint) + PaintSizeInfo(nDim1, nDim2, vMinBounds, vMaxBounds); + + // edge / vertex flags + if (g_qeglobals.d_select_mode == sel_vertex) + { + if(!g_PrefsDlg.m_bGlPtWorkaround) + { + // brush verts + qglPointSize (4); + qglColor3f (0,1,0); + qglBegin (GL_POINTS); + for (i=0 ; iCurrentStyle() == MainFrame::eSplit) + qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME]); + else + qglColor3fv( g_qeglobals.d_savedinfo.AxisColors[m_nViewType]); + qglBegin (GL_LINE_LOOP); + qglVertex2i (0, 0); + qglVertex2i (m_nWidth-1, 0); + qglVertex2i (m_nWidth-1, m_nHeight-1); + qglVertex2i (0, m_nHeight-1); + qglEnd (); + + qglMatrixMode (GL_PROJECTION); + qglPopMatrix (); + qglMatrixMode (GL_MODELVIEW); + qglPopMatrix (); + } + } + + qglFinish(); + + if (m_bTiming) + { + end = Sys_DoubleTime (); + i = (int)(1000*(end-start)); + int i3 = (int)(1000*(end2-start2)); + g_lCount++; + g_lTotal += i; + int i2 = g_lTotal / g_lCount; + Sys_Printf ("xy: %i ab: %i avg: %i\n", i, i3, i2); + } + + // Fishman - Add antialiazed points and lines support. 09/03/00 + if (g_PrefsDlg.m_bAntialiasedPointsAndLines) + { + qglDisable(GL_POINT_SMOOTH); + qglDisable(GL_LINE_SMOOTH); + qglDisable(GL_BLEND); + } +} + +void XYWnd::Copy() +{ +} + +void XYWnd::Undo() +{ +} + +void XYWnd::UndoClear() +{ +} + +void XYWnd::UndoCopy() +{ +} + +bool XYWnd::UndoAvailable() +{ + return (g_brUndo.next != &g_brUndo); +} + +void XYWnd::Paste() +{ +} + +// should be static as should be the rotate scale stuff +bool XYWnd::AreaSelectOK() +{ + return RotateMode() ? false : ScaleMode() ? false : true; +} + +void XYWnd::OnCreate () +{ + if (!MakeCurrent ()) + Error ("glXMakeCurrent failed"); + + qglPolygonStipple ((unsigned char *)s_stipple); + qglLineStipple (3, 0xaaaa); +} + +void XYWnd::OnExpose () +{ + bool bPaint = true; + if (!MakeCurrent ()) + { + Sys_Printf("ERROR: glXMakeCurrent failed.. Error:%i\n",qglGetError()); + Sys_Printf("Please restart Radiant if the Map view is not working\n"); + bPaint = false; + } + if (bPaint) + { + QE_CheckOpenGLForErrors(); + XY_Draw (); + QE_CheckOpenGLForErrors(); + + if (m_nViewType != XY) + { + qglPushMatrix(); + if (m_nViewType == YZ) + qglRotatef (-90, 0, 1, 0); // put Z going up + qglRotatef (-90, 1, 0, 0); // put Z going up + } + + if (g_bCrossHairs) + { + qglColor4f(0.2f, 0.9f, 0.2f, 0.8f); + qglBegin (GL_LINES); + if (m_nViewType == XY) + { + qglVertex2f(2*g_MinWorldCoord, tdp[1]); + qglVertex2f(2*g_MaxWorldCoord, tdp[1]); + qglVertex2f(tdp[0], 2*g_MinWorldCoord); + qglVertex2f(tdp[0], 2*g_MaxWorldCoord); + } + else if (m_nViewType == YZ) + { + qglVertex3f(tdp[0], 2*g_MinWorldCoord, tdp[2]); + qglVertex3f(tdp[0], 2*g_MaxWorldCoord, tdp[2]); + qglVertex3f(tdp[0], tdp[1], 2*g_MinWorldCoord); + qglVertex3f(tdp[0], tdp[1], 2*g_MaxWorldCoord); + } + else + { + qglVertex3f (2*g_MinWorldCoord, tdp[1], tdp[2]); + qglVertex3f (2*g_MaxWorldCoord, tdp[1], tdp[2]); + qglVertex3f(tdp[0], tdp[1], 2*g_MinWorldCoord); + qglVertex3f(tdp[0], tdp[1], 2*g_MaxWorldCoord); + } + qglEnd(); + } + + if (ClipMode()) + { + // Draw clip points + if (g_Clip1.Set()) + g_Clip1.Draw(m_fScale, 1); // qglVertex3fv (g_Clip1); + if (g_Clip2.Set()) + g_Clip2.Draw(m_fScale, 2); // qglVertex3fv (g_Clip2); + if (g_Clip3.Set()) + g_Clip3.Draw(m_fScale, 3); // qglVertex3fv (g_Clip3); + if (g_Clip1.Set() && g_Clip2.Set()) + { + ProduceSplitLists(); + brush_t* pBrush; + brush_t* pList = (g_bSwitch) ? &g_brBackSplits : &g_brFrontSplits; + for (pBrush = pList->next ; pBrush != NULL && pBrush != pList ; pBrush=pBrush->next) + { + qglColor3f (1,1,0); + face_t *face; + int order; + for (face = pBrush->brush_faces,order = 0 ; face ; face=face->next, order++) + { + winding_t* w = face->face_winding; + if (!w) + continue; + // draw the polygon + qglBegin(GL_LINE_LOOP); + for (int i=0 ; inumpoints ; i++) + qglVertex3fv(w->points[i]); + qglEnd(); + } + } + } + } + + if (PathMode()) + { + int n; + for (n = 0; n < g_nPathCount; n++) + g_PathPoints[n].Draw(m_fScale, n+1); // qglVertex3fv(g_PathPoints[n]); + } + if (m_nViewType != XY) + qglPopMatrix(); + + m_XORRectangle.set(rectangle_t()); + SwapBuffers (); + } +} + +void XYWnd::KillPathMode() +{ + g_bSmartGo = false; + g_bPathMode = false; + if (g_pPathFunc) + g_pPathFunc(false, g_nPathCount); + g_nPathCount = 0; + g_pPathFunc = NULL; + Sys_UpdateWindows(W_ALL); +} + +// gets called for drop down menu messages +// TIP: it's not always about EntityCreate +void XYWnd::OnEntityCreate (const char* item) +{ + Undo_Start("create entity"); + Undo_AddBrushList(&selected_brushes); + + if (m_mnuDrop != NULL) + { + CString strItem; + strItem = item; + + if (strItem.CompareNoCase("Add to...") == 0) + { + //++timo TODO: fill the menu with current groups? + // this one is for adding to existing groups only + Sys_Printf("TODO: Add to... in XYWnd::OnEntityCreate\n"); + } + else if (strItem.CompareNoCase("Remove") == 0) + { + // remove selected brushes from their current group + brush_t *b; + for( b = selected_brushes.next; b != &selected_brushes; b = b->next ) + { + + } + } + + //++timo FIXME: remove when all hooks are in + if (strItem.CompareNoCase("Add to...") == 0 + || strItem.CompareNoCase("Remove") == 0 + || strItem.CompareNoCase("Name...") == 0 + || strItem.CompareNoCase("New group...") == 0) + { + Sys_Printf("TODO: hook drop down group menu\n"); + return; + } + + if (strItem.Find("Smart_") >= 0) + { + CreateSmartEntity(this, m_ptDownX, m_ptDownY, strItem); + } + else + { + CreateRightClickEntity(this, m_ptDownX, m_ptDownY, (char*)strItem.GetBuffer()); + } + + Sys_UpdateWindows(W_ALL); + //OnLButtonDown((MK_LBUTTON | MK_SHIFT), CPoint(m_ptDown.x+2, m_ptDown.y+2)); + } + Undo_EndBrushList(&selected_brushes); + Undo_End(); +} + +/* Drawing clip points */ +void ClipPoint::Draw(float fScale, int num) +{ + CString strLabel; + strLabel.Format("%d", num); + Draw(fScale, strLabel.GetBuffer()); +} + +#define ALT_POINT_VERTS 6 + +void ClipPoint::Draw(float fScale, const char *label) +{ + // draw point + if(!g_PrefsDlg.m_bGlPtWorkaround) + { + qglPointSize (4); + qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER]); + qglBegin (GL_POINTS); + qglVertex3fv (m_ptClip); + qglEnd(); + qglPointSize (1); + } + else + { + qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER]); + qglLineWidth(2.0); + qglBegin (GL_LINES); + DrawAlternatePoint(m_ptClip, fScale); + qglEnd(); + qglLineWidth(1.0); + } + + // draw label + qglRasterPos3f (m_ptClip[0]+2, m_ptClip[1]+2, m_ptClip[2]+2); + qglCallLists (strlen(label), GL_UNSIGNED_BYTE, label); +} + diff --git a/radiant/z.cpp b/radiant/z.cpp index b5806cba..dff40708 100644 --- a/radiant/z.cpp +++ b/radiant/z.cpp @@ -1,466 +1,466 @@ -/* -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 -*/ - -#include "stdafx.h" -//#include "qe3.h" - -#define PAGEFLIPS 2 - -z_t z; - -/* -============ -Z_Init -============ -*/ -void Z_Init (void) -{ - z.origin[0] = 0; - z.origin[1] = 20; - z.origin[2] = 46; - - z.scale = 1; -} - - - -/* -============================================================================ - - MOUSE ACTIONS - -============================================================================ -*/ - -static int cursorx, cursory; - -/* -============== -Z_MouseDown -============== -*/ -void Z_MouseDown (int x, int y, int buttons) -{ - vec3_t org, dir, vup, vright; - brush_t *b; - - Sys_GetCursorPos (&cursorx, &cursory); - - vup[0] = 0; vup[1] = 0; vup[2] = 1/z.scale; - - VectorCopy (z.origin, org); - org[2] += (y - (z.height/2))/z.scale; - org[1] = g_MinWorldCoord; - - b = selected_brushes.next; - if (b != &selected_brushes) - { - org[0] = (b->mins[0] + b->maxs[0])/2; - } - - dir[0] = 0; dir[1] = 1; dir[2] = 0; - - vright[0] = 0; vright[1] = 0; vright[2] = 0; - - // LBUTTON = manipulate selection - // shift-LBUTTON = select - // middle button = grab texture - // ctrl-middle button = set entire brush to texture - // ctrl-shift-middle button = set single face to texture - - int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON; - if ( (buttons == MK_LBUTTON) - || (buttons == (MK_LBUTTON | MK_SHIFT)) - || (buttons == MK_MBUTTON) -// || (buttons == (MK_MBUTTON|MK_CONTROL)) - || (buttons == (nMouseButton|MK_SHIFT|MK_CONTROL)) ) - { - Drag_Begin (x, y, buttons, - vright, vup, - org, dir); - return; - } - - // control mbutton = move camera - if ((buttons == (MK_CONTROL|nMouseButton) ) || (buttons == (MK_CONTROL|MK_LBUTTON))) - { - g_pParentWnd->GetCamWnd()->Camera()->origin[2] = org[2] ; - Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY|W_Z); - } - - -} - -/* -============== -Z_MouseUp -============== -*/ -void Z_MouseUp (int x, int y, int buttons) -{ - Drag_MouseUp (); -} - -/* -============== -Z_MouseMoved -============== -*/ -void Z_MouseMoved (int x, int y, int buttons) -{ - if (!buttons) - return; - if (buttons == MK_LBUTTON) - { - Drag_MouseMoved (x, y, buttons); - Sys_UpdateWindows (W_Z|W_CAMERA_IFON|W_XY); - return; - } - // rbutton = drag z origin - if (buttons == MK_RBUTTON) - { - Sys_GetCursorPos (&x, &y); - if ( y != cursory) - { - z.origin[2] += y-cursory; - Sys_SetCursorPos (cursorx, cursory); - Sys_UpdateWindows (W_Z); - } - return; - } - // control mbutton = move camera - int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON; - if ((buttons == (MK_CONTROL|nMouseButton) ) || (buttons == (MK_CONTROL|MK_LBUTTON))) - { - g_pParentWnd->GetCamWnd()->Camera()->origin[2] = (y - (z.height/2))/z.scale; - Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY|W_Z); - } - -} - - -/* -============================================================================ - -DRAWING - -============================================================================ -*/ - - -/* -============== -Z_DrawGrid -============== -*/ -void Z_DrawGrid (void) -{ - float zz, zb, ze; - float w, h; - char text[32]; - - w = (z.width/2 / z.scale); - h = (z.height/2 / z.scale); - - zb = z.origin[2] - h; - if (zb < region_mins[2]) - zb = region_mins[2]; - zb = 64 * floor (zb/64); - - ze = z.origin[2] + h; - if (ze > region_maxs[2]) - ze = region_maxs[2]; - ze = 64 * ceil (ze/64); - - // draw major blocks - - qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR]); - - if ( g_qeglobals.d_showgrid ) - { - if (g_qeglobals.d_gridsize < 128) - { - qglBegin (GL_LINES); - - qglVertex2f (0, zb); - qglVertex2f (0, ze); - - for (zz=zb ; zz= 128 .. it's an int for sure - if ( ((int)zz & ((int)g_qeglobals.d_gridsize-1)) != 0 ) - continue; - - qglVertex2f (-w, zz); - qglVertex2f (w, zz); - } - - qglEnd (); - } - } - - // draw minor blocks - if (g_qeglobals.d_showgrid && g_qeglobals.d_gridsize*z.scale >= 4 && - g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR] != g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK]) - { - qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR]); - - qglBegin (GL_LINES); - for (zz=zb ; zz 64 ? g_qeglobals.d_gridsize : 64); - zb = z.origin[2] - h; - if (zb < region_mins[2]) - zb = region_mins[2]; - zb = step * floor (zb/step); - - for (zz=zb ; zzGetCamWnd()->Camera()->origin[2]; - - qglColor3f (0.0, 0.0, 1.0); - qglBegin(GL_LINE_STRIP); - qglVertex3f (x-xCam,y,0); - qglVertex3f (x,y+gizmo,0); - qglVertex3f (x+xCam,y,0); - qglVertex3f (x,y-gizmo,0); - qglVertex3f (x-xCam,y,0); - qglVertex3f (x+xCam,y,0); - qglVertex3f (x+xCam,y-height,0); - qglVertex3f (x-xCam,y-height,0); - qglVertex3f (x-xCam,y,0); - qglEnd (); - -} - -GLbitfield glbitClear = GL_COLOR_BUFFER_BIT; //HACK - -/* -============== -Z_Draw -============== -*/ -void Z_Draw (void) -{ -#ifdef DBG_WINDOWPOS - CheckWatchit ("Z_Draw"); -#endif - brush_t *brush; - float w, h; - double start, end; - qtexture_t *q; - float top, bottom; - vec3_t org_top, org_bottom, dir_up, dir_down; - int xCam = z.width/3; - - if (!active_brushes.next) - return; // not valid yet - - if (z.timing) - start = Sys_DoubleTime (); - - // - // clear - // - qglViewport(0, 0, z.width, z.height); - - qglClearColor ( - g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][0], - g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][1], - g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][2], - 0); - - /* GL Bug */ - /* When not using hw acceleration, gl will fault if we clear the depth - buffer bit on the first pass. The hack fix is to set the GL_DEPTH_BUFFER_BIT - only after Z_Draw() has been called once. Yeah, right. */ - qglClear(glbitClear); - glbitClear |= GL_DEPTH_BUFFER_BIT; - qglMatrixMode(GL_PROJECTION); - - qglLoadIdentity (); - w = z.width/2 / z.scale; - h = z.height/2 / z.scale; - qglOrtho (-w, w, z.origin[2]-h, z.origin[2]+h, -8, 8); - - qglDisable(GL_TEXTURE_2D); - qglDisable(GL_TEXTURE_1D); - qglDisable(GL_DEPTH_TEST); - qglDisable(GL_BLEND); - - - // - // now draw the grid - // - Z_DrawGrid (); - - // - // draw stuff - // - - qglDisable(GL_CULL_FACE); - - qglShadeModel (GL_FLAT); - - qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); - - qglDisable(GL_TEXTURE_2D); - qglDisable(GL_BLEND); - qglDisable(GL_DEPTH_TEST); - - - // draw filled interiors and edges - dir_up[0] = 0 ; dir_up[1] = 0; dir_up[2] = 1; - dir_down[0] = 0 ; dir_down[1] = 0; dir_down[2] = -1; - VectorCopy (z.origin, org_top); - org_top[2] = g_MaxWorldCoord; - VectorCopy (z.origin, org_bottom); - org_bottom[2] = g_MinWorldCoord; - - for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next) - { - if (brush->bFiltered) - continue; - - if (brush->mins[0] >= z.origin[0] - || brush->maxs[0] <= z.origin[0] - || brush->mins[1] >= z.origin[1] - || brush->maxs[1] <= z.origin[1]) - continue; - - if (!Brush_Ray (org_top, dir_down, brush, &top)) - continue; - top = org_top[2] - top; - if (!Brush_Ray (org_bottom, dir_up, brush, &bottom)) - continue; - bottom = org_bottom[2] + bottom; - - q = brush->brush_faces->pShader->getTexture(); - qglColor3f (q->color[0], q->color[1], q->color[2]); - qglBegin (GL_QUADS); - qglVertex2f (-xCam, bottom); - qglVertex2f (xCam, bottom); - qglVertex2f (xCam, top); - qglVertex2f (-xCam, top); - qglEnd (); - - qglColor3f (1,1,1); - qglBegin (GL_LINE_LOOP); - qglVertex2f (-xCam, bottom); - qglVertex2f (xCam, bottom); - qglVertex2f (xCam, top); - qglVertex2f (-xCam, top); - qglEnd (); - } - - // - // now draw selected brushes - // - for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next) - { - if ( !(brush->mins[0] >= z.origin[0] - || brush->maxs[0] <= z.origin[0] - || brush->mins[1] >= z.origin[1] - || brush->maxs[1] <= z.origin[1]) ) - { - if (Brush_Ray (org_top, dir_down, brush, &top)) - { - top = org_top[2] - top; - if (Brush_Ray (org_bottom, dir_up, brush, &bottom)) - { - bottom = org_bottom[2] + bottom; - - q = brush->brush_faces->pShader->getTexture(); - qglColor3f (q->color[0], q->color[1], q->color[2]); - qglBegin (GL_QUADS); - qglVertex2f (-xCam, bottom); - qglVertex2f (xCam, bottom); - qglVertex2f (xCam, top); - qglVertex2f (-xCam, top); - qglEnd (); - } - } - } - - qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES]); - qglBegin (GL_LINE_LOOP); - qglVertex2f (-xCam, brush->mins[2]); - qglVertex2f (xCam, brush->mins[2]); - qglVertex2f (xCam, brush->maxs[2]); - qglVertex2f (-xCam, brush->maxs[2]); - qglEnd (); - } - - - ZDrawCameraIcon (); - - qglFinish(); - QE_CheckOpenGLForErrors(); - - if (z.timing) - { - end = Sys_DoubleTime (); - Sys_Printf ("z: %i ms\n", (int)(1000*(end-start))); - } -} - +/* +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 +*/ + +#include "stdafx.h" +//#include "qe3.h" + +#define PAGEFLIPS 2 + +z_t z; + +/* +============ +Z_Init +============ +*/ +void Z_Init (void) +{ + z.origin[0] = 0; + z.origin[1] = 20; + z.origin[2] = 46; + + z.scale = 1; +} + + + +/* +============================================================================ + + MOUSE ACTIONS + +============================================================================ +*/ + +static int cursorx, cursory; + +/* +============== +Z_MouseDown +============== +*/ +void Z_MouseDown (int x, int y, int buttons) +{ + vec3_t org, dir, vup, vright; + brush_t *b; + + Sys_GetCursorPos (&cursorx, &cursory); + + vup[0] = 0; vup[1] = 0; vup[2] = 1/z.scale; + + VectorCopy (z.origin, org); + org[2] += (y - (z.height/2))/z.scale; + org[1] = g_MinWorldCoord; + + b = selected_brushes.next; + if (b != &selected_brushes) + { + org[0] = (b->mins[0] + b->maxs[0])/2; + } + + dir[0] = 0; dir[1] = 1; dir[2] = 0; + + vright[0] = 0; vright[1] = 0; vright[2] = 0; + + // LBUTTON = manipulate selection + // shift-LBUTTON = select + // middle button = grab texture + // ctrl-middle button = set entire brush to texture + // ctrl-shift-middle button = set single face to texture + + int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON; + if ( (buttons == MK_LBUTTON) + || (buttons == (MK_LBUTTON | MK_SHIFT)) + || (buttons == MK_MBUTTON) +// || (buttons == (MK_MBUTTON|MK_CONTROL)) + || (buttons == (nMouseButton|MK_SHIFT|MK_CONTROL)) ) + { + Drag_Begin (x, y, buttons, + vright, vup, + org, dir); + return; + } + + // control mbutton = move camera + if ((buttons == (MK_CONTROL|nMouseButton) ) || (buttons == (MK_CONTROL|MK_LBUTTON))) + { + g_pParentWnd->GetCamWnd()->Camera()->origin[2] = org[2] ; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY|W_Z); + } + + +} + +/* +============== +Z_MouseUp +============== +*/ +void Z_MouseUp (int x, int y, int buttons) +{ + Drag_MouseUp (); +} + +/* +============== +Z_MouseMoved +============== +*/ +void Z_MouseMoved (int x, int y, int buttons) +{ + if (!buttons) + return; + if (buttons == MK_LBUTTON) + { + Drag_MouseMoved (x, y, buttons); + Sys_UpdateWindows (W_Z|W_CAMERA_IFON|W_XY); + return; + } + // rbutton = drag z origin + if (buttons == MK_RBUTTON) + { + Sys_GetCursorPos (&x, &y); + if ( y != cursory) + { + z.origin[2] += y-cursory; + Sys_SetCursorPos (cursorx, cursory); + Sys_UpdateWindows (W_Z); + } + return; + } + // control mbutton = move camera + int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON; + if ((buttons == (MK_CONTROL|nMouseButton) ) || (buttons == (MK_CONTROL|MK_LBUTTON))) + { + g_pParentWnd->GetCamWnd()->Camera()->origin[2] = (y - (z.height/2))/z.scale; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY|W_Z); + } + +} + + +/* +============================================================================ + +DRAWING + +============================================================================ +*/ + + +/* +============== +Z_DrawGrid +============== +*/ +void Z_DrawGrid (void) +{ + float zz, zb, ze; + float w, h; + char text[32]; + + w = (z.width/2 / z.scale); + h = (z.height/2 / z.scale); + + zb = z.origin[2] - h; + if (zb < region_mins[2]) + zb = region_mins[2]; + zb = 64 * floor (zb/64); + + ze = z.origin[2] + h; + if (ze > region_maxs[2]) + ze = region_maxs[2]; + ze = 64 * ceil (ze/64); + + // draw major blocks + + qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR]); + + if ( g_qeglobals.d_showgrid ) + { + if (g_qeglobals.d_gridsize < 128) + { + qglBegin (GL_LINES); + + qglVertex2f (0, zb); + qglVertex2f (0, ze); + + for (zz=zb ; zz= 128 .. it's an int for sure + if ( ((int)zz & ((int)g_qeglobals.d_gridsize-1)) != 0 ) + continue; + + qglVertex2f (-w, zz); + qglVertex2f (w, zz); + } + + qglEnd (); + } + } + + // draw minor blocks + if (g_qeglobals.d_showgrid && g_qeglobals.d_gridsize*z.scale >= 4 && + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR] != g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK]) + { + qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR]); + + qglBegin (GL_LINES); + for (zz=zb ; zz 64 ? g_qeglobals.d_gridsize : 64); + zb = z.origin[2] - h; + if (zb < region_mins[2]) + zb = region_mins[2]; + zb = step * floor (zb/step); + + for (zz=zb ; zzGetCamWnd()->Camera()->origin[2]; + + qglColor3f (0.0, 0.0, 1.0); + qglBegin(GL_LINE_STRIP); + qglVertex3f (x-xCam,y,0); + qglVertex3f (x,y+gizmo,0); + qglVertex3f (x+xCam,y,0); + qglVertex3f (x,y-gizmo,0); + qglVertex3f (x-xCam,y,0); + qglVertex3f (x+xCam,y,0); + qglVertex3f (x+xCam,y-height,0); + qglVertex3f (x-xCam,y-height,0); + qglVertex3f (x-xCam,y,0); + qglEnd (); + +} + +GLbitfield glbitClear = GL_COLOR_BUFFER_BIT; //HACK + +/* +============== +Z_Draw +============== +*/ +void Z_Draw (void) +{ +#ifdef DBG_WINDOWPOS + CheckWatchit ("Z_Draw"); +#endif + brush_t *brush; + float w, h; + double start, end; + qtexture_t *q; + float top, bottom; + vec3_t org_top, org_bottom, dir_up, dir_down; + int xCam = z.width/3; + + if (!active_brushes.next) + return; // not valid yet + + if (z.timing) + start = Sys_DoubleTime (); + + // + // clear + // + qglViewport(0, 0, z.width, z.height); + + qglClearColor ( + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][0], + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][1], + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][2], + 0); + + /* GL Bug */ + /* When not using hw acceleration, gl will fault if we clear the depth + buffer bit on the first pass. The hack fix is to set the GL_DEPTH_BUFFER_BIT + only after Z_Draw() has been called once. Yeah, right. */ + qglClear(glbitClear); + glbitClear |= GL_DEPTH_BUFFER_BIT; + qglMatrixMode(GL_PROJECTION); + + qglLoadIdentity (); + w = z.width/2 / z.scale; + h = z.height/2 / z.scale; + qglOrtho (-w, w, z.origin[2]-h, z.origin[2]+h, -8, 8); + + qglDisable(GL_TEXTURE_2D); + qglDisable(GL_TEXTURE_1D); + qglDisable(GL_DEPTH_TEST); + qglDisable(GL_BLEND); + + + // + // now draw the grid + // + Z_DrawGrid (); + + // + // draw stuff + // + + qglDisable(GL_CULL_FACE); + + qglShadeModel (GL_FLAT); + + qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + + qglDisable(GL_TEXTURE_2D); + qglDisable(GL_BLEND); + qglDisable(GL_DEPTH_TEST); + + + // draw filled interiors and edges + dir_up[0] = 0 ; dir_up[1] = 0; dir_up[2] = 1; + dir_down[0] = 0 ; dir_down[1] = 0; dir_down[2] = -1; + VectorCopy (z.origin, org_top); + org_top[2] = g_MaxWorldCoord; + VectorCopy (z.origin, org_bottom); + org_bottom[2] = g_MinWorldCoord; + + for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next) + { + if (brush->bFiltered) + continue; + + if (brush->mins[0] >= z.origin[0] + || brush->maxs[0] <= z.origin[0] + || brush->mins[1] >= z.origin[1] + || brush->maxs[1] <= z.origin[1]) + continue; + + if (!Brush_Ray (org_top, dir_down, brush, &top)) + continue; + top = org_top[2] - top; + if (!Brush_Ray (org_bottom, dir_up, brush, &bottom)) + continue; + bottom = org_bottom[2] + bottom; + + q = brush->brush_faces->pShader->getTexture(); + qglColor3f (q->color[0], q->color[1], q->color[2]); + qglBegin (GL_QUADS); + qglVertex2f (-xCam, bottom); + qglVertex2f (xCam, bottom); + qglVertex2f (xCam, top); + qglVertex2f (-xCam, top); + qglEnd (); + + qglColor3f (1,1,1); + qglBegin (GL_LINE_LOOP); + qglVertex2f (-xCam, bottom); + qglVertex2f (xCam, bottom); + qglVertex2f (xCam, top); + qglVertex2f (-xCam, top); + qglEnd (); + } + + // + // now draw selected brushes + // + for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next) + { + if ( !(brush->mins[0] >= z.origin[0] + || brush->maxs[0] <= z.origin[0] + || brush->mins[1] >= z.origin[1] + || brush->maxs[1] <= z.origin[1]) ) + { + if (Brush_Ray (org_top, dir_down, brush, &top)) + { + top = org_top[2] - top; + if (Brush_Ray (org_bottom, dir_up, brush, &bottom)) + { + bottom = org_bottom[2] + bottom; + + q = brush->brush_faces->pShader->getTexture(); + qglColor3f (q->color[0], q->color[1], q->color[2]); + qglBegin (GL_QUADS); + qglVertex2f (-xCam, bottom); + qglVertex2f (xCam, bottom); + qglVertex2f (xCam, top); + qglVertex2f (-xCam, top); + qglEnd (); + } + } + } + + qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES]); + qglBegin (GL_LINE_LOOP); + qglVertex2f (-xCam, brush->mins[2]); + qglVertex2f (xCam, brush->mins[2]); + qglVertex2f (xCam, brush->maxs[2]); + qglVertex2f (-xCam, brush->maxs[2]); + qglEnd (); + } + + + ZDrawCameraIcon (); + + qglFinish(); + QE_CheckOpenGLForErrors(); + + if (z.timing) + { + end = Sys_DoubleTime (); + Sys_Printf ("z: %i ms\n", (int)(1000*(end-start))); + } +} + diff --git a/radiant/zwindow.cpp b/radiant/zwindow.cpp index 3da6284d..ee7fa898 100644 --- a/radiant/zwindow.cpp +++ b/radiant/zwindow.cpp @@ -1,125 +1,125 @@ -/* -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 -*/ - -// -// Z Window -// -// Leonardo Zide (leo@lokigames.com) -// - -#include "stdafx.h" -#include "zwindow.h" - -// ============================================================================= -// ZWnd class - -ZWnd::ZWnd () - : GLWindow (FALSE) -{ -} - -ZWnd::~ZWnd() -{ -} - -void ZWnd::OnCreate () -{ - g_qeglobals_gui.d_z = m_pWidget; - - if (!MakeCurrent()) - Error ("wglMakeCurrent in CZWnd::OnCreate failed"); -} - -void ZWnd::OnLButtonDown(guint32 nFlags, int pointx, int pointy) -{ - SetFocus(); - SetCapture(); - Z_MouseDown (pointx, m_pWidget->allocation.height - 1 - pointy , nFlags); -} - -void ZWnd::OnMButtonDown(guint32 nFlags, int pointx, int pointy) -{ - SetFocus(); - SetCapture(); - Z_MouseDown (pointx, m_pWidget->allocation.height - 1 - pointy , nFlags); -} - -void ZWnd::OnRButtonDown(guint32 nFlags, int pointx, int pointy) -{ - SetFocus(); - SetCapture(); - Z_MouseDown (pointx, m_pWidget->allocation.height - 1 - pointy , nFlags); -} - -void ZWnd::OnLButtonUp(guint32 nFlags, int pointx, int pointy) -{ - Z_MouseUp (pointx, m_pWidget->allocation.height - 1 - pointy, nFlags); - ReleaseCapture (); -} - -void ZWnd::OnMButtonUp(guint32 nFlags, int pointx, int pointy) -{ - Z_MouseUp (pointx, m_pWidget->allocation.height - 1 - pointy, nFlags); - ReleaseCapture (); -} - -void ZWnd::OnRButtonUp(guint32 nFlags, int pointx, int pointy) -{ - Z_MouseUp (pointx, m_pWidget->allocation.height - 1 - pointy, nFlags); - ReleaseCapture (); -} - -void ZWnd::OnMouseMove(guint32 nFlags, int pointx, int pointy) -{ - float fz = z.origin[2] + ((m_pWidget->allocation.height - 1 - pointy) - (z.height/2)) / z.scale; - fz = floor(fz / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; - CString strStatus; - strStatus.Format("Z:: %.1f", fz); - g_pParentWnd->SetStatusText(1, strStatus); - Z_MouseMoved (pointx, m_pWidget->allocation.height - 1 - pointy, nFlags); -} - -void ZWnd::OnExpose() -{ - if (!MakeCurrent ()) - { - Sys_Printf("ERROR: wglMakeCurrent failed..\n "); - Sys_Printf("Please restart Radiant if the Z view is not working\n"); - } - else - { - QE_CheckOpenGLForErrors(); - Z_Draw (); - QE_CheckOpenGLForErrors(); - SwapBuffers(); - } -} - -void ZWnd::OnSize(int cx, int cy) -{ - z.width = cx; - z.height = cy; - if (z.width < 10) - z.width = 10; - if (z.height < 10) - z.height = 10; - RedrawWindow (); -} +/* +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 +*/ + +// +// Z Window +// +// Leonardo Zide (leo@lokigames.com) +// + +#include "stdafx.h" +#include "zwindow.h" + +// ============================================================================= +// ZWnd class + +ZWnd::ZWnd () + : GLWindow (FALSE) +{ +} + +ZWnd::~ZWnd() +{ +} + +void ZWnd::OnCreate () +{ + g_qeglobals_gui.d_z = m_pWidget; + + if (!MakeCurrent()) + Error ("wglMakeCurrent in CZWnd::OnCreate failed"); +} + +void ZWnd::OnLButtonDown(guint32 nFlags, int pointx, int pointy) +{ + SetFocus(); + SetCapture(); + Z_MouseDown (pointx, m_pWidget->allocation.height - 1 - pointy , nFlags); +} + +void ZWnd::OnMButtonDown(guint32 nFlags, int pointx, int pointy) +{ + SetFocus(); + SetCapture(); + Z_MouseDown (pointx, m_pWidget->allocation.height - 1 - pointy , nFlags); +} + +void ZWnd::OnRButtonDown(guint32 nFlags, int pointx, int pointy) +{ + SetFocus(); + SetCapture(); + Z_MouseDown (pointx, m_pWidget->allocation.height - 1 - pointy , nFlags); +} + +void ZWnd::OnLButtonUp(guint32 nFlags, int pointx, int pointy) +{ + Z_MouseUp (pointx, m_pWidget->allocation.height - 1 - pointy, nFlags); + ReleaseCapture (); +} + +void ZWnd::OnMButtonUp(guint32 nFlags, int pointx, int pointy) +{ + Z_MouseUp (pointx, m_pWidget->allocation.height - 1 - pointy, nFlags); + ReleaseCapture (); +} + +void ZWnd::OnRButtonUp(guint32 nFlags, int pointx, int pointy) +{ + Z_MouseUp (pointx, m_pWidget->allocation.height - 1 - pointy, nFlags); + ReleaseCapture (); +} + +void ZWnd::OnMouseMove(guint32 nFlags, int pointx, int pointy) +{ + float fz = z.origin[2] + ((m_pWidget->allocation.height - 1 - pointy) - (z.height/2)) / z.scale; + fz = floor(fz / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; + CString strStatus; + strStatus.Format("Z:: %.1f", fz); + g_pParentWnd->SetStatusText(1, strStatus); + Z_MouseMoved (pointx, m_pWidget->allocation.height - 1 - pointy, nFlags); +} + +void ZWnd::OnExpose() +{ + if (!MakeCurrent ()) + { + Sys_Printf("ERROR: wglMakeCurrent failed..\n "); + Sys_Printf("Please restart Radiant if the Z view is not working\n"); + } + else + { + QE_CheckOpenGLForErrors(); + Z_Draw (); + QE_CheckOpenGLForErrors(); + SwapBuffers(); + } +} + +void ZWnd::OnSize(int cx, int cy) +{ + z.width = cx; + z.height = cy; + if (z.width < 10) + z.width = 10; + if (z.height < 10) + z.height = 10; + RedrawWindow (); +} -- 2.39.2